Python API Development Fundamentals
上QQ阅读APP看书,第一时间看更新

Making HTTP Requests to the Flask API using curl and httpie

Now, we are going to use the httpie and curl commands to test our API endpoints. We will test the functions for getting all the recipes back from the server and create/update/delete, publish, and unpublish the recipes. The best way to learn this is to complete a hands-on exercise. Let's get started!

Exercise 11: Testing the Endpoints Using curl and httpie

In this exercise, we are going to use the httpie and curl commands to send requests to the endpoints so that we can create our first recipe. We want you to get comfortable using the httpie and curl command-line testing tool. Let's get started:

  1. Open the Terminal in PyCharm and type in the following commands. You can use either the httpie or curl command. The following is the httpie command (= is for string and := is for non-string):

    http POST localhost:5000/recipes name="Cheese Pizza" description="This is a lovely cheese pizza" num_of_servings:=2 cook_time:=30 directions="This is how you make it"

    The following is the curl command. The -H argument is used to specify the header in the client request. We will set Content-Type: application/json as the header here. The -d argument is used for HTTP POST data, that is, the recipe in JSON format:

    curl -i -X POST localhost:5000/recipes -H "Content-Type: application/json" -d '{"name":"Cheese Pizza", "description":"This is a lovely cheese pizza", "num_of_servings":2, "cook_time":30, "directions":"This is how you make it" }'

  2. Examine the response, you should see the following. Carefully examine it, it should be the same recipe as the one that was used in our request in Step 1:

    HTTP/1.0 201 CREATED

    Content-Type: application/json

    Content-Length: 188

    Server: Werkzeug/0.16.0 Python/3.7.0

    Date: Sun, 03 Nov 2019 03:19:00 GMT

    {

        "id": 1,

        "name": "Cheese Pizza",

        "description": "This is a lovely cheese pizza",

        "num_of_servings": 2,

        "cook_time": 30,

        "directions": "This is how you make it"

    }

    Note

    Once the client request has been sent to the server using the HTTP POST method, the post method in RecipeResource will pick up the request and save the recipe in the request to the application memory. The new recipe will be appended in recipe_list. Once everything is done, it will return HTTP 201 CREATED and the newly created recipe in JSON format.

We have successfully created our first recipe on the platform. This recipe is stored on the server-side and we already have the API to retrieve it. Let's continue by creating our second recipe and retrieving all our recipes in one go.

Exercise 12: Testing the Auto-Incremented Recipe ID

Now that we have implemented the auto-incremented ID in our Smilecook application, let's see how it works in practice. In this exercise, we will create the second recipe using the httpie and curl commands. Note that the ID is auto- incremented for our second recipe. Let's get started:

  1. Create a second recipe and note that the ID is automatically incremented. Send the following client request using httpie:

    http POST localhost:5000/recipes name="Tomato Pasta" description="This is a lovely tomato pasta recipe" num_of_servings:=3 cook_time:=20 directions="This is how you make it"

    Alternatively, send the request using curl. Again, the -H argument is used to specify the header in the client request. We will set "Content-Type: application/json" as the header here. The -d argument is used for HTTP POST data, meaning that the recipe is in JSON format:

    curl -i -X POST localhost:5000/recipes -H "Content-Type: application/json" -d '{"name":"Tomato Pasta", "description":"This is a lovely tomato pasta recipe", "num_of_servings":3, "cook_time":20, "directions":"This is how you make it"}'

  2. You should see the following response. Examine it carefully, it should be the same recipe as the one that was used in our request in Step 1:

    HTTP/1.0 201 CREATED

    Content-Type: application/json

    Content-Length: 195

    Server: Werkzeug/0.16.0 Python/3.7.0

    Date: Sun, 03 Nov 2019 03:23:37 GMT

    {

        "id": 2,

        "name": "Tomato Pasta",

        "description": "This is a lovely tomato pasta recipe",

        "num_of_servings": 3,

        "cook_time": 20,

        "directions": "This is how you make it"

    }

    Once the preceding client request has been sent to the server using the HTTP POST method, the post method in RecipeResource will pick up the request and save the recipe in the request to the application memory. The new recipe will be appended in recipe_list. This time, the ID will be automatically assigned to 2.

Exercise 13: Getting All the Recipes Back

