Search icon
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletters
Free Learning
Arrow right icon
Building RESTful Python Web Services

You're reading from  Building RESTful Python Web Services

Product type Book
Published in Oct 2016
Publisher Packt
ISBN-13 9781786462251
Pages 418 pages
Edition 1st Edition
Languages
Author (1):
Gaston C. Hillar Gaston C. Hillar
Profile icon Gaston C. Hillar

Table of Contents (18) Chapters

Building RESTful Python Web Services
Credits
About the Author
Acknowledgments
About the Reviewer
www.PacktPub.com
Preface
1. Developing RESTful APIs with Django 2. Working with Class-Based Views and Hyperlinked APIs in Django 3. Improving and Adding Authentication to an API With Django 4. Throttling, Filtering, Testing, and Deploying an API with Django 5. Developing RESTful APIs with Flask 6. Working with Models, SQLAlchemy, and Hyperlinked APIs in Flask 7. Improving and Adding Authentication to an API with Flask 8. Testing and Deploying an API with Flask 9. Developing RESTful APIs with Tornado 10. Working with Asynchronous Code, Testing, and Deploying an API with Tornado 11. Exercise Answers

Chapter 2.  Working with Class-Based Views and Hyperlinked APIs in Django

In this chapter, we will expand the capabilities of the RESTful API that we started in the previous chapter. We will change the ORM settings to work with a more powerful PostgreSQL database and we will take advantage of the advanced features included in Django REST Framework that allow us to reduce the boilerplate code for complex APIs, such as class-based views. We will:

  • Use model serializers to eliminate duplicate code

  • Work with wrappers to write API views

  • Use the default parsing and rendering options and move beyond JSON

  • Browse the API

  • Design a RESTful API to interact with a complex PostgreSQL database

  • Understand the tasks performed by each HTTP method

  • Declare relationships with the models

  • Manage serialization and deserialization with relationships and hyperlinks

  • Create class based views and use generic classes

  • Work with endpoints for the API

  • Create and retrieve related resources

Using model serializers to eliminate duplicate code


The GameSerializer class declares many attributes with the same names that we used in the Game model and repeats information, such as the types and the max_length values. The GameSerializer class is a subclass of rest_framework.serializers.Serializer, it declares attributes that we manually mapped to the appropriate types and overrides the create and update methods.

Now, we will create a new version of the GameSerializer class that will inherit from the rest_framework.serializers.ModelSerializer class. The ModelSerializer class automatically populates both set of default fields and a set of default validators. In addition, the class provides default implementations for the create and update methods.

Tip

In case you have any experience with Django Web Framework, you will notice that the Serializer and ModelSerializer classes are similar to the Form and ModelForm classes.

Now, go to the gamesapi/games folder and open the serializers.py file....

Working with wrappers to write API views


Our code in the games/views.py file declared a JSONResponse class and two function-based views. These functions returned JSONResponse when it was necessary to return JSON data and a django.Http.Response.HttpResponse instance when the response was just of an HTTP status code.

No matter the accepted content type specified in the HTTP request header, the view functions always provide the same content in the response body-JSON. Run the following two commands to retrieve all the games with different values for the Accept request header-text/html and application/json :

http :8000/games/ Accept:text/html
http :8000/games/ Accept:application/json

The following are the equivalent curl commands:

curl -H 'Accept: text/html' -iX GET :8000/games/
curl -H 'Accept: application/json' -iX GET :8000/games/

The preceding commands will compose and send the following HTTP request: GET http://localhost:8000/games/. The first command defines the text/html value for the Accept...

Using the default parsing and rendering options and move beyond JSON


The APIView class specifies default settings for each view that we can override by specifying appropriate values in the gamesapi/settings.py file or by overriding the class attributes in subclasses. As previously explained, the usage of the APIView class under the hoods makes the decorator apply these default settings. Thus, whenever we use the decorator, the default parser classes and the default renderer classes will be associated with the function views.

By default, the value for the DEFAULT_PARSER_CLASSES is the following tuple of classes:

( 
    'rest_framework.parsers.JSONParser', 
    'rest_framework.parsers.FormParser', 
    'rest_framework.parsers.MultiPartParser' 
) 

When we use the decorator, the API will be able to handle any of the following content types through the appropriate parsers when accessing the request.data attribute:

  • application/json

  • application/x-www-form-urlencoded

  • multipart/form-data

Tip

