Introduction: Enhancing User Experience with Dynamic Recipes

Welcome back! So far, you’ve learned how to build API endpoints that let users retrieve recipes, search by ingredients, and view recipe steps. These features are essential for any recipe app, but sometimes users want a little more excitement or guidance. For example, what if someone can’t decide what to cook and wants a random suggestion? Or maybe they want to see the most popular recipes based on ratings from other users.

In this lesson, you’ll learn how to add two new features to your cooking helper API:

  • An endpoint that returns a random recipe
  • An endpoint that returns the most popular recipes based on user ratings

These features make your app more interactive and helpful, giving users new ways to discover recipes.

Quick Recall: Retrieving and Filtering Recipes

Before we dive in, let’s quickly remind ourselves how we’ve been working with recipes so far.

Previously, you built endpoints to:

  • List all recipes with pagination (so users don’t get overwhelmed by too many results at once)
  • Retrieve a single recipe by its ID
  • Search for recipes by ingredients

All of these endpoints use Flask for routing and SQLAlchemy to interact with the database. You’ve also learned how to format JSON responses so that the data is easy to use in any app.

Now, let’s build on these skills to add dynamic selection features.

Building the Random Recipe Endpoint

Let’s start by creating an endpoint that returns a random recipe. This is useful for users who want to try something new or can’t decide what to cook.

Step 1: Setting Up the Route

First, we need to define a new route in our Flask app. We’ll use the @routes.route decorator to create a GET endpoint at /api/recipes/random.

This sets up the endpoint, but it doesn’t do anything yet.

Step 2: Selecting a Random Recipe

To select a random recipe from the database, we use SQLAlchemy’s order_by(func.random()) method. This tells the database to shuffle the recipes and pick the first one.

  • Recipe.query starts a query for all recipes.
  • .order_by(func.random()) shuffles the order randomly.
  • .first() picks the first recipe from the shuffled list.

If there are no recipes in the database, recipe will be None.

Step 3: Returning the Recipe as JSON

Now, let’s check if we found a recipe. If not, we return an error message. If we did, we return the recipe details as JSON.

  • If no recipe is found, we return a 404 error.
  • Otherwise, we build a JSON object with the recipe’s ID, name, list of ingredient names, and steps.
Full Example

Here’s the complete function:

Example Output:

This endpoint gives users a fun way to discover new recipes with a single click.

Building the Popular Recipes Endpoint

Next, let’s create an endpoint that returns the most popular recipes. We’ll define “popular” as recipes with the highest average user ratings.

Step 1: Setting Up the Route

We’ll create a GET endpoint at /api/recipes/popular.

Step 2: Calculating Average Ratings

To find popular recipes, we need to:

  • Calculate the average rating for each recipe
  • Sort recipes by their average rating, highest first
  • Limit the results to the top 10 recipes

We can do this using SQLAlchemy’s query features. First, we create a subquery that groups reviews by recipe and calculates the average rating.

  • Review.recipe_id selects all recipe_ids that will be used in the grouping clause later in the code.
  • func.avg(Review.rating) calculates the average rating for each recipe.
  • .group_by(Review.recipe_id) tells the database to group all the reviews that belong to the same recipe together. This way, when we calculate the average rating with func.avg(Review.rating), it computes the average for each recipe separately, not for all reviews combined. As a result, the query returns one row per recipe, with each row containing the recipe’s ID and its average rating.
Step 3: Joining Recipes with Ratings and Sorting

Now, we join this subquery with the Recipe table, sort by average rating, and limit it to 10 results.

  • .join(subquery, Recipe.id == subquery.c.recipe_id) links each recipe to its average rating.
  • .order_by(subquery.c.avg_rating.desc()) sorts recipes from highest to lowest average rating.
  • .limit(10) returns only the top 10 recipes.
Step 4: Formatting the Output

Finally, we build a list of recipes with their details and average ratings.

  • For each recipe, we include its ID, name, ingredients, steps, and average rating (rounded to two decimal places).
Full Example

Here’s the complete function:

Example Output:

This endpoint helps users quickly find the best-rated recipes, making it easier to choose something delicious.

Summary and What’s Next

In this lesson, you learned how to add two new endpoints to your recipe API:

  • One for serving a random recipe to help users discover new dishes
  • One for listing the most popular recipes based on user ratings

These features make your app more dynamic and user-friendly. Now, you’re ready to practice building and using these endpoints in the exercises that follow. This will help you reinforce what you’ve learned and see how these features work in real scenarios.

Keep up the great work — your cooking helper app is becoming more powerful with each lesson!

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal