Welcome back! In the last lesson, you learned how to make your cooking assistant more accessible by generating audio instructions. Now, we are going to make your cooking API even more useful and interactive by adding two new features: the ability to list all available ingredients and to let users submit reviews for recipes.
These features are important for any smart cooking app. Listing ingredients helps users see what’s available or filter recipes, while reviews allow users to share feedback and help others find the best recipes. By the end of this lesson, you will know how to build and test these endpoints using a modern API framework.
Before we dive in, let’s quickly remind ourselves how endpoints work in this framework. Instead of defining the URL and the logic in the same place, we split them into two files:
urls.py: This file handles routing. It maps a URL path (like/hello) to a specific function.views.py: This file contains the logic. It defines functions (called "views") that take arequestand return a response.
To restrict which HTTP methods (like GET or POST) an endpoint accepts, we use decorators like @require_http_methods.
For example, here’s a simple GET endpoint:
urls.py
views.py
In this lesson, you’ll use this pattern to build your new endpoints.
Let’s start by creating an endpoint that lists all unique ingredients in your database. This will be a GET endpoint, which means users will request data from it.
First, you need to define the function in views.py and map it to a path in urls.py. The view function always takes a request object as its first argument.
views.py
urls.py
Next, you want to get all unique ingredient names from the database. You can use the ORM (Object-Relational Mapper) to do this efficiently:
Ingredient.objects.values_list("name", flat=True)asks the database for just the values of thenamecolumn..distinct()ensures you only get each name once.
The ORM query returns a special QuerySet object. To return this as a JSON response, we convert it into a standard list.
list(names)converts the database result into a simple list of strings.safe=Falseis required inJsonResponsewhenever you are returning a list (an array) instead of a dictionary (an object) at the top level.
Here is how the implementation looks across your files:
recipes/urls.py
recipes/views.py
Example Output:
If your database has eggs, flour, and milk, a GET request to /ingredients will return:
Now, let’s add a way for users to submit reviews for recipes. This will be a POST endpoint. Because we are receiving data, we need to handle manual JSON parsing and security.
To handle a POST request for data submission, we use two important decorators:
@csrf_exempt: This allows external tools or frontends to sendPOSTrequests to our API without needing a security token (common for purely programmatic APIs).@require_http_methods(["POST"]): This ensures the endpoint only reacts toPOSTrequests.
Since the data is sent in the request body as JSON, we must parse it manually. We also need to check if the user provided the required fields and if the rating is within the valid range (1 to 5).
We also check whether the recipe being reviewed actually exists in our database:
.filter(pk=recipe_id).first()looks for a recipe where the primary key matches theID. If none is found, it returnsNone.
If the data is valid, we create a new record in the database and return a 201 Created status code.
Review.objects.create()builds and saves the object in one step.status=201explicitly tells the user that a new resource was created.
Here is the complete implementation for the reviews endpoint, including a helper for parsing:
recipes/views.py
Example Input:
A user sends this JSON to /reviews:
Example Output:
In this lesson, you learned how to add two important features to your smart cooking API: listing all unique ingredients and allowing users to submit reviews. You saw how to:
- Map
URLsinurls.pyto logic inviews.py. - Use
ORMmethods likevalues_listanddistinct. - Manually parse
JSONfrom arequestbody and perform validation. - Return appropriate status codes like
201for created resources and422or400for errors.
Next, you’ll get a chance to practice these skills by building and testing similar endpoints on your own!
