Book Image

Building RESTful Python Web Services

By : Gaston C. Hillar
Book Image

Building RESTful Python Web Services

By: Gaston C. Hillar

Overview of this book

Python is the language of choice for millions of developers worldwide, due to its gentle learning curve as well as its vast applications in day-to-day programming. It serves the purpose of building great web services in the RESTful architecture. This book will show you the best tools you can use to build your own web services. Learn how to develop RESTful APIs using the popular Python frameworks and all the necessary stacks with Python, Django, Flask, and Tornado, combined with related libraries and tools. We will dive deep into each of these frameworks to build various web services, and will provide use cases and best practices on when to use a particular framework to get the best results. We will show you everything required to successfully develop RESTful APIs with the four frameworks such as request handling, URL mapping, serialization, validation, authentication, authorization, versioning, ORMs, databases, custom code for models and views, and asynchronous callbacks. At the end of each framework, we will add authentication and security to the RESTful APIs and prepare tests for it. By the end of the book, you will have a deep understanding of the stacks needed to build RESTful web services.
Table of Contents (18 chapters)
Building RESTful Python Web Services
Credits
About the Author
Acknowledgments
About the Reviewer
www.PacktPub.com
Preface

Making HTTP requests to the API


The Django development server is running on localhost (127.0.0.1), listening on port 8000, and waiting for our HTTP requests. Now, we will compose and send HTTP requests locally in our development computer or from other computer or devices connected to our LAN. We will use the following different kind of tools to compose and send HTTP requests throughout our book.

  • Command-line tools

  • GUI tools

  • Python code

  • JavaScript code

Tip

Notice that you can use any other application that allows you to compose and send HTTP requests. There are many apps that run on tablets and smartphones that allow you to accomplish this task. However, we will focus our attention on the most useful tools when building RESTful Web APIs.

Working with command-line tools - curl and httpie

We will start with command-line tools. One of the key advantages of command-line tools is that we can easily run again the HTTP requests after we built them for the first time, and we don't need to use the mouse or tap the screen to run requests. We can also easily build a script with batch requests and run them. As happens with any command-line tool, it can take more time to perform the first requests compared with GUI tools, but it becomes easier once we performed many requests and we can easily reuse the commands we have written in the past to compose new requests.

Curl, also known as cURL, is a very popular open source command-line tool and library that allow us to easily transfer data. We can use the curl command-line tool to easily compose and send HTTP requests and check their responses.

Tip

If you are working on either macOS or Linux, you can open a Terminal and start using curl from the command line. If you are working on any Windows version, you can easily install curl from the Cygwin package installation option, and execute it from the Cygwin terminal. You can read more about the curl utility at http://curl.haxx.se. You can read more about the Cygwin terminal and its installation procedure at http://cygwin.com/install.html.

Open a Cygwin terminal in Windows or a terminal in macOS or Linux, and run the following command. It is very important that you enter the ending slash (/) because /games won't match any of the patterns specified in urlpatterns in the games/urls.py file. We are using the default configuration for Django that doesn't redirect URLs that don't match any of the patterns to the same URLs with a slash appended. Thus, we must enter /games/, including the ending slash (/):

curl -X GET :8000/games/

The preceding command will compose and send the following HTTP request-GET http://localhost:8000/games/. The request is the simplest case in our RESTful API because it will match and run the views.game_list function, that is, the game_list function declared within the games/views.py file. The function just receives request as a parameter because the URL pattern doesn't include any parameters. As the HTTP verb for the request is GET, the request.method property is equal to 'GET', and therefore, the function will execute the code that retrieves all the Game objects and generates a JSON response with all of these Game objects serialized.

The following lines show an example response for the HTTP request, with three Game objects in the JSON response:

[{"pk":3,"name":"Angry Birds RPG","release_date":"2016-05-18T03:02:00.776594Z","game_category":"3D RPG","played":false},{"pk":2,"name":"Smurfs Jungle","release_date":"2016-05-18T03:02:00.776594Z","game_category":"2D mobile arcade","played":false},{"pk":11,"name":"Tomb Raider Extreme Edition","release_date":"2016-05-18T03:02:00.776594Z","game_category":"3D RPG","played":false}]

As we might notice from the previous response, the curl utility displays the JSON response in a single line, and therefore, it is a bit difficult to read it. In this case, we know that the Content-Type of the response is application/json. However, in case we want to have more details about the response, we can use the -i option to request curl to print the HTTP response headers. We can combine the -i and -X options by using -iX.

Go back to the Cygwin terminal in Windows or the Terminal in macOS or Linux, and run the following command:

curl -iX GET :8000/games/

The following lines show an example response for the HTTP request. The first lines show the HTTP response headers, including the status (200 OK) and the Content-type (application/json). After the HTTP response headers, we can see the details for the three Game objects in the JSON response:

HTTP/1.0 200 OK
Date: Tue, 24 May 2016 18:04:40 GMT
Server: WSGIServer/0.2 CPython/3.5.1
Content-Type: application/json
X-Frame-Options: SAMEORIGIN
[{"pk":3,"name":"Angry Birds RPG","release_date":"2016-05-18T03:02:00.776594Z","game_category":"3D RPG","played":false},{"pk":2,"name":"Smurfs Jungle","release_date":"2016-05-18T03:02:00.776594Z","game_category":"2D mobile arcade","played":false},{"pk":11,"name":"Tomb Raider Extreme Edition","release_date":"2016-05-18T03:02:00.776594Z","game_category":"3D RPG","played":false}]

After we run the two requests, we will see the following lines in the window that is running the Django development server. The output indicates that the server received two HTTP requests with the GET verb and /games/ as the URI. The server processed both HTTP requests, returned status code 200 and the response length was equal to 379 characters. The response length can be different because the value for the primary key assigned to each game will have an incidence in the response length. The first number after HTTP/1.1." indicates the returned status code (200) and the second number the response length (379).

[25/May/2016 04:35:09] "GET /games/ HTTP/1.1" 200 379
[25/May/2016 04:35:10] "GET /games/ HTTP/1.1" 200 379

The following image shows two terminal windows side-by-side on macOS. The Terminal window at the left-hand side is running the Django development server and displays the received and processed HTTP requests. The Terminal window at the right-hand side is running curl commands to generate the HTTP requests.

It is a good idea to use a similar configuration to check the output while we compose and send the HTTP requests. Notice that the JSON outputs are a bit difficult to read because they don't use syntax highlighting:

Now, we will install HTTPie, a command-line HTTP client written in Python that makes it easy to send HTTP requests and uses a syntax that is easier than curl (also known as cURL). One of the great advantages of HTTPie is that it displays colorized output and uses multiple lines to display the response details. Thus, HTTPie makes it easier to understand the responses than the curl utility. We just need to activate the virtual environment and then run the following command in the terminal or command prompt to install the HTTPie package:

pip install --upgrade httpie

The last lines for the output will indicate that the django package has been successfully installed.

Collecting httpie
  Downloading httpie-0.9.3-py2.py3-none-any.whl (66kB)
Collecting requests>=2.3.0 (from httpie)
  Using cached requests-2.10.0-py2.py3-none-any.whl
Collecting Pygments>=1.5 (from httpie)
  Using cached Pygments-2.1.3-py2.py3-none-any.whl
Installing collected packages: requests, Pygments, httpie
Successfully installed Pygments-2.1.3 httpie-0.9.3 requests-2.10.0

Tip

In case you don't remember how to activate the virtual environment that we created for this example, read the following section in this chapter-Setting up the virtual environment with Django REST framework.

Now, we can use an http command to easily compose and send HTTP requests to localhost:8000 and test the RESTful API built with Django REST framework. HTTPie supports curl-like shorthands for localhost, and therefore, we can use :8000 as a shorthand that expands to http://localhost:8000. Run the following command and remember to enter the ending slash (/):

http :8000/games/

The preceding command will compose and send the following HTTP request: GET http://localhost:8000/games/. The request is the same one we have previously composed with the curl command. However, in this case, the HTTPie utility will display a colorized output and it will use multiple lines to display the JSON response. The preceding command is equivalent to the following command that specifies the GET method after http:

http GET :8000/games/

The following lines show an example response for the HTTP request, with the headers and the three Game objects in the JSON response. It is indeed easier to understand the response compared with the results generated when we composed the HTTP request with curl. HTTPie automatically formats the JSON data received as a response and applies syntax highlighting, specifically, both colors and formatting:

HTTP/1.0 200 OK
Content-Type: application/json
Date: Thu, 26 May 2016 21:33:17 GMT
Server: WSGIServer/0.2 CPython/3.5.1
X-Frame-Options: SAMEORIGIN
[
    {
        "game_category": "3D RPG",
        "name": "Angry Birds RPG",
        "pk": 3,
        "played": false,
        "release_date": "2016-05-18T03:02:00.776594Z"
    },
    {
        "game_category": "2D mobile arcade",
        "name": "Smurfs Jungle",
        "pk": 2,
        "played": false,
        "release_date": "2016-05-18T03:02:00.776594Z"
    },
    {
        "game_category": "3D RPG",
        "name": "Tomb Raider Extreme Edition",
        "pk": 11,
        "played": false,
        "release_date": "2016-05-18T03:02:00.776594Z"
    }
]

Tip

We can achieve the same results by combining the output generated with the curl command with other utilities. However, HTTPie provides us exactly what we need to work with RESTful APIs. We will use HTTPie to compose and send HTTP request, but we will always provide the equivalent curl command.

The following image shows two Terminal windows side-by-side on macOS. The terminal window at the left-hand side is running the Django development server and displays the received and processed HTTP requests. The Terminal window at the right-hand side is running HTTPie commands to generate the HTTP requests. Notice that the JSON output is easier to read compared to the output generated by the curl command:

We can execute HTTPie with the -b option in case we don't want to include the header in the response. For example, the following line performs the same HTTP request but doesn't display the header in the response output, and therefore, the output will just display the JSON response:

http -b :8000/games/

Now, we will select one of the games from the preceding list and we will compose an HTTP request to retrieve just the chosen game. For example, in the previous list, the first game has a pk value equal to 3. Run the following command to retrieve this game. Use the pk value you have retrieved in the previous command for the first game, as the pk number might be different:

http :8000/games/3/

The following is the equivalent curl command:

curl -iX GET :8000/games/3/

The previous commands will compose and send the following HTTP request: GET http://localhost:8000/games/3/. The request has a number after /games/, and therefore, it will match '^games/(?P<pk>[0-9]+)/$' and run the views.game_detail function, that is, the game_detail function declared within the games/views.py file. The function receives request and pk as parameters because the URL pattern passes the number specified after /games/ in the pk parameter. As the HTTP verb for the request is GET, the request.method property is equal to 'GET', and therefore, the function will execute the code that retrieves the Game object whose primary key matches the pk value received as an argument and, if found, generates a JSON response with this Game object serialized. The following lines show an example response for the HTTP request, with the Game object that matches the pk value in the JSON response:

HTTP/1.0 200 OK
Content-Type: application/json
Date: Fri, 27 May 2016 02:28:30 GMT
Server: WSGIServer/0.2 CPython/3.5.1
X-Frame-Options: SAMEORIGIN
{
    "game_category": "3D RPG",
    "name": "Angry Birds RPG",
    "pk": 3,
    "played": false,
    "release_date": "2016-05-18T03:02:00.776594Z"
}

Now, we will compose and send an HTTP request to retrieve a game that doesn't exist. For example, in the preceding list, there is no game with a pk value equal to 99999. Run the following command to try to retrieve this game. Make sure you use a pk value that doesn't exist. We must make sure that the utilities display the headers as part of the response because the response won't have a body:

http :8000/games/99999/

The following is the equivalent curl command:

curl -iX GET :8000/games/99999/

