min read Author: klaas

Adding a handler

Now let's add a handler and an API to our todo list app

As you know, all PythonOnWheels apps are Model-View-Controller (or MVC) based. Handler are the controllers in PythonOnWheels. Handlers give us a way to actually do something with our models. In PythonOnWheels they are also creating an API defined by routes which are accessible from the outside, mostly the web. In fact Models hold, store and retrieve the data and handlers hold the logic to deal with the data and make some of their methods and logic externally accessible. Which is your apps API.

Handlers are the brain of your app. They are where your applications logic goes. They create your app's API.

This might seem a little formal or buerocratic but in fact it's really easy. Just think of it like this. We defined a model to hold our todos data (if you have not created a todo model, please read Working with models (NoSQL) first).  Remember it looks like this:

class Todo(TinyModel):
schema = {
'title': { 'type': 'string', 'maxlength' : 35 },
'text' : { 'type': 'string'},
'done' : { 'type': 'boolean', "default" : False },
"votes" : { "type" : "integer", "default" : 0 }

So lets really create our first handler

As always in PythonOnWheels we want to focus on what we want to do and get rid of the boilerplate. So we generate our handler using the generate_handler script. We give it the name todo and we need to say with which DB model we want to connect. The convention in PoW is that the handler uses the model with the same name. So we just give it the right DB type with -t tinydb. It will lok for models named todo but cannot know what DB you chose for that model. That's due to the fact that PoW supports many different DBs (even at the same time) ... So we point it to the right one. A model named todo (same as the handler) of type tinydb

python generate_handler.py -n todo -t tinydb --rest

We also added the --rest parameter to automatically create a standard REST API for our new handler. This makes working with PythonOnWheels so easy. Most probably you want to create, read, update and delete your data, maybe also show and list it ... And this is exactly what is now already prepared for you.

PythonOnWheels automatically creates a standard REST handler and API for you if you use the --rest parameter

This is what a PoW (REST) handler looks like

The generated handler is nicely structured an consists of the methods you need to respond to the typical REST requests. You can see in the excerpt below the methods for show, list, page (list with pagination) edit and so on. There are many more things. As you can see some methods are access protected by default (edit). You can of course also create non REST handlers that just offer some specific routes, but we will cover this in more detail later. For now we are on the fast forward path.

You can also see the class decorator


This generates the REST routing which links the methods to actual REST URLs. Like this:

So what this really does is that it links any http GET request to the URL /todo to the list method of the todo handler.

So when you call http://localhost:8080/todo the todo.list() method will be called

Since this really now already works and we already have some todos we can actually start the server and send requests to our app.

So let's run the server:

python server.py

You should see the PythonOnWheels server starting. It will display information about the configured DBs and routes. It should look something like this:

We can see the REST routes for our todo handler starting from route number #20. But let's not focus on the boilerplate cause that's what PoW should take out of our sight and minds. (But it's good to know it's there and it's just standard routing)

Our first HTTP access to our todo app

We can now already access your todo handler (and models) on port 8080 (The default port configured in the config.py file)

Make sure that you have created a todo model before. Read: getting started part 1: how to create a model.

Let's try this with curl

Open a new terminal (make sure you have curl installed) and execute the following curl command:

curl -H "Accept: application/json" -X GET http://localhost:8080/todo

Our PoW todo app should respond with the json formatted list of our todo models. Should look similar to this:

Or like this (if you haven't added any data so far..)

khz@~ $ curl -H "Accept: application/json" -X GET http://localhost:8080/todo 
{"message": "todo, index", "http_status": 200, "prev": null, "next": null, "data": []}

Let us add one (more) todo

curl -H "Content-Type: application/json" -X POST -d "{ \"title\" : \"best todo\" }" http://localhost:8080/todo 

Which replies with:

(venv) khz@~/devel/pow_devel $ curl -H "Content-Type: application/json" -X POST -d "{ \"title\" : \"best todo\" }" http://localhost:8080/todo 
{"message": "todo, successfully created bceddeb6-3268-480f-8b57-080a5579d97f", "http_status": 200, "prev": null, "next": null, "data": {"title": "best todo", "text": "", "done": false, "id": "bceddeb6-3268-480f-8b57-080a5579d97f", "_uuid": "bceddeb6-3268-480f-8b57-080a5579d97f", "created_at": "2019-12-13 22:16:23", "last_updated": "2019-12-13 22:16:23"}}(venv)

And make a query one last time

curl -H "Accept: application/json" -X GET http://localhost:8080/todo

Now you should at least see the todo we added

(venv) khz@~/devel/pow_devel $ curl -H "Accept: application/json" -X GET http://localhost:8080/todo 
{"message": "todo, index", "http_status": 200, "prev": null, "next": null, "data": {"title": "best todo", "text": "", "done": false, "id": "c42a1ac3-0969-45b5-87d1-55c5a180550c", "_uuid": "c42a1ac3-0969-45b5-87d1-55c5a180550c", "created_at": "2019-12-13 22:11:57", "last_updated": "2019-12-13 22:11:57"}}(venv)

So that is really quick and easy!

Lets sum it up so far.

  • We just generated a model.
  • We added a done boolean attribute (default to False)
  • We easily created some models at the command line (and saved them using upsert())
  • We generated a handler (using the --rest paramater)
  • We started the server and we are done.

But far more interesting is what we NOT needed to do

  • No additional installations
  • No DB setup at all (No installation, no configuration)
  • We haven't written a single class
  • We just adapted two lines in the model schema
  • No editing of config files. If we use the conventions (like in Ruby on Rails) everything is auto detected
    • For example the handler finds the model itself
  • No routing definitions needed for REST API

So a fully accessible Web app with REST routes in only some minutes.

And we could really focus on our data/models and logic (REST for the moment). In the next articles we will see how to generate a web frontend with scaffolding and how to add our own methods to handlers.

Next Steps:

Follow the last step in the getting started path and scaffold the web views for the todo application

Hope you enjoyed it so far.

Tweet some thoughts, questions or ideas for enhancements to @pythononwheels.

about it, both is very appreciated.

A short remark why PythonOnWheels Controllers are called handlers:

This is also the terminology used in tornado which builds the foundation of PythonOnWheels Web services. Tornado is great. It's not only a python webserver and template engine but also implements a fully blown asynchronous IOloop.