Making requests that interact with resources that have relationships

Now, we will use the HTTP command or its curl equivalents to compose and send HTTP requests to the recently coded RESTful Web Service that allows us to work with drone categories, drones, pilots, and competitions. 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.

Launch Django's development server to compose and send HTTP requests to our new unsecure Web service. We will definitely add security later. In case you don't remember how to start Django's development server, check the instructions in Chapter 3, Creating API Views, in the Launching Django's development server section.

First, we will compose and send an HTTP POST request to create a new drone category:

http POST :8000/drone-categories/ name="Quadcopter"

The following is the equivalent curl command:

curl -iX POST -H "Content-Type: application/json" -d '{"name":"Quadcopter"}' localhost:8000/drone-categories/  

The previous command will compose and send a POST HTTP request with the specified JSON key/value pair. The request specifies /drone-categories/, and therefore, it will match the '^drone-categories/$' regular expression and run the post method for the views.DroneCategoryList class based view. Remember that the method is defined in the ListCreateAPIView superclass and it ends up calling the create method defined in mixins.CreateModelMixin.

If the new DroneCategory instance was successfully persisted in the database, the call to the method will return an HTTP 201 Created status code and the recently persisted DroneCategory serialized to JSON in the response body. The following line shows a sample response for the HTTP request with the new DroneCategory object in the JSON response. Notice that the response body includes both the primary key, pk, and the URL, url, for the created category. The drones array is empty because there aren't drones related to the recently created drone category yet. The response doesn't include the header to focus on the body:

{
     "drones": [], 
     "name": "Quadcopter", 
     "pk": 1, 
     "url": "http://localhost:8000/drone-categories/1"
}

Now, we will compose and send HTTP requests to create two drones that belong to the drone category we recently created: Quadcopter. We specify the drone_category value with the name of the desired drone category. The database table that persists the Drone model (the drones_drone table) will save the value of the primary key of the related DroneCategory whose name value matches the one we provide:

    http POST :8000/drones/ name="WonderDrone" drone_category="Quadcopter" manufacturing_date="2017-07-20T02:02:00.716312Z" has_it_competed=false 
    http POST :8000/drones/ name="Atom" drone_category="Quadcopter" manufacturing_date="2017-08-18T02:02:00.716312Z" has_it_competed=false
  

The following are the equivalent curl commands:

    curl -iX POST -H "Content-Type: application/json" -d '{"name":"WonderDrone", "drone_category":"Quadcopter", "manufacturing_date": "2017-07-20T02:02:00.716312Z", "has_it_competed": "false"}' localhost:8000/drones/
    curl -iX POST -H "Content-Type: application/json" -d '{"name":"Atom", "drone_category":"Quadcopter", "manufacturing_date": "2017-08-18T02:02:00.716312Z", "has_it_competed": "false"}' localhost:8000/drones/
  

The previous commands will compose and send two POST HTTP requests with the specified JSON key/value pairs. The request specifies /toys/, and therefore, it will match the '^toys/$' regular expression and run the post method for the views.DroneList class based view.

The following lines show sample responses for the two HTTP requests with the new Drone objects in the JSON responses. Notice that the response includes only the URL, url, for the created drones and doesn't include the primary key. The value for drone_category is the name for the related DroneCategory:

    {
        "drone_category": "Quadcopter", 
        "has_it_competed": false, 
        "inserted_timestamp": "2017-11-03T01:58:49.135737Z", 
        "manufacturing_date": "2017-07-20T02:02:00.716312Z", 
        "name": "WonderDrone", 
        "url": "http://localhost:8000/drones/1"
    }
    {
        "drone_category": "Quadcopter", 
        "has_it_competed": false, 
        "inserted_timestamp": "2017-11-03T01:59:31.108031Z", 
        "manufacturing_date": "2017-08-18T02:02:00.716312Z", 
        "name": "Atom", 
        "url": "http://localhost:8000/drones/2"
    }  

