Creating a production ready API with Python and Django Rest Framework – part 2

In the first part of this tutorial we have seen how to create a basic API using Django Rest Framework. This second part will explain how to implement POST methods and add different levels of permissions and authentication. If you are starting from part 2, you may want to checkout the source code at this exact point:

A step back

Before showing how easy it is to implement a POST method for our existing API, I want to do a step back and show you the “manual way”, using just the APIView class. Edit the file catalog/views.py and change the code in this way:

If we try to use the API again (from the browser of from the http client), it will still work in the same way. The difference here is that we are using the very basic APIView class and we have explicitly defined the GET method for it.

Implementing a POST method with APIView

An API is not being used at its full potential if it’s read only. We are going to implement a POST method for the existing view and testing it with httpie client again. First of all we need to add an import to catalog/views.py

then we add this method to our ProductList class:

Now let’s test our POST method we just implemented:

It works! In case something doesn’t work, try to fetch the source code at this point:

Implementing a POST method with ListCreateAPIView

Do you remember when I mentioned at the beginning that there is an easy way to do the same thing? I wasn’t cheating. Let’s change again our old code in catalog/views.py but this time we will use a different base class:

let’s test this again with httpie:

We just POSTed some data on the API! How can it work? Well, we have changed the base class from ListAPIView to ListCreateAPIView. This particular class implements a generic POST method that will accept and validate all the fields through the specified serializer.

Authentication

Now our API let us add products to the catalog, amazing! But… is it exactly what we want? In a real scenario we don’t want any random user to be able to add products in our database, so we are going to protect the POST method allowing only Admin users.

Before digging into Django Rest Framework permissions, we need to setup an authentication system. For simplicity we will implement TokenAuthentication. As first step we need to edit settings.py and insert rest_framework.authtoken in the INSTALLED_APPS:

after this, we need to add TokenAuthentication as default authentication class (append this in settings.py at the end):

Finally we need to add a particular URL to the project so that clients will be able to call an endpoint passing username and password to get a token back. Edit drftutorial/urls.py and make it’s like this:

Don’t forget to re-run the migrations, because TokenAuthorization needs to change a couple of tables:

In case you had any problem changing the code up to this point, you can always fetch the related git tag:

Testing the Authentication

Before testing the authentication, make sure you created at least the Django superuser with:

now let’s try to obtain the token we will need later for our API calls:

We will need to pass this token in every API call we want to be authenticated. The token is being passed through the “Authentication” header parameter.

API Permissions

Authentication is something that identify the user with a particular system. Permissions instead are the level of things that are allowed or not allowed for a particular user. In our case we said we want to let Admin users to be able to POST new products and we want to let even anonymous users to GET the product list.

Django Rest Framework has some built-in classes that we can apply to our views to define the level of permissions. We could have used the IsAdminUser class, but it would not allow anonymous users to perform the GET request. Or we could have used IsAuthenticatedOrReadOnly class, but this would allow any registered user to add products (and we want to let only admins).

Or…we can define our own permission class and have exactly what we want. Create a new file catalog/permissions.py

Just as a side note, SAFE_METHODS are GET, HEAD and OPTIONS. These method are considered “safe” because they don’t change any existing data. Open catalog/views.py again, import this at the beginning:

and set this as permission_classes to ProductList:

Let’s now try to add a new product using the token we got before (you will have to use your own token of course, mine only works on my local db):

It worked! We have now protected our API so that not admin people can’t create any product. If you have any problem with the code, you can check it out with this tag:

Wrapping Up

We have now implemented the POST method to add new products to our catalog. In the next episode we will see how to implement endpoints to get a single product, to update or delete products and finally we will allow registered users to send a review for a specific product.

Feedback Please

I know, this blog doesn’t have any “comment” feature (I was tired of dealing with spam), but if you want to provide some feedback you can still do it by email. Just visit my About page, you will find my email there.