Deploying circuits.web with Nginx/uwsgi

Explanation

Here we load the Controller module, and wsgi Application module from circuits.web. Essentially the peices we need to not only serve a WSGI application, but to handle the requests being sent to the app.

# uwsgi --version
uWSGI 0.9.6.7

This is the main Root controller.

server {
	server_name myapp.example.com;
 
	location / { 
		uwsgi_pass 127.0.0.1:3031;
		#You can also use sockets such as : uwsgi_pass unix:/tmp/uwsgi.sock;
		include uwsgi_params;
	}
}

Here we store some HTML output into formpage for later use

def application(environ, start_response):
    start_response("200 OK", [("Content-Type", "text/plain")])
    return ["Hello World!"]

When visiting http://myapp.example.com/ , the main index is served with a simple string

# uwsgi -s 127.0.0.1:3031 -w myapp
*** Starting uWSGI 0.9.6.7 (64bit) on [Mon Jan 31 00:10:36 2011] ***
compiled with version: 4.4.5
Python version: 2.6.6 (r266:84292, Dec 26 2010, 22:48:11)  [GCC 4.4.5]
uWSGI running as root, you can use --uid/--gid/--chroot options
 *** WARNING: you are running uWSGI as root !!! (use the --uid flag) *** 
 *** WARNING: you are running uWSGI without its master process manager ***
your memory page size is 4096 bytes
allocated 640 bytes (0 KB) for 1 request's buffer.
binding on TCP port: 3031
your server socket listen backlog is limited to 100 connections
initializing hooks...done.
...getting the applications list from the 'myapp' module...
uwsgi.applications dictionary is not defined, trying with the "applications" one...
applications dictionary is not defined, trying with the "application" callable.
application 0 () ready
setting default application to 0
spawned uWSGI worker 1 (and the only) (pid: 20317)

When visiting http://myapp.example.com/query/?foo=bar&more=stuff circuits.web will parse the query string into a dictionary called data and then will print out each key=value received. **data can also capture key-values sent via POST.

Notice how /query/ invokes the query function under the Root controller.

apt-get install python-setuptools

Similar to the query function above, we check to see if a object say has been passed, and if it has the value of yes.
http://myapp.example.com/sayyes/ -> “You didn’t say anything”
http://myapp.example.com/sayyes/?say=no -> “You didn’t say ‘yes'”
http://myapp.example.com/sayyes/?say=yes -> “You said yes…”

easy_install circuits

Remember the stored HTML string above, here when someone visits /form/ that data will be returned to the browser.

	def form(self):
		return self.formpage

The form above submits POST data to /submit/ , as a result the values will be shown to the browser.
Notice how the arguments can be defined in the function like above, but predefined to the field name.

	def submit(self, firstName, lastName):
		return "Hello %s %s<br /><a href=\"/form/\">Return</a>" % (firstName, lastName)

And now we have a new controller. Notice how there is a channel=”/math”, this controller will only be invoked if http://myapp.example.com/math/* is requested. In this way you can create a number of controllers bound to a specific URI.

class SomeMath(Controller):
	channel = "/math"

Here we have a very simple arithmetic function, adding two numbers passed to it:
http://myapp.example.com/math/addtwo/ -> “You need two numbers, missing both”
http://myapp.example.com/math/addtwo/2/ -> “You need two numbers, missing second”
http://myapp.example.com/math/addtwo/2/3/ -> “2 + 3 = 5”
Note: Other than checking for the existence of arguments, it does not validate the inputs

	def addtwo(self, firstNum, secondNum):
		if not firstNum:
			return "You need two numbers, missing both"
 
		if not secondNum:
			return "You need two numbers, missing second"
 
		newNum = int(firstNum) + int(secondNum)
 
		return "%d + %d = %d" % (int(firstNum), int(secondNum), newNum)

Similar function to above, however will process any number of arguments. But we also validate the input here, and catch the error if one occurs.
http://myapp.example.com/math/addmulti/1/2/3/4/ -> “The sum of the numbers you provided was 10”
http://myapp.example.com/math/addmulti/1/oops/4 -> “One or more numbers was not valid”

	def addmulti(self, *args):
		try:
			total = sum([int(x) for x in args])
		except ValueError:
			return "One or more numbers was not valid"
 
		return "The sum of the numbers you provided was %d" % (total)

And here we tie it all up, notice how we just add on each controller as we need it.

application = Application() + Root() + SomeMath()

Comments are closed.