Restful Json Api for Mobile With Python and Django Using Behave

Mar 3, 2016 19:09 · 1398 words · 7 minute read python django restful api behave

Rare mobile application could survive without reliable back-end that stores and processes date. Nowadays, mobile applications are complex enough to require solid back-end behind. This particular topic is about how to build reliable RESTful json API with Python and Django, why is it so efficient and straightforward. This article talks about the following aspects of json API development.

What Makes API Good?

Reliable

Good API means that it is reliable. The API should work no matter what. Whatever application queries API has to gracefully respond with either error message or actual data. It should always follow the protocol and there is no excuse for unexpected behaviour. It is especially important for developers who make an integration. Clear, straightforward and expectable output enables to integrate quickly.

Scalable

Nowadays application can get half of the million visitors overnight. It is very important to be able to handle a load when it comes. That doesn’t meant to put hundred of servers from day one, it simply means to be able to put them when it needs. Scalability in terms of API means to have such architecture that will allow to grow without changing a protocol of communication.

Developers Friendly

After all it is developers who deal with all the things. API has to be supported with solid documentation, sandbox environment, clear instructions of how to use it and the way to test it.

Nice error messages in responses are much appreciated. It speeds up integration process a lot.

Quick to Bootstrap

It is an era of lean startups and all kind of MVP-like products. Small investments, tight deadlines, market researchers and so on force IT industry to offer cheap and quick solutions. API is not an exception. It has to be fast to bootstrap and easy to change when needs. The good API should be launched in days or weeks at most.

Technology - Python and Django Solution

First, we use Python 3.5. The reason is simple - it is really fast to create applications with Python.

We also use Django Rest Framework to achieve the best quality and increase development speed. The reason why we chosen django - it is extremely fast to build on top of it. It saves weeks or even months reducing the cost of developments dramatically.

Python and Django community is great. It produces lots of tools daily that can be utilised.

SDK for mobile apps. We created SDKs for iOS and Android to simplify the app developers work. Debug web interface for app developers. We also provide a nice-looking web interface for app developers so they can test it without knowing too much about web development itself. The django-rest-framework provide it out of the box which makes it easy to use.

Testing. Unit Test with Behave

Regardless whether you do TDD or just write tests afterwards there has to be tests. For that purpose unittest Python module fits the best. However, unit tests will only allow you to check whether your functions, methods, classes and modules work fine. Technically, API couldn’t be considered as tested before you run acceptance tests over it. There is quite nice tool named behave which allows you to test the exact behaviour of the system.

This is a part of bigger subject called Behaviour Driven Development which is not part of this article but worth mentioning. In short, it gives you a way to abstract from the implementation and test the behaviour of the API. The syntax is very simple:

your_awesome_thing.feature

Feature: showing off behave
  
  Scenario: run a simple test
    Given we have behave installed
    When we implement a test
    Then behave will test it for us!

and the implementation

from behave import *

@given('we have behave installed')
def step_impl(context):
    pass

@when('we implement a test')
def step_impl(context):
    assert True is not False
@then('behave will test it for us!')
def step_impl(context):
    assert context.failed is False

As you can see you can write your use cases first and implement test cases after.

Logging with Sentry Online Logger

There has to be a way to identify the root of the problem. It is always a good idea to log everything what happens on a backend. We also provide nice web interface to view logs so app developers can use it to identify problems if any appears.

sentry ui

There are certain things that nice to log while creating json API:

  • Every API call with method, headers, query string and body
  • Log and attach tags to log entries to easily filter
  • The URL that was called
  • Internal method calls and dump context during critical operations
  • Timing on the API calls. Could be important while analysing performance.
  • Background task execution with Celery and RabbitMQ

Often, there is a need to perform certain actions in the background. It is not only API-related problem but in the context of mobile applications is quite important. Since responsiveness of mobile application is very important, every piece of the system should work to reduce timings and delays. This is where background processing steps in.

from .models import User

@app.task
def create_user(username, password):
    User.objects.create(username=username, password=password)

For example the following tasks could be executed in the background:

  • Sending push notifications
  • Sending emails
  • 3rd-part API calls
  • Payment processing
  • Scaling images or any kind of image editing
  • Heavy database operations such as re-indexing
  • Creating bundles and files

There are much more of course. To make the mobile app truly fast and responsive it is important to pick up reliable tool. This is where Celery project (see official website) helps us.

Celery is a Python library that allows to manage workers and execute tasks in certain context. It requires broker - message queue - such as RabbitMQ or Redis. It works well in distributed cloud environments and fairly independent. Celery supports quite a lot of nice features such as delayed execution, chains, scheduled tasks etc. It also integrates well with Django and Django Rest Framework.

Documentation: Swagger Interactive

Documentation is a crucial part of the API. It is an interface to the interface. This is how everyone will know what’s your API is about. It’s importance is hard to underestimate thus should be done in a very careful way. One of the possibilities is to use Swagger web wrapper. It allows developers and all the other end users to play with API interactively without writing any code at all. You can send GET/POST/DELETE requests via web interface and see how API will react. It is a nice way to compare responses you get within an application to the etalon. The documentation is structured nicely and come along with code inline documentation. We have standard way to organise our docs and the framework also provide tools to automatically generate necessary documentation.

alt text

Swagger.io - official website.

Sandbox with Docker

From the API consumer’s perspective it is very important to have an ability to “play” with API. Obviously, there has to be testing environment where incorrect API calls wouldn’t harm. It has to be easy to roll back changes and discover all the edge cases. This is where docker could be useful.

Docker is designed to be a revertible and sandboxed environment. What we do is we put API application (usually Django or Flask app) into a docker container. Often, we put Dockerfile inside the repository to allow developers to run their sandboxes locally. Aside of that we run docker on a staging/testing server. This approach allow us to provide API consumers such as mobile developers and rich front-end d developers with sandboxed environment.

SWIFT integration example

To illustrate the interaction with json API in SWIFT consider the following code:

var err: NSError?
let body = [
    "user": "demo@example.com",
    "password": "password"
]
let request = NSMutableURLRequest(URL: NSURL(string: "http://demo.anvileight.com/login")!)
request.HTTPMethod = "POST"
request.HTTPBody = NSJSONSerialization.dataWithJSONObject(body, options: nil, error: &err)

let session = NSURLSession.sharedSession()

let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
    let json:JSON = JSON(data: data)
    onCompletion(json, err)
})
task.resume()

This is fairly simple example but covers the most most frequent case. It makes a call in a background thus doesn’t hold UI. This is quite complete code and could be adopted for particular cases.

Source code There is an example of API project I’ve created for another reason. You can find source code on our git repository. This was made as an example of test driven development approach. There is no live version of that API yet but I will update this post once I create it.

We will notify you about new posts every few weeks