-
Book Overview & Buying
-
Table Of Contents
-
Feedback & Rating
Python API Development Fundamentals
By :
In this section, we will go through ways to test the API service endpoints in our recipe management application using Command Prompt. Testing is a very important step in application development. This is to ensure the functions we developed are working as expected. We can use curl or httpie, depending on your personal preference. In the subsequent exercise, we will show you both tools.
Curl (or cURL) is a command-line tool that can transfer data using URLs. We can use this tool to send requests to our API endpoints and examine the response. If you are running on macOS, you don't need to install curl. It is pre-installed in the system and you can find it in Terminal. You can also run it in the Terminal in PyCharm. However, if you are running on Windows, you need to download and install it for free from http://curl.haxx.se/download.html.
Httpie (aych-tee-tee-pie) is another command-line client that does a similar thing. It was built with the goal to improve the communication between the CLI (command-line interface) and the web. It is pretty user-friendly. For more details about httpie, please refer to https://httpie.org/.
We added httpie==1.0.2 in our requirements.txt previously, so PyCharm should have already installed it for us. The main benefit of having httpie is it will beautifully format the JSON document, making it more readable. And believe me, that will save us a lot of time when we move on to verifying the HTTP response from the server.
In this exercise, we are going to use httpie and curl to test our API endpoints. We will test the functions of getting all the recipes back from the server, and also creating/updating the recipes:

http://localhost:5000/recipes; we will be using the HTTP GET method here:http GET localhost:5000/recipes
-i is for showing the header in the response and -X is for specifying the HTTP method. We will be using GET here:curl -i -X GET localhost:5000/recipes
The http GET and curl-i -X GET commands basically do the same thing, which is using the HTTP GET method to send a request to http://localhost:5000/recipes. If the code that we put in on the server-side is working properly, the request will go through the /recipes route and the get_recipes function will be invoked. This will then get us all the recipes in JSON format.
Take a look at the response we get. The first few lines in the response are the header. It has the HTTP status 200 OK and a Content-Length of 175 bytes. The Content-Type is application/json and, in the end, we have the response body in JSON format:
HTTP/1.0 200 OK
Content-Length: 175
Content-Type: application/json
Date: Mon, 15 Jul 2019 12:40:44 GMT
Server: Werkzeug/0.15.4 Python/3.7.0
{
"data": [
{
"description": "This is a lovely egg salad recipe.",
"id": 1,
"name": "Egg Salad"
},
{
"description": "This is a lovely tomato pasta recipe.",
"id": 2,
"name": "Tomato Pasta"
}
]
}POST method, as we have lots of information that cannot be encoded in the URL. Please take a look at the following httpie command:http POST localhost:5000/recipes name="Cheese Pizza" description="This is a lovely cheese pizza"
Content-Type: application/json, as we are going to send over the details of the new recipe in JSON format. The -d here is to specify the HTTP POST data, which is our new recipe:curl -i -X POST localhost:5000/recipes -H "Content-Type: application/json" -d '{"name":"Cheese Pizza", "description":"This is a lovely cheese pizza"}'@app.route('/recipes', methods=['POST']) in the backend to catch this client request and invoke the create_recipe function. It will get the recipe details from the client request and save it to a list in the application memory. Once the recipe is successfully stored in the memory, it will return an HTTP status of 201 CREATED, and the new recipe will also be returned in the HTTP response for us to verify:HTTP/1.0 201 CREATED
Content-Length: 77
Content-Type: application/json
Date: Mon, 15 Jul 2019 14:26:11 GMT
Server: Werkzeug/0.15.4 Python/3.7.0
{
"description": "This is a lovely cheese pizza",
"id": 3,
"name": "Cheese Pizza"
}http GET localhost:5000/recipes curl -i -X GET localhost:5000/recipes
get_recipes function and get us all the recipes currently stored in the application memory in JSON format. In the following response, we can see that the HTTP header is saying OK, and the Content-Length is now slightly longer than our previous response, that is, 252 bytes. This makes sense because we are expecting to see one more recipe in the response. The Content-Type is again application/json, with the body storing the recipes in JSON format. Now we can see our new recipe with ID 3:
HTTP/1.0 200 OK
Content-Length: 252
Content-Type: application/json
Date: Tue, 16 Jul 2019 01:55:30 GMT
Server: Werkzeug/0.15.4 Python/3.7.0
{
"data": [
{
"description": "This is a lovely egg salad recipe.",
"id": 1,
"name": "Egg Salad"
},
{
"description": "This is a lovely tomato pasta recipe.",
"id": 2,
"name": "Tomato Pasta"
},
{
"description": "This is a lovely cheese pizza",
"id": 3,
"name": "Cheese Pizza"
}
]
}PUT method and send over the modified name and description of the recipe to localhost:5000/recipes/3:http PUT localhost:5000/recipes/3 name="Lovely Cheese Pizza" description="This is a lovely cheese pizza recipe."
The following is the curl command. Again, -H is to specify the header in the HTTP request, and we are setting that to "Content-Type: application/json"; -d is to specify that our data should be in JSON format:
curl -i -X PUT localhost:5000/recipes/3 -H "Content-Type: application/json" -d '{"name":"Lovely Cheese Pizza", "description":"This is a lovely cheese pizza recipe."}'@app.route('/recipes/<int:recipe_id>', methods=['PUT']) route. It will then invoke the update_recipe(recipe_id) function to look for the recipe with the passed-in recipe_id, update it, and return it. Together with the updated recipe in JSON format, we will also receive the HTTP status of OK (200):HTTP/1.0 200 OK
Content-Length: 92
Content-Type: application/json
Date: Tue, 16 Jul 2019 02:04:57 GMT
Server: Werkzeug/0.15.4 Python/3.7.0
{
"description": "This is a lovely cheese pizza recipe.",
"id": 3,
"name": "Lovely Cheese Pizza"
}localhost:5000/recipes/3 to get the recipe with ID 3, and confirm whether our previous update was successful:http GET localhost:5000/recipes/3
We can also use a curl command:
curl -i -X GET localhost:5000/recipes/3
recipe_id and return it in JSON format, together with an HTTP status of 200 OK:HTTP/1.0 200 OK
Content-Length: 92
Content-Type: application/json
Date: Tue, 16 Jul 2019 06:10:49 GMT
Server: Werkzeug/0.15.4 Python/3.7.0
{
"description": "This is a lovely cheese pizza recipe.",
"id": 3,
"name": "Lovely Cheese Pizza"
}http GET localhost:5000/recipes/101
Alternatively, use the following curl command, which will do the same thing as in the preceding code:
curl -i -X GET localhost:5000/recipes/101
@app.route('/recipes/<int:recipe_id>', methods=['GET']) in the application will catch this client request and try to look for the recipe with ID = 101. The application will return with an HTTP status of 404 and a message: "recipe not found" in JSON format:HTTP/1.0 404 NOT FOUND
Content-Length: 31
Content-Type: application/json
Date: Tue, 16 Jul 2019 06:15:31 GMT
Server: Werkzeug/0.15.4 Python/3.7.0
{
"message": "recipe not found"
}If your application passed the test, congratulations! It is a pretty solid implementation. You can choose to perform more tests by yourself if you want to.
Change the font size
Change margin width
Change background colour