Welcome back! In the last lesson, you learned how to build basic endpoints to retrieve recipes from your database, including fetching a single recipe by its ID
and listing recipes with pagination. These are the building blocks of any recipe API.
Now, let’s take things a step further. Imagine you open a cooking app and want to find recipes that use only the ingredients you have in your kitchen. Or maybe you want to see the steps of a recipe as a list so you can follow them one by one. These features make your app much more helpful and user-friendly.
In this lesson, you’ll learn how to:
- Search for recipes by a list of ingredients.
- Return recipe steps as an array, not just a long string.
These skills will help you build a smarter, more flexible recipe API.
Before we dive in, let’s quickly remind ourselves how our data is organized. This will help you understand how searching and filtering work.
- Recipe: Each recipe has an
id
, aname
, asteps
field (which is a string with all the steps), and a list ofingredients
. - Ingredient: Each ingredient has an
id
and aname
. Ingredients are linked to recipes through a many-to-many relationship. - Review: Each review is linked to a recipe and has a
rating
.
Here’s a simplified look at the models (from your models.py
):
- The
recipe_ingredient
table connects recipes and ingredients. - Each recipe can have many ingredients, and each ingredient can be used in many recipes.
This structure is important for searching recipes by ingredients.
Many apps and websites want to show recipe steps one at a time, not as a single long string. To help with this, you can create an endpoint that returns the steps as a list.
First, get the recipe by its ID
:
get_or_404
will return a 404 error if the recipe does not exist.
Assume the steps
are stored as a string, with each step on a new line. You can split this string into a list:
split('\n')
breaks the string into lines.strip()
removes any extra spaces.- The list comprehension skips any empty lines.
In this step, we use the jsonify
function to create a JSON response that includes the recipe’s ID, name, and the list of steps. The jsonify
function takes a Python dictionary and converts it into a JSON object, which is the standard format for API responses.
Here’s how you do it:
Here’s what we return:
recipe_id
: The unique ID of the recipe.name
: The name of the recipe.steps
: The list of individual steps, split into an array.
Example output:
This structure allows clients (like web or mobile apps) to easily loop through the steps and present them to users in a clear, step-by-step format.
Let’s say you want to find all recipes that use a specific set of ingredients, like "tomato"
and "basil"
. You’ll need an endpoint that takes a list of ingredient names and returns only the recipes that use all of them.
First, you need to accept a list of ingredient names from the user. In Flask
, you can do this by creating a POST
endpoint that expects a JSON body.
request.get_json()
reads the JSON body from the request.- We check if the
"ingredients"
key is present and not empty. - We also convert all ingredient names to lowercase for case-insensitive matching.
Example input:
Next, you need to find the IDs
of the ingredients that match the names provided.
- This code looks up all ingredients in the database whose names match the ones in the list.
- If no ingredients are found, we return an empty list.
Now, you want to find recipes that use all the specified ingredients. This is a bit more complex, but here’s how it works:
- The
subquery
counts how many of the requested ingredients each recipe uses. - We then select only those recipes where the count matches the number of ingredients requested. This ensures the recipe uses all the ingredients.
Finally, you return the matching recipes as a JSON list.
Example output:
If no recipes match, you’ll get an empty list: []
.
In this lesson, you learned how to:
- Return recipe steps as an array, making it easier for users to follow each step.
- Search for recipes by a list of ingredients, returning only those that use all the specified ingredients.
These features make your recipe API much more useful and user-friendly. Up next, you’ll get to practice building and testing these endpoints yourself. This hands-on practice will help you solidify your understanding and prepare you for even more advanced features. Good luck!