When...

Browsing the API


With the recent edits, we made it possible for our API to use the default content renderers configured in Django REST Framework, and therefore, our API is capable of rendering the text/html content. We can take advantage of the browsable API, a feature included in Django REST Framework that generates human-friendly HTML output for each resource whenever the request specifies text/html as the value for the Content-type key in the request header.

Whenever we enter a URL for an API resource in a web browser, the browser will require an HTML response, and therefore, Django REST Framework will provide an HTML response built with Bootstrap (http://getbootstrap.com). This response will include a section that displays the resource content in JSON, buttons to perform different requests, and forms to submit data to the resources. As everything in Django REST Framework, we can customize the templates and themes used to generate the browsable API.

Open a web browser and enter http://localhost...

Designing a RESTful API to interact with a complex PostgreSQL database


So far, our RESTful API has performed CRUD operations on a single database table. Now, we want to create a more complex RESTful API with Django REST Framework to interact with a complex database model that has to allow us to register player scores for played games that are grouped into game categories. In our previous RESTful API, we used a string field to specify the game category for a game. In this case, we want to be able to easily retrieve all the games that belong to a specific game category, and therefore, we will have a relationship between a game and a game category.

We should be able to perform CRUD operations on different related resources and resource collections. The following list enumerates the resources and the model names that we will use to represent them in Django REST Framework:

  • Game categories (GameCategory model)

  • Games (Game model)

  • Players (Player model)

  • Player scores (PlayerScore model)

The game category...

Understanding the tasks performed by each HTTP method


The following table shows the HTTP verbs, the scope, and the semantics for the methods that our new API must support. Each method is composed by an HTTP verb and a scope and all the methods have well-defined meanings for all the resources and collections.

Declaring relationships with the models


Make sure you quit the Django's development server. Remember that you just need to press Ctrl + C in the terminal or command-prompt window in which it is running. Now, we will create the models that we are going to use to represent and persist the game categories, games, players and scores, and their relationships. Open the games/models.py file and replace its contents with the following code. The lines that declare fields related to other models are highlighted in the code listing. The code file for the sample is included in the restful_python_chapter_02_03 folder.

from django.db import models 
 
 
class GameCategory(models.Model): 
    name = models.CharField(max_length=200) 
 
    class Meta: 
        ordering = ('name',) 
 
    def __str__(self): 
        return self.name 
 
 
class Game(models.Model): 
    created = models.DateTimeField(auto_now_add=True) 
    name = models.CharField(max_length=200) 
    game_category = models.ForeignKey( ...

Managing serialization and deserialization with relationships and hyperlinks


Our new RESTful Web API has to be able to serialize and deserialize the GameCategory, Game, Player, and PlayerScore instances into JSON representations. In this case, we also have to pay special attention to the relationships between the different models when we create the serializer classes to manage serialization to JSON and deserialization from JSON.

In our last version of the previous API, we created a subclass of the rest_framework.serializers.ModelSerializer class to make it easier to generate a serializer and reduce boilerplate code. In this case, we will also declare a class that inherits from ModelSerializer, but the other classes will inherit from the rest_framework.serializers.HyperlinkedModelSerializer class.

The HyperlinkedModelSerializer is a type of ModelSerializer that uses hyperlinked relationships instead of primary key relationships, and therefore, it represents the realationships to other model...

Creating class-based views and using generic classes


This time, we will write our API views by declaring class-based views, instead of function-based views. We might code classes that inherit from the rest_framework.views.APIView class and declare methods with the same names than the HTTP verbs we want to process: get, post, put, patch, delete, and so on. These methods receive a request argument as happened with the functions that we created for the views. However, this approach would require us to write a lot of code. Instead, we can take advantage of a set of generic views that we can use as our base classes for our class-based views to reduce the required code to the minimum and take advantage of the behavior that has been generalized in Django REST Framework.

We will create subclasses of the two following generic class views declared in rest_framework.generics:

  • ListCreateAPIView: Implements the get method that retrieves a listing of a queryset and the post method that creates a model...

Taking advantage of generic class based views


Go to the gamesapi/games folder and open the views.py file. Replace the code in this file with the following code that declares the required imports and the class based views. We will add more classes to this file later. The code file for the sample is included in the restful_python_chapter_02_03 folder:

from games.models import GameCategory 
from games.models import Game 
from games.models import Player 
from games.models import PlayerScore 
from games.serializers import GameCategorySerializer 
from games.serializers import GameSerializer 
from games.serializers import PlayerSerializer 
from games.serializers import PlayerScoreSerializer 
from rest_framework import generics 
from rest_framework.response import Response 
from rest_framework.reverse import reverse 
 
 
class GameCategoryList(generics.ListCreateAPIView): 
    queryset = GameCategory.objects.all() 
    serializer_class = GameCategorySerializer 
    name = 'gamecategory-list' 
 
...

Working with endpoints for the API


We want to create an endpoint for the root of our API to make it easier to browse the API with the browsable API feature and understand how everything works. Add the following code to the views.py file to declare the ApiRoot class. The code file for the sample is included in the restful_python_chapter_02_03 folder.

class ApiRoot(generics.GenericAPIView): 
    name = 'api-root' 
    def get(self, request, *args, **kwargs): 
        return Response({ 
            'players': reverse(PlayerList.name, request=request), 
            'game-categories': reverse(GameCategoryList.name, request=request), 
            'games': reverse(GameList.name, request=request), 
            'scores': reverse(PlayerScoreList.name, request=request) 
            }) 

The ApiRoot class is a subclass of the rest_framework.generics.GenericAPIView class and declares the get method. The GenericAPIView class is the base class for all the other generic views. The ApiRoot class defines the...

Creating and retrieving related resources


Now, we will use the HTTPie command or its curl equivalents to compose and send HTTP requests to the API. We will use JSON for the requests that require additional data. Remember that you can perform the same tasks with your favorite GUI-based tool or with the browsable API.

First, we will compose and send an HTTP request to create a new game category. Remember that we used the browsable API to create a game category named '3D RPG'.

http POST :8000/game-categories/ name='2D mobile arcade'

The following is the equivalent curl command:

curl -iX POST -H "Content-Type: application/json" -d '{"name":"2D mobile arcade"}' :8000/game-categories/

The preceding command will compose and send a POST HTTP request with the specified JSON key-value pair. The request specifies /game-categories/, and therefore, it will match '^game-categories/$' and run the post method for the views.GameCategoryList class-based view. Remember that the method is defined in the ListCreateAPIView...

Test your knowledge


  1. Under the hoods, the @api_view decorator is:

    1. A wrapper that converts a function-based view into a subclass of the rest_framework.views.APIView class.

    2. A wrapper that converts a function-based view into a serializer.

    3. A wrapper that converts a function-based view into a subclass of the rest_framework.views.api_view class.

  2. The browsable API, a feature included in Django REST Framework that:

    1. Generates human-friendly JSON output for each resource whenever the request specifies application/json as the value for the Content-type key in the request header.

    2. Generates human-friendly HTML output for each resource whenever the request specifies text/html as the value for the Content-type key in the request header.

    3. Generates human-friendly HTML output for each resource whenever the request specifies application/json as the value for the Content-type key in the request header.

  3. The rest_framework.serializers.ModelSerializer class:

    1. Automatically populates both a set of default constraints...

Summary


In this chapter, we took advantage of the various features included in Django REST Framework that allowed us to eliminate duplicate code and build our API reusing generalized behaviors. We used model serializers, wrappers, default parsing, and rendering options, class based views, and generic classes.

We used the browsable API feature and we designed a RESTful API that interacted with a complex PostgreSQL database. We declared relationships with the models, managed serialization and deserialization with relationships, and hyperlinks. Finally, we created and retrieved related resources and we understood how things work under the hoods.

Now that we have built a complex API with Django REST Framework, we will use additional abstractions included in the framework to improve our API, we will add security and authentication, which is what we are going to discuss in the next chapter.

lock icon The rest of the chapter is locked
You have been reading a chapter from
Building RESTful Python Web Services
Published in: Oct 2016 Publisher: Packt ISBN-13: 9781786462251
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €14.99/month. Cancel anytime}

HTTP verb

Scope

Semantics

GET

Collection of game categories

Retrieve all the stored game categories in the collection, sorted by their name in ascending order. Each game category must include a list of URLs for each game resource that belongs to the category.

GET

Game category

Retrieve a single game category. The game category must include a list of URLs for each game resource that belongs to the category.

POST

Collection of game categories

Create a new game category in the collection.

PUT

Game category

Update an existing game category.

PATCH

Game category

Update one or more fields of an existing game category.

DELETE

Game category

Delete an existing...