The preceding commands will compose and send the following HTTP request: GET http://localhost:8000/games/99999/. The request is the same than the previous one we have analyzed, with a different number for the pk parameter. The server will run the views.game_detail function, that is, the game_detail function declared within the games/views.py file. The function will execute the code that retrieves the Game object whose primary key matches the pk value received as an argument and a Game.DoesNotExist exception will be thrown and captured because there is no game with the specified pk value. Thus, the code will return an HTTP 404 Not Found status code. The following lines show an example header response for the HTTP request:

HTTP/1.0 404 Not Found
Content-Type: text/html; charset=utf-8
Date: Fri, 27 May 2016 02:20:41 GMT
Server: WSGIServer/0.2 CPython/3.5.1
X-Frame-Options: SAMEORIGIN

We will compose and send an HTTP request to create a new game.

http POST :8000/games/ name='PvZ 3' game_category='2D mobile arcade' played=false release_date='2016-05-18T03:02:00.776594Z'

The following is the equivalent curl command. It is very important to use the -H "Content-Type: application/json" option to indicate curl to send the data specified after the -d option as application/json instead of the default application/x-www-form-urlencoded:

curl -iX POST -H "Content-Type: application/json" -d '{"name":"PvZ 3", "game_category":"2D mobile arcade", "played": "false", "release_date": "2016-05-18T03:02:00.776594Z"}' :8000/games/

The previous commands will compose and send the following HTTP request: POST http://localhost:8000/games/ with the following JSON key-value pairs:

{  
    "name": "PvZ 3",  
    "game_category": "2D mobile arcade",  
    "played": false,  
    "release_date": "2016-05-18T03:02:00.776594Z" 
} 

The request specifies /games/, and therefore, it will match '^games/$' and run the views.game_list function, that is, the game_detail function declared within the games/views.py file. The function just receives request as a parameter because the URL pattern doesn't include any parameters. As the HTTP verb for the request is POST, the request.method property is equal to 'POST', and therefore, the function will execute the code that parses the JSON data received in the request, creates a new Game and, if the data is valid, it saves the new Game. If the new Game was successfully persisted in the database, the function returns an HTTP 201 Created status code and the recently persisted Game serialized serialized to JSON in the response body. The following lines show an example response for the HTTP request, with the new Game object in the JSON response:

HTTP/1.0 201 Created
Content-Type: application/json
Date: Fri, 27 May 2016 05:12:39 GMT
Server: WSGIServer/0.2 CPython/3.5.1
X-Frame-Options: SAMEORIGIN
{
    "game_category": "2D mobile arcade",
    "name": "PvZ 3",
    "pk": 15,
    "played": false,
    "release_date": "2016-05-18T03:02:00.776594Z"
}

Now, we will compose and send an HTTP request to update an existing game, specifically, the previously added game. We have to check the value assigned to pk in the previous response and replace 15 in the command with the returned value. For example, in case the value for pk was 5, you should use :8000/games/5/ instead of :8000/games/15/.

http PUT :8000/games/15/ name='PvZ 3' game_category='2D mobile arcade' played=true release_date='2016-05-20T03:02:00.776594Z'

The following is the equivalent curl command. As happened with the previous curl example, it is very important to use the -H "Content-Type: application/json" option to indicate curl to send the data specified after the -d option as application/json instead of the default application/x-www-form-urlencoded:

curl -iX PUT -H "Content-Type: application/json" -d '{"name":"PvZ 3", "game_category":"2D mobile arcade", "played": "true", "release_date": "2016-05-20T03:02:00.776594Z"}' :8000/games/15/

The previous commands will compose and send the following HTTP request: PUT http://localhost:8000/games/15/ with the following JSON key-value pairs:

{  
    "name": "PvZ 3",  
    "game_category": "2D mobile arcade",  
    "played": true,  
    "release_date": "2016-05-20T03:02:00.776594Z" 
} 

The request has a number after /games/, and therefore, it will match '^games/(?P<pk>[0-9]+)/$' and run the views.game_detail function, that is, the game_detail function declared within the games/views.py file. The function receives request and pk as parameters because the URL pattern passes the number specified after /games/ in the pk parameter. As the HTTP verb for the request is PUT, the request.method property is equal to 'PUT', and therefore, the function will execute the code that parses the JSON data received in the request, creates a Game instance from this data and updates the existing game in the database. If the game was successfully updated in the database, the function returns an HTTP 200 OK status code and the recently updated Game serialized serialized to JSON in the response body. The following lines show an example response for the HTTP request, with the updated Game object in the JSON response:

HTTP/1.0 200 OK
Content-Type: application/json
Date: Sat, 28 May 2016 00:49:05 GMT
Server: WSGIServer/0.2 CPython/3.5.1
X-Frame-Options: SAMEORIGIN
{
    "game_category": "2D mobile arcade",
    "name": "PvZ 3",
    "pk": 15,
    "played": true,
    "release_date": "2016-05-20T03:02:00.776594Z"
}

In order to successfully process a PUT HTTP request that updates an existing game, we must provide values for all the required fields. We will compose and send an HTTP request to try update an existing game, and we will fail to do so because we will just provide a value for the name. As happened in the previous request, we will use the value assigned to pk in the last game we added:

http PUT :8000/games/15/ name='PvZ 4'

The following is the equivalent curl command:

curl -iX PUT -H "Content-Type: application/json" -d '{"name":"PvZ 4"}'
    :8000/games/15/

The previous commands will compose and send the following HTTP request: PUT http://localhost:8000/games/15/ with the following JSON key-value pair:

{  
    "name": "PvZ 4",  
} 

The request will execute the same code we explained for the previous request. Because we didn't provide all the required values for a Game instance, the game_serializer.is_valid() method will return False and the function will return an HTTP 400 Bad Request status code and the details generated in the game_serializer.errors attribute serialized to JSON in the response body. The following lines show an example response for the HTTP request, with the required fields that our request didn't include values in the JSON response:

HTTP/1.0 400 Bad Request
Content-Type: application/json
Date: Sat, 28 May 2016 02:53:08 GMT
Server: WSGIServer/0.2 CPython/3.5.1
X-Frame-Options: SAMEORIGIN
{
    "game_category": [
        "This field is required."
    ],
    "release_date": [
        "This field is required."
    ]
}

Tip

When we want our API to be able to update a single field for an existing resource, in this case, an existing game, we should provide an implementation for the PATCH method. The PUT method is meant to replace an entire resource and the PATCH method is meant to apply a delta to an existing resource. We can write code in the handler for the PUT method apply a delta to an existing resource, but it is a better practice to use the PATCH method for this specific task. We will work with the PATCH method later.

Now, we will compose and send an HTTP request to delete an existing game, specifically, the last game we added. As happened in our last HTTP requests, we have to check the value assigned to pk in the previous response and replace 12 in the command with the returned value:

http DELETE :8000/games/15/

The following is the equivalent curl command:

curl -iX DELETE :8000/games/15/

The preceding commands will compose and send the following HTTP request: DELETE http://localhost:8000/games/15/. The request has a number after /games/, and therefore, it will match '^games/(?P<pk>[0-9]+)/$' and run the views.game_detail function, that is, the game_detail function declared within the games/views.py file. The function receives request and pk as parameters because the URL pattern passes the number specified after /games/ in the pk parameter. As the HTTP verb for the request is DELETE, the request.method property is equal to 'DELETE', and therefore, the function will execute the code that parses the JSON data received in the request, creates a Game instance from this data and deletes the existing game in the database. If the game was successfully deleted in the database, the function returns an HTTP 204 No Content status code. The following lines show an example response for the HTTP request after successfully deleting an existing game:

HTTP/1.0 204 No Content
Date: Sat, 28 May 2016 04:08:58 GMT
Server: WSGIServer/0.2 CPython/3.5.1
Content-Length: 0
X-Frame-Options: SAMEORIGIN
Content-Type: text/html; charset=utf-8

Working with GUI tools - Postman and others

So far, we have been working with two terminal-based or command-line tools to compose and send HTTP requests to our Django development server-cURL and HTTPie. Now, we will work with GUI (Graphical User Interface) tools.

Postman is a very popular API testing suite GUI tool that allows us to easily compose and send HTTP requests, among other features. Postman is available as a Chrome App and as a Mac App. We can execute it in Windows, Linux and macOS as a Chrome App, that is, an application running on top of Google Chrome. In case we work with macOS, we can use the Mac App instead of the Chrome App. You can download the versions of the Postman App from the following URL-https://www.getpostman.com.

Tip

You can download and install Postman for free to compose and send HTTP requests to our RESTful APIs. You just need to sign up to Postman and we won't be using any of the paid features provided by Postman cloud in our examples. All the instructions work with Postman 4.2.2 or greater.

Now, we will use the Builder tab in Postman to easily compose and send HTTP requests to localhost:8000 and test the RESTful API with this GUI tool. Postman doesn't support curl-like shorthands for localhost, and therefore, we cannot use the same shorthands we have been using when composing requests with HTTPie.

Select GET in the dropdown menu at the left-hand side of the Enter request URL textbox, and enter localhost:8000/games/ in this textbox at the right-hand side of the dropdown. Then, click Send and Postman will display the Status (200 OK), the time it took for the request to be processed and the response body with all the games formatted as JSON with syntax highlighting (Pretty view).

The following screenshot shows the JSON response body in Postman for the HTTP GET request:

Click on Headers at the right-hand side of Body and Cookies to read the response headers. The following screenshot shows the layout for the response headers that Postman displays for the preceding response. Notice that Postman displays the Status at the right-hand side of the response and doesn't include it as the first line of the Headers, as happened when we worked with both the cURL and HTTPie utilities:

Now, we will use the Builder tab in Postman to compose and send an HTTP request to create a new game, specifically, a POST request. Follow the next steps:

  1. Select POST in the drop-down menu at the left-hand side of the Enter request URL textbox, and enter localhost:8000/games/ in this textbox at the right-hand side of the dropdown.

  2. Click Body at the right-hand side of Authorization and Headers, within the panel that composes the request.

  3. Activate the raw radio button and select JSON (application/json) in the dropdown at the right-hand side of the binary radio button. Postman will automatically add a Content-type as application/json header, and therefore, you will notice the Headers tab will be renamed to Headers (1), indicating us that there is one key-value pair specified for the request headers.

  4. Enter the following lines in the textbox below the radio buttons, within the Body tab:

{ 
    "name": "Batman vs Superman",  
    "game_category": "3D RPG",  
    "played": false,  
    "release_date": "2016-05-18T03:02:00.776594Z" 
} 

The following screenshot shows the request body in Postman:

We followed the necessary steps to create an HTTP POST request with a JSON body that specifies the necessary key-value pairs to create a new game. Click on Send and Postman will display the Status (201 Created), the time it took for the request to be processed and the response body with the recently added game formatted as JSON with syntax highlighting (Pretty view). The following screenshot shows the JSON response body in Postman for the HTTP POST request.

Tip

If we want to compose and send an HTTP PUT request with Postman, it is necessary to follow the previously explained steps to provide JSON data within the request body.

One of the nice features included in Postman is that we can easily review and again run the HTTP requests we have made by browsing the saved History shown at the left-hand side of the Postman window. The History pane displays a list with the HTTP verb followed by the URL for each HTTP request we have composed and sent. We just need to click on the desired HTTP request and click Send to run it again. The following screenshot shows the many HTTP requests in the History pane and the first one selected to send it again.

JetBrains PyCharm is a very popular multiplatform Python IDE (short for Integrated Development Environment) available on macOS, Linux and Windows. Its paid Professional version includes a REST Client that allows us to test RESTful Web services. In case we work with this version of the IDE, we can compose and send HTTP requests without leaving the IDE. You don't need a JetBrains PyCharm Professional version license to run the examples included in this book. However, as the IDE is very popular, we will learn the necessary steps to compose and send an HTTP request for our API using the REST Client included in this IDE.