In this exercise, we will be using the httpie and curl commands to get back all the recipes that we have created. We are doing this to ensure that our recipes are there in the backend server. Let's get started:

  1. Retrieve all the recipes by sending the following client request using httpie:

    http GET localhost:5000/recipes

    Alternatively, send the following request using curl. The -i argument is used to state that we want to see the response header. -X GET means that we are sending the client request using the HTTP GET method:

    curl -i -X GET localhost:5000/recipes

  2. You should see the following response. Please examine it carefully:

    HTTP/1.0 200 OK

    Content-Length: 19

    Content-Type: application/json

    Date: Sun, 03 Nov 2019 03:24:53 GMT

    Server: Werkzeug/0.16.0 Python/3.7.0

    {

        "data": []

    }

    Once the preceding client request has been sent to the server using the HTTP GET method, the get method in RecipeResource will pick up the request and retrieve all the published recipes from recipe_list in the application memory.

    Note

    We should see an empty list in the HTTP response because all the recipes we have created in the previous steps are in draft form (not published).

Exercise 14: Testing the Recipe Resources

We have already tested the endpoints we built around the recipe resources. In this exercise, we will continue to use the httpie and curl commands to test the recipe publishing API. We can test it by sending requests asking to publish our recipes on the API endpoint. Let's get started:

  1. Modify the publish status of the recipe with ID 1. We can send the following client request using the httpie command:

    http PUT localhost:5000/recipes/1/publish

    Alternatively, we can use the following curl command:

    curl -i -X PUT localhost:5000/recipes/1/publish

    Note

    Once the preceding client request has been sent to the server using the HTTP PUT method, the put method in RecipePublishResource will pick up the request and assign recipe_id to be 1. The application will look for the recipe with ID = 1 and update its publish status to True.

  2. You should see the following response. Please examine it carefully:

    HTTP/1.0 204 NO CONTENT

    Content-Type: application/json

    Date: Sun, 03 Nov 2019 03:25:48 GMT

    Server: Werkzeug/0.16.0 Python/3.7.0

  3. Now, retrieve all the published recipes and examine them. Then, send the following client request using httpie:

    http GET localhost:5000/recipes

    Alternatively, send the following request using curl. The -i argument is used to say that we want to see the response header. -X GET means that we are sending the client request using the HTTP GET method:

    curl -i -X GET localhost:5000/recipes

  4. You should see the following response. Please examine it carefully:

    HTTP/1.0 200 OK

    Content-Type: application/json

    Content-Length: 276

    Server: Werkzeug/0.16.0 Python/3.7.0

    Date: Sun, 03 Nov 2019 03:26:43 GMT

    {

        "data": [

            {

                "id": 1,

                "name": "Cheese Pizza",

                "description": "This is a lovely cheese pizza",

                "num_of_servings": 2,

                "cook_time": 30,

                "directions": "This is how you make it"

            }

        ]

    }

    Once the preceding client request has been sent to the server using the HTTP GET method, the get method in RecipeResource will pick up the request and retrieve all the published recipes from recipe_list in the application memory. This time, because the recipe with ID 1 has been set to publish, we shall see it in the HTTP response.

Exercise 15: Negative Testing

In the previous exercise, we successfully published our recipe. This is good because it shows us that the APIs that we've developed work. But the whole point of testing is to discover potential issues if any. We can perform so-called negative testing here. This is the process of deliberately testing the scenario with unwanted input. This exercise is going to test a request with an HTTP VERB that has no corresponding method defined in the resource. Let's get started:

  1. Send the following request to the server-side. This HTTP method has not been defined; let's see what happens:

    http DELETE localhost:5000/recipes

    The following is the curl command, which does the same thing:

    curl -i -X DELETE localhost:5000/recipes

  2. You should see the following response. Please examine it carefully:

    HTTP/1.0 405 METHOD NOT ALLOWED

    Content-Type: application/json

    Content-Length: 70

    Allow: POST, GET, HEAD, OPTIONS

    Server: Werkzeug/0.16.0 Python/3.7.0

    Date: Sun, 03 Nov 2019 03:27:37 GMT

    {

        "message": "The method is not allowed for the requested URL."

    }

    We should see a response with an HTTP status of 405, which means that the method is not allowed for the requested URL. This makes sense because we have not defined a delete method in RecipeListResource.

Negative testing is important. We always want our testing to be more complete and covers more scenarios.

