Handling Requests
=================
Now that we can store data we're going to need a way to serve it to our users.
First, we'll take a short detour to discuss one of the core parts of Ferris: Handlers.
Ferris handles HTTP requests with the cleverly named Handlers. Handlers are
Python classes that contain a collection of *actions*. Actions are Python
methods that can be invoked via HTTP. Handlers can also render template files
and serve content such as JSON or blobs.
.. note::
Handlers are usually plural nouns and are tied to a particular model (i.e. Posts handler for the Post model, Daleks handler for the Dalek model). However, there are cases where you'll make exceptions, such as handlers that don't have a model or those that have multiple models.
Saying Hello
------------
Here's a rather simple handler to get your feet wet. We'll just say hello.
Create ``app/handlers/hello.py``::
from ferris.core.handler import Handler
class Hello(Handler):
def list(self):
return "Hello, is it me you're looking for?"
If you open http://localhost:8080/hello, you should see a friendly welcome.
.. note::
A dev server restart might be required at this point.
You can also accept input from GET or POST, if you'd like.
Modify our list action::
def list(self):
return "Hello, %s" % self.request.params['name']
Now try to open http://localhost:8080/hello?name=Doctor
You may have noticed that ``Hello.list`` gets automatically routed to `/hello`.
Ferris will automatically route the actions ``list``, ``add``, ``edit``, ``view``, and ``delete``.
The other actions will be discussed in the Routing and Scaffolding sections.
Templates
---------
You're not limited to returning simple strings from your handler. Ferris
also provides you the fantastic `Jinja2 template engine `_.
Let's create a template for our action at ``app/templates/hello/list.html``::
{% extends 'layouts/default.html' %}
{% block layout_content %}
Hello, {{who}}
{% endblock %}
The syntax for Jinja2 can be a bit much to take in at once; I highly recommend checking out their
most excellent `documentation `_. The gist of this is that we are going to use the default layout
and add some content that says hello.
Now we just need to modify our list action::
def list(self):
self.set(who=self.request.params['name'])
Notice here that we have to explictly set the ``who`` variable in the template using ``self.set``.
If you load up http://localhost:8080/hello?name=Doctor, you should see a slighly prettier greeting.
.. note::
Ferris expects the template to be located at ``app/templates/handler/action.html``. So the template
for this action is at ``app/templates/hello/list.html``. You can manually specify the template location
by setting ``self.template_name`` in your action.
Routing
-------
You've already seen how ``Hello.list`` gets automatically routed to `/hello`.
Ferris will implicitly route the following actions to these urls:
+---------+----------------------+
|Action | URL |
+=========+======================+
|list | /handler |
+---------+----------------------+
|add | /handler/add |
+---------+----------------------+
|view | /handler/ |
+---------+----------------------+
|edit | /handler//edit |
+---------+----------------------+
|delete | /handler//delete|
+---------+----------------------+
Notice the `handler` section of the url. The handler's name is passed to ``inflector.underscore``. For example, `Posts` becomes `posts` and `FlyingMonsters` becomes `flying_monsters`.
But what about actions that are not part of this list? You have to explictly route them using the ``route`` decorator.
Modify our imports in the Hello handler::
from ferris.core.handler import Handler, route
Add the following action to our Hello handler::
@route
def custom(self):
return "Something, indeed."
Go ahead and open http://localhost:8080/hello/custom.
You'll notice that Ferris determines the url using the template ``/handler/action``.
Ferris can also put parameters in the url as well. Let's modify our custom function::
@route
def custom(self, text):
return "%s, indeed." % text
Opening http://localhost:8080/hello/custom gives us a 404. We must pass some text to the ``custom`` action.
Open http://localhost:8080/hello/custom/Yes. You should see "Yes, indeed." The last argument in this url is passed as a parameter to the ``custom`` action.
You may have multiple mapped arguments::
@route
def custom(self, text, person):
return "%s, %s, indeed." % (text, person)
Try with http://localhost:8080/hello/custom/Yes/sir
.. note::
You can set your own URLs for methods using the route_with decorator.
Next
----
Continue with :doc:`4_scaffolding`