We can run the commands explained in the Analyzing the database section to check the rows that were inserted in the tables that Django created in the PostgreSQL database to persist the models. The drone_category_id column for the drones_drone table saves the value of the primary key of the related row in the drones_drone_category table. The DroneSerializer class uses the SlugRelatedField to display the name value for the related DroneCategory. The following screenshot uses the psql command-line utility to query the contents for the drones_drone_category and the drones_drone table in a PostgreSQL database after running the HTTP requests:

Now, we will compose and send an HTTP request to retrieve the drone category that contains the two drones we created. Don't forget to replace 1 with the primary key value of the drone category whose name is equal to 'Quadcopter' in your configuration:

http :8000/drone-categories/1

The following is the equivalent curl command:

curl -iX GET localhost:8000/drone-categories/1  

The previous commands will compose and send the following HTTP request: GET http://localhost:8000/drone-categories/1. The request has a number after /drone-categories/, and therefore, it will match the '^drone-categories/(?P<pk>[0-9]+)$' regular expression and run the get method for the views.DroneCategoryDetail class-based view.

Remember that the method is defined in the RetrieveUpdateDestroyAPIView superclass and it ends up calling the retrieve method defined in mixins.RetrieveModelMixin. The following lines show a sample response for the HTTP request, with the DroneCategory object and the hyperlinks of the related drones in the JSON response:

    HTTP/1.0 200 OK
    Allow: GET, PUT, PATCH, DELETE, HEAD, OPTIONS
    Content-Length: 154
    Content-Type: application/json
    Date: Fri, 03 Nov 2017 02:58:33 GMT
    Server: WSGIServer/0.2 CPython/3.6.2
    Vary: Accept, Cookie
    X-Frame-Options: SAMEORIGIN
    
    {
        "drones": [
            "http://localhost:8000/drones/2", 
            "http://localhost:8000/drones/1"
        ], 
        "name": "Quadcopter", 
        "pk": 1, 
        "url": "http://localhost:8000/drone-categories/1"
    }  

The DroneCategorySerializer class defined the drones attribute as a HyperlinkedRelatedField, and therefore, the serializer renders the URL for each related Drone instance in the value for the drones array. Later, we will display the results in a web browser through the browsable API and we will be able to click or tap on the hyperlink to see the details for each drone.

Now, we will compose and send an HTTP POST request to create a drone related to a drone category name that doesn't exist: 'Octocopter':

    http POST :8000/drones/ name="Noisy Drone" drone_category="Octocopter" manufacturing_date="2017-10-23T02:03:00.716312Z" has_it_competed=false   

The following is the equivalent curl command:

    curl -iX POST -H "Content-Type: application/json" -d '{"name":"Noisy Drone", "drone_category":"Octocopter", "manufacturing_date": "2017-10-23T02:03:00.716312Z", "has_it_competed": "false"}' localhost:8000/drones/

Django won't be able to retrieve a DroneCategory instance whose name is equal to the specified value: Octocopter. Hence, as a result of the previous request, we will receive a 400 Bad Request status code in the response header and a message related to the value specified for the drone_category key in the JSON body. The following lines show a sample response:

    HTTP/1.0 400 Bad Request
    Allow: GET, POST, HEAD, OPTIONS
    Content-Length: 66
    Content-Type: application/json
    Date: Fri, 03 Nov 2017 03:15:07 GMT
    Server: WSGIServer/0.2 CPython/3.6.2
    Vary: Accept, Cookie
    X-Frame-Options: SAMEORIGIN
    
    {
        "drone_category": [
            "Object with name=Octocopter does not exist."
        ]
    }

Now, we will compose and send HTTP requests to create two pilots:

http POST :8000/pilots/ name="Penelope Pitstop" gender="F" races_count=0
http POST :8000/pilots/ name="Peter Perfect" gender="M" races_count=0 

The following are the equivalent curl commands:

curl -iX POST -H "Content-Type: application/json" -d '{"name":"Penelope Pitstop", "gender":"F", "races_count": 0}' localhost:8000/pilots/
    curl -iX POST -H "Content-Type: application/json" -d '{"name":"Peter Perfect", "gender":"M", "races_count": 0}' localhost:8000/pilots/  

The previous commands will compose and send two HTTP POST requests with the specified JSON key/value pairs. The request specifies /pilots/, and therefore, it will match the '^Pilots/$' regular expression and run the post method for the views.PilotList class-based view.

The following lines show sample responses for the two HTTP requests with the new Pilot objects in the JSON responses. Notice that the response includes only the url, url, for the created pilots and doesn't include the primary key. The value for gender_description is the choice description for the gender char. The competitions array is empty because there aren't competitions related to each new Pilot yet. The responses don't include the headers:

    {
        "url": "http://localhost:8000/pilots/1",
        "name": "Penelope Pitstop",
        "gender": "F",
        "gender_description": "Female",
        "races_count": 0,
        "inserted_timestamp":"2017-11-03T03:22:36.399433Z", 
        "competitions":[]
    }
    {
        "url": "http://localhost:8000/pilots/2",
        "name": "Peter Perfect",
        "gender": "M",
        "gender_description": "Male",
        "races_count": 0,
        "inserted_timestamp": "2017-11-03T03:23:02.276186Z",
        "competitions": []
    }

Now, we will compose and send many HTTP POST requests to create three competitions:

    http POST :8000/competitions/ distance_in_feet=800 distance_achievement_date="2017-10-20T05:03:20.776594Z" pilot="Penelope Pitstop" drone="Atom"
    http POST :8000/competitions/ distance_in_feet=2800 distance_achievement_date="2017-10-21T06:02:23.776594Z" pilot="Penelope Pitstop" drone="WonderDrone"
    http POST :8000/competitions/ distance_in_feet=790 distance_achievement_date="2017-10-20T05:43:20.776594Z" pilot="Peter Perfect" drone="Atom"  

The following are the equivalent curl commands:

    curl -iX POST -H "Content-Type: application/json" -d '{"distance_in_feet":"800", "distance_achievement_date":"2017-10-20T05:03:20.776594Z", "pilot":"Penelope Pitstop", "drone":"Atom"}' localhost:8000/competitions/
    curl -iX POST -H "Content-Type: application/json" -d '{"distance_in_feet":"2800", "distance_achievement_date":"2017-10-21T06:02:23.776594Z", "pilot":"Penelope Pitstop", "drone":"WonderDrone"}' localhost:8000/competitions/
    curl -iX POST -H "Content-Type: application/json" -d '{"distance_in_feet":"790", "distance_achievement_date":"2017-10-20T05:43:20.776594Z", "pilot":"Peter Perfect", "drone":"Atom"}' localhost:8000/competitions/  

The previous commands will compose and send three HTTP POST requests with the specified JSON key/value pairs. The request specifies /competitions/, and therefore, it will match the '^competitions/$' regular expression and run the post method for the views.CompetitionList class based view.

The following lines show sample responses for the three HTTP requests with the new Competition objects in the JSON responses. Django REST framework uses the PilotCompetitionSerializer class to generate the JSON response. Hence, the value for drone is the name for the related Drone instance and the value for Pilot is the name for the related Pilot instance. The PilotCompetitionSerializer class used SlugRelatedField for both fields, and therefore, we can specify the names as the values for both the drone and pilot keys. The responses don't include the headers:

    {
        "distance_achievement_date": "2017-10-20T05:03:20.776594Z", 
        "distance_in_feet": 800, 
        "drone": "Atom", 
        "pilot": "Penelope Pitstop", 
        "pk": 1, 
        "url": "http://localhost:8000/competitions/1"
    }
    {
        "distance_achievement_date": "2017-10-21T06:02:23.776594Z", 
        "distance_in_feet": 2800, 
        "drone": "WonderDrone", 
        "pilot": "Penelope Pitstop", 
        "pk": 2, 
        "url": "http://localhost:8000/competitions/2"
    }
    {
        "distance_achievement_date": "2017-10-20T05:43:20.776594Z", 
        "distance_in_feet": 790, 
        "drone": "Atom", 
        "pilot": "Peter Perfect", 
        "pk": 3, 
        "url": "http://localhost:8000/competitions/3"
    }