Now, we will use the REST Client included in PyCharm professional to compose and send an HTTP request to create a new game, specifically, a POST request. Follow the next steps:

  1. Select Tools | Test RESTful Web Service in the main menu to display the REST Client panel.

  2. Select POST in the HTTP method dropdown menu in the REST Client pane.

  3. Enter localhost:8000 in the Host/port textbox, at the right-hand side of the dropdown.

  4. Enter /games/ in the Path textbox, at the right-hand side of the Host/port textbox.

  5. Make sure that the Request tab is activated and click on the add (+) button at the bottom of the Headers list. The IDE will display a textbox for the name and a dropdown for the value. Enter Content-Type in Name, enter application/json in Value and press Enter.

  6. Activate the Text: radio button in Request Body and click the ... button, on the right-hand side of the Text textbox, to specify the text to send. Enter the following lines in textbox included in the Specify the text to send dialog box and then click on OK.

{ 
    "name": "Teenage Mutant Ninja Turtles",  
    "game_category": "3D RPG",  
    "played": false,  
    "release_date": "2016-05-18T03:02:00.776594Z" 
} 

The following screenshot shows the request built in PyCharm Professional REST Client:

We followed the necessary steps to create an HTTP POST request with a JSON body that specifies the necessary key-value pairs to create a new game. Click on the submit request button, that is, the first button with the play icon at the upper-left corner of the REST Client pane. The REST client will compose and send the HTTP POST request, will activate the Response tab, and display the response code 201 (Created), the time it took for the request to be processed, and the content length at the bottom of the pane.

By default, the REST client will automatically apply JSON syntax highlighting to the response. However, sometimes, the JSON content is displayed without line breaks and it is necessary to click on the reformat response button, that is, the first button in the Response tab. The REST client displays the response headers in another tab, and therefore, it just displays the response body in the Response tab. The following screenshot shows the JSON response body in the REST client for the HTTP POST request:

Tip

If we want to compose and send an HTTP PUT request with the REST Client included in PyCharm Professional, it is necessary to follow the previously explained steps to provide JSON data within the request body.

In case you don't work with PyCharm Professional, run any of the following commands to compose and send the HTTP POST request to create the new game:

http POST :8000/games/ name='Teenage Mutant Ninja Turtles' game_category='3D RPG' played=false release_date='2016-05-18T03:02:00.776594Z'

The following is the equivalent curl command:

curl -iX POST -H "Content-Type: application/json" -d '{"name": "Teenage
Mutant Ninja Turtles", "game_category": "3D RPG", "played": "false",
"release_date": "2016-05-18T03:02:00.776594Z"}' :8000/games/

Telerik Fiddler is a popular tool for Windows developers. Telerik Fiddler is a free Web debugging proxy with a GUI but it only runs on Windows. Its main Web page promotes it as a multi-platform tool, but at the time this book was published, the macOS and Linux versions were completely unstable and their development abandoned. We can use Telerik Fiddler in Windows to compose and send HTTP requests, among other features. You can download Fiddler for Windows from the following URL-https://www.telerik.com/download/fiddler.

Stoplight is a popular powerful API modeling tool that allows us to easily test our APIs. Its HTTP request maker allows us to compose and send requests and generate the necessary code to make them in different programming languages, such as JavaScript, Swift, C#, PHP, Node, and Go, among others. You can sign up to work with Stoplight at the following URL-http://stoplight.io.

We can also use apps that can compose and send HTTP requests from mobile devices to work with the RESTful API. For example, we can work with the iCurlHTTP App on iOS devices such as iPad and iPhone-https://itunes.apple.com/us/app/icurlhttp/id611943891?mt=8. In Android devices, we can work with the HTTP Request App-https://play.google.com/store/apps/details?id=air.http.request&hl=en.

The following screenshot shows the results of composing and sending the following HTTP request with the iCurlHTTP App: GET http://192.168.1.106:8000/games/. Remember that you have to perform the previously explained configurations in your LAN and router to be able to access the Django development server from other devices connected to your LAN. In this case, the IP assigned to the computer running the Django Web server is 192.168.1.106, and therefore, you must replace this IP with the IP assigned to your development computer.

At the time this book was published, the mobile apps that allow you to compose and send HTTP requests do not provide all the features you can find in Postman or command-line utilities.