Working with wrappers to write API views

Our code in the games_service/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 an HTTP status code. Hence, no matter what the accepted content type that's 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. The code file for the sample is included in the restful_python_2_06_01 folder, in the Django01/cmd/cmd601.txt file:

    http -v ":8000/games/" "Accept:text/html"
    http -v ":8000/games/" "Accept:application/json"

The following are the equivalent curl commands. The code file for the sample is included in the restful_python_2_06_01 folder, in the Django01/cmd/cmd602.txt file:

    curl -H "Accept: text/html" -viX GET "localhost:8000/games/"
    curl -H "Accept: application/json" -viX GET "localhost:8000/games/"

The previous commands will compose and send the following HTTP request: GET http://localhost:8000/games/. We have requested both http and curl to enable the verbose mode with the -v option in which they specify more details about the operation and display the whole request, including the request header.

The first command defines the text/html value for the Accept request header. The second command defines the application/json value for the Accept request header. You will notice that both commands produce the same results, and therefore, the view functions don't take into account the value specified for the Accept request header in the HTTP requests. The header response for both commands will include the following line:

    Content-Type: application/json

The second request specified that it will only accept text/html, but the response included a JSON body, that is, application/json content. Thus, our first version of the RESTful API is not prepared to render content other from JSON. We will make some changes to enable the API to render other contents.

Whenever we have doubts about the methods supported by a resource or resource collection in a RESTful API, we can compose and send an HTTP request with the OPTIONS HTTP verb and the URL for the resource or resource collection. If the RESTful API implements the OPTIONS HTTP verb for a resource or resource collection, it provides a comma-separated list of HTTP verbs or methods that it supports as a value for the Allow header in the response. In addition, the response header will include additional information about other supported options, such as the content type it is capable of parsing from the request and the content type it is capable of rendering on the response.

For example, if we want to know which HTTP verbs the games collection supports, we can run the following command. The code file for the sample is included in the restful_python_2_06_01 folder, in the Django01/cmd/cmd603.txt file:

    http OPTIONS ":8000/games/"

The following is the equivalent curl command. The code file for the sample is included in the restful_python_2_06_01 folder, in the Django01/cmd/cmd604.txt file:

    curl -iX OPTIONS "localhost:8000/games/"

The previous command will compose and send the following HTTP request: OPTIONS http://localhost:8000/games/. The request will match and run the views.game_collection function, that is, the game_collection function declared within the game_service/games/views.py file. This function only runs code when the request.method is equal to 'GET' or 'POST'. In this case, request.method is equal to 'OPTIONS', and therefore, the function won't run any code and won't return any response, specifically, it won't return an HttpResponse instance. As a result, we will see the Internal Server Error shown in the next screenshot listed in Django's development server console output:

The following lines show the header for the output that also includes a huge HTML document with detailed information about the error because the debug mode is activated for Django. We receive a 500 Internal Server Error status code. Notice that you will have to scroll up in the Terminal or Command Prompt to find these lines:

    HTTP/1.1 500 Internal Server Error
    Content-Length: 51566
    Content-Type: text/html
    Date: Thu, 25 Oct 2018 04:14:09 GMT
    Server: WSGIServer/0.2 CPython/3.7.1
    Vary: Cookie
    X-Frame-Options: SAMEORIGIN

Obviously, we want to provide a more consistent API and we want to provide an accurate response when we receive a request with the OPTIONS verbs for either a game resource or the games collection.

If we compose and send an HTTP request with the OPTIONS verb for a game resource, we will see the same error and we will have a similar response because the views.game_detail function only runs code when request.method is equal to 'GET', 'PUT', or 'DELETE'.

The following commands will produce the explained error when we try to see the options offered for the game resource whose ID is equal to 2. Don't forget to replace 2 with a primary key value of an existing game in your configuration. The code file for the sample is included in the restful_python_2_06_01 folder, in the Django01/cmd/cmd605.txt file:

    http OPTIONS ":8000/games/3/"

The following is the equivalent curl command. The code file for the sample is included in the restful_python_2_06_01 folder, in the Django01/cmd/cmd606.txt file:

    curl -iX OPTIONS "localhost:8000/games/3/"

We just need to make a few small changes in the games_service/games/views.py file to solve the issues we have been analyzing for our RESTful API. We will use the useful @api_view decorator, declared in the rest_framework.decorators module, for our function-based views. This decorator allows us to specify which are the HTTP verbs that our function can process. If the request that has to be processed by the view function has an HTTP verb that isn't included in the string list specified as the http_method_names argument for the @api_view decorator, the default behavior returns a 405 Method Not Allowed status code. This way, we make sure that whenever we receive an HTTP verb that isn't considered within our function view, we won't generate an unexpected error as the decorator handles the response for the unsupported HTTP verbs or methods.

Under the hood, the @api_view decorator is a wrapper that converts a function-based view into a subclass of the rest_framework.views.APIView class. This class is the base class for all view in Django REST Framework. As we might guess, if we want to work with class-based views, we can create classes that inherit from this class and we will have the same benefits we have analyzed for the function-based views that use the decorator. We will start working with class-based views in the forthcoming examples in this chapter.

In addition, as we specify a string list with the supported HTTP verbs, the decorator automatically builds the response for the OPTIONS HTTP verb with the supported methods, parser, and rendering capabilities. Our actual version of the API is just capable of rendering JSON as its output. The usage of the decorator makes sure that we always receive an instance of the rest_framework.request.Request class in the request argument when Django calls our view function. The decorator also handles the ParserError exceptions when our function views access the request.data attribute that might cause parsing problems.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.190.159.10