Exercise 16: Modifying the Recipes

In our Smilecook application, authors are allowed to update their recipes. It is like a blogging platform, where the authors can take their time to perfect their work, even after it has been published. Since we have already built the API, we would like to test it using Postman. Let's get started:

  1. Use the PUT method to send the request to localhost:5000/recipes/1, along with the new recipe details:

    http PUT localhost:5000/recipes/1 name="Lovely Cheese Pizza" description="This is a lovely cheese pizza recipe" num_of_servings:=3 cook_time:=60 directions="This is how you make it"

    Alternatively, send the following request using curl. The -H argument is used to specify the header in the client request. We will set "Content-Type: application/json" as the header here. The -d argument is used for HTTP POST data, meaning that the recipe will be in JSON format:

    curl -i -X PUT localhost:5000/recipes/1 -H "Content-Type: application/json" -d '{"name":"Lovely Cheese Pizza", "description":"This is a lovely cheese pizza recipe", "num_of_servings":3, "cook_time":60, "directions":"This is how you make it"}'

  2. You should see the following response. Please examine it carefully:

    HTTP/1.0 200 OK

    Content-Type: application/json

    Content-Length: 202

    Server: Werkzeug/0.16.0 Python/3.7.0

    Date: Sun, 03 Nov 2019 03:28:57 GMT

    {

        "id": 1,

        "name": "Lovely Cheese Pizza",

        "description": "This is a lovely cheese pizza recipe",

        "num_of_servings": 3,

        "cook_time": 60,

        "directions": "This is how you make it"

    }

    Once the preceding client request has been sent to the server using the HTTP PUT method, the put method in RecipeResource will pick up the request and assign recipe_id to be 1. The application will look for the recipe with id = 1 and update its details with those in the client request. The preceding response shows that the recipe with ID 1 is modified.

We just finished testing another important feature. You have been doing great. Let's keep going!

Exercise 17: Getting Back Specific Recipes with a Certain ID

So far, we have tested getting all the recipes back. But in the real world, a user will want to only get the recipes that they want to see. They can do this by using the recipe ID. This exercise will show you how to get a particular recipe with a certain ID. Let's get started:

  1. Send the following client request using httpie:

    http GET localhost:5000/recipes/1

    Alternatively, use the following curl command, which does the same thing:

    curl -i -X GET localhost:5000/recipes/1

    You should see the following response. Please examine it carefully:

    HTTP/1.0 200 OK

    Content-Type: application/json

    Content-Length: 202

    Server: Werkzeug/0.16.0 Python/3.7.0

    Date: Sun, 03 Nov 2019 03:29:59 GMT

    {

        "id": 1,

        "name": "Lovely Cheese Pizza",

        "description": "This is a lovely cheese pizza recipe",

        "num_of_servings": 3,

        "cook_time": 60,

        "directions": "This is how you make it"

    }

    Once the preceding client request has been sent to the server using the HTTP GET method, the get method in RecipeResource will pick up the request and assign recipe_id to be 1. It will retrieve all the published recipes from recipe_list in the application memory with an HTTP status of HTTP 200.

We have just tested our Smilecook application and confirmed that it can give us back the recipe we want.

Activity 3: Testing the APIs Using Postman

We added quite a few functions in the previous exercise. Now, we need to make sure that they work properly before we move on and develop other functions. In this activity, instead of using httpie/curl, we will be testing our API using Postman. Please follow these high-level steps:

  1. Create the first recipe using Postman.
  2. Create the second recipe using Postman.
  3. Retrieve all the recipes using Postman.
  4. Set the recipes to published using Postman.
  5. Retrieve all the recipes using Postman again.
  6. Modify the recipe using Postman.
  7. Get a specific recipe back using Postman.

    Note

    The solution to this activity can be found on page 293.

Activity 4: Implementing the Delete Recipe Function

In this activity, you will implement the delete recipe function in the Smilecook application yourself. Do this by adding a delete function to RecipeResource, similar to what we did in the previous exercises. Then, we will follow the standard software development life cycle flow, which is used to test our implementation, using Postman. Follow these steps to complete this activity:

  1. Add the delete function to RecipeResource.
  2. Start up the Flask server for testing.
  3. Create the first recipe using Postman.
  4. Delete the recipe using Postman.

    Note

    The solution to this activity can be found on page 299.