Restful API Design using Flask-RESTful (Part 1)

Python is by far one of the best languages I’ve used to write programs so far. The ease of writing code as well as how intuitive it is to understand the language nuances make it a good choice for beginners or experts alike.
Like most Python programs, Flask is built on Python philosophies which in summary make using the package API as easy as eating ice-cream.
Don’t take my word for it, head over to their docs to see what I mean.
Starting up a server is just a few lines

from flask import Flask

app = Flask(__name__)

if __name__ == '__main__':
    app.run(debug=True)

Doing this and then running it, we see that the Python server starts off and shows that it is listening on port 7000 (The default port number).

If you haven’t already installed flask, run pip install Flask within your virtual environment to do so.

For this exercise, we shall be making use of Flask-RESTful, a tool that makes Flask development much easier.

Setting up a single endpoint in Flask is done this way.

from flask import request, Flask

app = Flask(__name__)

@app.route('/someendpoint', methods=['GET', 'POST']
def endpoint_callback():
    if request.method == 'GET':
        return "Some random string"
    if request.method == 'POST':
        return "From the post method"

if __name__ == '__main__':
    app.run(debug=True)

Using this snippet, we can capture both GET and POST requests headed at http://some.domain/someendpoint and handle the different cases using the request.method string value.
To do something similar on Flask-RESTful, the mechanics are similar but it can be a lot more understandable at a glance.

from flask import Flask
from flask_restful import Resource, Api

app = Flask(__name__)
api = Api(app)

class EndpointResource(Resource):
    def get(self):
        return "Some random string"
    def post(self):
        return "From the post method"

api.add_resource(EndpointResource, '/someendpoint')

if __name__ == '__main__':
    app.run(debug=True)

Similar to the previous code snippet, we need to create Flask instance to run at the very least. The configuration, however, in this case is a lot different than the previous one. Here the different endpoints are configured using the URL pattern and resource classes. These classes contain method implementations corresponding to each of the HTTP verbs. i.e GET method behaviour is implemented in get() function of the resource class, POST method behaviour is implemented in post() function of the resource class e.t.c. This way we can think of multiple benefits,

  1. Easier to read syntax
  2. With more separation e.g of resource classes, we would achieve even far more organization of the project in general.
  3. List and Dictionary return values are automatically parsed using jsonify to their corresponding Javascript Data structures.
  4. We have the ability to combine this with the blueprint to get even more modular overall architecture.

To ensure we have a good understanding of this, we shall demo this with a simple inventory management system.

We would require the following endpoints in the application (for an MVP).

For this example, we shall be storing all the values within the class for simplicity.

We will start with the code for the Items resource and then move on to the SingleItem resource. Your application code should look something like this

from cerberus import Validator
from datetime import datetime
from uuid import uuid64
from flask import Flask
from flask_restful import Resource, Api

app = Flask(__name__)
api = Api(app)

items = {}

class Items(Resource):
    def get(self):
        return items

    def post(self):
        body = request.json
        try:
            item = {k: body[k] for k in ('name', 'quantity')}
        catch Exception:
            return 'Error while parsing request', 500
        # Generate random item id
        id = uuid64()

        item['date_created'] = datetime.now()
        item['date_modified'] = datetime.now()

        # We shall be validating the request body data against this
        schema = {
            'name': {'required': 'True', 'type': 'string'},
            'quantity': {'type': 'integer', 'min': 10},
            'date_created': {'type': 'datetime'},
            'date_modified': {'type': 'datetime'}
        }
        v = Validator(schema)
        if not v(item):
            return "There was something wrong with your arguments", 400

        item[id] = id
        items[id] = item
        return item, 201

api.add_resource(Items, '/items/')

if __name__ == '__main__':
    app.run(debug=True)

A couple of things stand out here for me. The first thing that comes to mind is the fact that we’re making use of cerberus to validate our dictionary structure. This works simply by making use of dictionary format schemas which define constraints for keys in the dictionary we’re trying to validate.
We are also making use of the uuid64() function here to generate random object ids. The rest is simple logic to add the item to a dictionary for POST requests and return a list of items for a GET request.

The SingleItem is similar to what we have just done. The only difference IMO is the fact that we’re making use of a single object as opposed to a few.

You resource endpoints should look like this.

...
class SingleItem(Resource):
    def get(self, id):
        try:
            item = items[id]
        except IndexError:
            return "Item could not be found", 404
        return item

    def put(self, id):
        try:
            item = items[id]
        except IndexError:
            return "Item could not be found", 404
        body = request.json
        item['name'] = body['name'] or item['name']
        item['quantity'] = body['quantity'] or item['quantity']
        item['date_created'] = datetime.now()
        item['date_modified'] = datetime.now()

        # We shall be validating the request body data against this
        schema = {
            'name': {'required': 'True', 'type': 'string'},
            'quantity': {'type': 'integer', 'min': 10},
            'date_created': {'type': 'datetime'},
            'date_modified': {'type': 'datetime'}
        }
        v = Validator(schema)
        if not v(item):
            return "There was something wrong with your arguments", 400

        item[id] = id
        items[id] = item
        return item

    def delete(self, id):
        try:
            item = items[id]
        except IndexError:
            return "Item could not be found", 404
        return "Item has been deleted", 204

api.add_resource(SingleItem, '/items/<string:id>')

With this code, we have setup the 2 resource classes that we need for a very simple Inventory management system REST API.

As you would have observed the Flask-RESTful syntax makes this hyper easy for us. Apart from the features shown here, a number of other things exist to make our life even much easier. Some of these include marshalling dictionaries to be returned as JSON, URL parameter validation and Blueprint support.

In the next tutorial we shall be showing you how to refactor your code to make use of a SQL Databases.

Cheers.

 
44
Kudos
 
44
Kudos

Now read this

…one journey ends. Another begins…

It’s been a while since I wrote my last blog post, for several reasons. For one, I hadn’t renewed my subscription on Svbtle (this awesome blogging platform). This was one of the main reasons I went for a paid blogging platform over using... Continue →