Build a Python REST API in 5 Minutes

In this post we introduce Arrested — A new framework for building REST APIs using Python. We’ll use Docker, SQLAlchemy, and other tools to build a Star Wars themed API in 5 minutes!

This is the first in a series of posts aiming to help people build REST APIs in Python. We have developed a collection of tools that let you get started quickly yet remain robust enough to take you all the way to production.

In this first post we’ll introduce you to Arrested — A Framework we built for building Rest APIs using Flask. Arrested aims to take the pain out of building REST APIs, takes a batteries included approach for quick wins whilst being highly extensible for specialist requirements.

In this post we’ll cover:

  1. Use the Arrested cookie cutter template to setup up a Flask application complete with an SQLlite database, SQLAlchemy ORM to interact with the database, Kim Mappers for serialization and marshaling, Docker containers for our dev environment and an example users API.
  2. Step through creating a star wars themed resources that allows us to fetch a list of characters, create new characters, find characters using a resource ID and finally update and delete a character.

Here are some resources for some of the tools we’ll be using

Docker — Docker is used throughout our examples.
Git. We’ll be using git to clone some repositories
Cookie Cutter — Cookie Cutter is a project templating tool
Flask — Arrested builds on top of Flask, a micro framework for Python based on Werkzeug
Kim — A Python Marshaling and Serialization framework.
Arrested — A Framework For Rapidly Building REST APIs with Flask.


1. Creating the application. 🚀

We’ll use a cookie-cutter to quickly create the basic app structure and get all the boring stuff out of the way before we create a resource that will return characters from our star wars data set. If you’re not interested in using the cookie cutter you can take a look at the example application here.

$ cookiecutter gh:mikeywaites/arrested-cookiecutter
project_name [Arrested Users API]: star wars
project_slug [star-wars]:
package_name [star_wars]:

Now we have the basic app skeleton let’s build the Docker container and create the database.

$ cd star_wars
$ docker-compose build
$ docker-compose run --rm api flask db upgrade

Now start the API container and make a request to the users endpoint to check things are running correctly.

$ docker-compose up api
$ curl -u admin:secret localhost:8080/v1/users | python -m json.tool
{
"payload": []
}

And there we have it. A working API in 5 minutes. 💪

Sure, we’ve got a working REST API but all the hard work has been done for you and you’re still none the wiser about how to use Arrested to build an API.

In the next section we’ll step through creating a basic API for our star character data.


2. Creating the Characters Resource.

Now that we’ve got our application set up we can start creating our Characters APIs. We will add endpoints that allow clients to fetch a list of characters, create new characters, find a character by and and update and delete characters.

Before we can create our new APIs we need to create the Character model and CharacterMapper.

$ touch star_wars/models/character.py
$ touch star_wars/apis/v1/characters.py
$ touch star_wars/apis/v1/mappers/character.py

We’ll start with a very simple Character object that has a name.

Now import the model in the models/__init__.py

Create a migration for the new model.

$ docker-compose run --rm api flask db revision "character model"
INFO [alembic.runtime.migration] Context impl SQLiteImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
INFO [alembic.autogenerate.compare] Detected added table 'character'
Generating /opt/code/star_wars/migrations/d7d80c02d806_character_model.py ... done
# Now apply the migration to create the table
$ docker-compose run --rm api flask db upgrade

Add the Character mapper to the file we created earlier. star_wars/apis/v1/mappers/character.py The Mapper is responsible for serializing and marshaling our APIS data. You can read more about Kim here

Now import the mapper to the mapper/__init__.py module

Great! Now we have our database model and a way to serialize it, let’s create an endpoint that allows our API clients to get a list of characters. Add the following code to the api/v1/characters.py file we created.

Now we need to register our new Resource with the Arrested API object. Open up apis/v1/__init__.py module and import the characters_resource. Then register the resource against the v1 API object. Also specify the defer=True to instruct Arrested to defer registering the routes with Flask until the API object is initialised.

Let’s give our new Endpoint a test run. Make sure the Docker container is running and then use the curl command provided to make a GET request to the characters resource.

$ docker-compose up api
$ curl -u admin:secret localhost:8080/v1/characters | python -m json.tool

{
"payload": []
}

Awesome! We got a response but we’ve not got any character objects in our database yet. Now we need to add the ability to create new characters via our endpoint using the DBCreateMixin

Our characters.py module now looks like this

All we needed to do to support the creation of our Character object was mixin the DBCreateMixin to our CharactersIndexEndpoint. Arrested’s integration with SQLAlchemy and Kim handles validating the incoming data, converting our JSON input into a Character object and then persisting it to the database. Let’s go ahead and create a Character.

curl -u admin:secret -H "Content-Type: application/json" -d '{"name":"Darth Vader"}' -X POST localhost:8080/v1/characters | python -m json.tool

{
"payload": {
"created_at": "2017-11-22T08:18:26.044931",
"id": 1,
"name": "Darth Vader",
"updated_at": "2017-11-22T08:18:26.044958"
}
}

Darth Vader was successfully created. Now if we make the GET request we made earlier at our API we should see Darth Vader returned.

curl -u admin:secret localhost:8080/v1/characters | python -m json.tool

{
"payload": [
{
"created_at": "2017-11-22T08:18:26.044931",
"id": 1,
"name": "Darth Vader",
"updated_at": "2017-11-22T08:18:26.044958"
}
]
}

Now we need to set up an Endpoint that allows clients to fetch a Character using a resource ID.

We’ve added a new Endpoint CharacterObjectEndpoint and registered it with the characters resource. The DBObjectMixin will allow us to fetch a resource by ID, update a specific resource and delete a resource. Let’s try it out.

# Fetch a character with a resource id of 1curl -u admin:secret localhost:8080/v1/characters/1 | python -m json.tool

{
"payload": {
"created_at": "2017-11-22T08:18:26.044931",
"id": 1,
"name": "Darth Vader",
"updated_at": "2017-11-22T08:18:26.044958"
}
}
# Then we can update the characters name
curl -u admin:secret -H "Content-Type: application/json" -d '{"id": 1, "name":"Anakin Skywalker"}' -X PUT localhost:8080/v1/characters/1 | python -m json.tool

{
"payload": {
"created_at": "2017-11-22T08:18:26.044931",
"id": 1,
"name": "Anakin Skywalker",
"updated_at": "2017-11-22T08:18:26.044958"
}
}
# And finally delete a character
curl -u admin:secret -X DELETE localhost:8080/v1/characters/1

Information Security

Ensuring your users data is secure goes without saying. You will have noticed that our project requires requests to be authenticated using Basic Auth. Not only is this unsuitable when we have multiple clients accessing our API resources, it’s also insecure.

In our next post, Python REST API Authentication with JSON Web Tokens, we cover implementing JSON Web Tokens to secure access to our APIs endpoints.


So there we have it. A brief introduction to building REST APIs in Python using Arrested. We will be posting weekly tutorials expanding on this introduction so please subscribe to our publication to be updated.

If you’d like to read more about Arrested’s features then please check out the documentation.

Don’t forget to 👏 and please don’t hesitate to drop us a comment if you have any feedback or questions.

Thanks for reading.