We can run the commands explained in the Analyzing the database section to check the rows that were inserted in the tables that Django created in the PostgreSQL database to persist the models. The drone_id column for the drones_competition table saves the value of the primary key of the related row in the drones_drone table. In addition, the pilot_id column for the drones_competition table saves the value of the primary key of the related row in the drones_pilot table. The following screenshot uses the psql command-line utility to query the contents for the drones_drone_category, drones_drone, drones_pilot, and drones_competition tables in a PostgreSQL database after running the HTTP requests:

Now, we will compose and send an HTTP GET request to retrieve a specific pilot that participated in two competitions, that is, the pilot resource whose id or primary key is equal to 1. Don't forget to replace 1 with the primary key value of the Pilot whose name is equal to 'Penelope Pitstop' in your configuration:

    http :8000/pilots/1

The following is the equivalent curl command:

    curl -iX GET localhost:8000/Pilots/1

The previous commands will compose and send the following HTTP request: GET http://localhost:8000/Pilots/1. The request has a number after /pilots/, and therefore, it will match the '^Pilots/(?P<pk>[0-9]+)$' regular expression and run the get method for the views.PilotDetail class-based view.

Remember that the get method is defined in the RetrieveUpdateDestroyAPIView superclass and it ends up calling the retrieve method defined in mixins.RetrieveModelMixin. The following lines show a sample response for the HTTP request, with the Pilot object, the related Competition objects and the Drone object related to each Competition object in the JSON response:

    HTTP/1.0 200 OK
    Allow: GET, PUT, PATCH, DELETE, HEAD, OPTIONS
    Content-Length: 909
    Content-Type: application/json
    Date: Fri, 03 Nov 2017 04:40:43 GMT
    Server: WSGIServer/0.2 CPython/3.6.2
    Vary: Accept, Cookie
    X-Frame-Options: SAMEORIGIN
    
    {
        "competitions": [
            {
                "distance_achievement_date": "2017-10-
21T06:02:23.776594Z",
"distance_in_feet": 2800, "drone": { "drone_category": "Quadcopter", "has_it_competed": false, "inserted_timestamp": "2017-11-
03T01:58:49.135737Z",
"manufacturing_date": "2017-07-
20T02:02:00.716312Z",
"name": "WonderDrone", "url": "http://localhost:8000/drones/1" }, "pk": 2, "url": "http://localhost:8000/competitions/2" }, { "distance_achievement_date": "2017-10-
20T05:03:20.776594Z",
"distance_in_feet": 800, "drone": { "drone_category": "Quadcopter", "has_it_competed": false, "inserted_timestamp": "2017-11-
03T01:59:31.108031Z",
"manufacturing_date": "2017-08-
18T02:02:00.716312Z",
"name": "Atom", "url": "http://localhost:8000/drones/2" }, "pk": 1, "url": "http://localhost:8000/competitions/1" } ], "gender": "F", "gender_description": "Female", "inserted_timestamp": "2017-11-03T03:22:36.399433Z", "name": "Penelope Pitstop", "races_count": 0, "url": "http://localhost:8000/pilots/1" }

The PilotSerializer class defined the competitions attribute as a CompetitionSerializer instance with the many argument equal to True. Hence, this serializer renders each Competition related to the Pilot. The CompetitionSerializer class defined the drone attribute as a DroneSerializer, and therefore, this serializer renders each drone related to the competition.

Later, we will render the results in a web browser through the browsable API and we will be able to click or tap on the hyperlink of each of the related resources. However, in this case, we also see all their details without having to follow the hyperlink in the JSON response body.

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

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