Nutrition is an essential aspect of human life but many people have problems with it.
Some don’t have enough time and passion for eating healthy food, while others like to cook the same old dishes.
Today we will solve this issue, improve our diet, and learn how to create a beautiful web application for recipe search using APIs.
If you’re looking to start a food blog, this link may be helpful. (Don’t forget to SEO your food blog, like building backlinks and promotion.)
For our purposes, we’ll be using the Spoonacular API as the targeted data source.
It is a comprehensive database for food information and data.
You can find and share enormous amounts of recipes in real-life.
This API includes over 365,000 recipes, which includes over 80,000 ingredients, making it one of the best recipe APIs that includes full access to recipes and cooking instructions.
Also, the API allows for searching the recipes and cooking procedures via natural language. For example, you can search for something like “vegan desserts”, and you should receive some comprehensive search results.
Spoonacular has powerful calculation features for calories, pricing, and many other aspects. A potential user can even see a visualization of different meals of different cuisines.
Finally, there is a space for custom diets.
You can submit your particular diet, or follow the rules of some specific diet template.
This is only the tip of the iceberg – there are even associated chatbots and an ingredients autocompleting system!
In order to use the Spoonacular API, we will be using the RapidAPI platform.
Simply, sign up for a free RapidAPI user account and subscribe to the API. (hint: there’s a Basic Plan that allows you to do 500 free requests/day).
We’ll be coding in Python for this project, and we will create a Flask application with a bright demonstration of the nutrition API power. So be sure to have Python 3.7 on your machine.
Here are some of the top API endpoints:
The medial side responds to the headers and parameters within the chosen endpoint.
Here, you can check your unique RapidAPI id and host of the tested product.
It is a very informative way to meet a user with a request functionality.
Each input field has a description; you can change and test different combinations of them.
If you would like to see the results of the previously mentioned tests, look to the right side, you can find code snippets for all supported programming languages.
Now let’s review a practical example.
Once in awhile, we’ll peek into our fridge and make some strange food combinations.
Let’s create an app that helps us find recipes given the ingredients we have available.
First, let’s create a starting point for our users with a search page. If the user chooses not to type anything, the system still will back a few random propositions.
After that, the user can choose and open a detailed view of a single recipe. Each page should include dynamic information and use multiple API endpoints. The full list of them is as follows:
As mentioned before, we will make a web application using Python, so we will need a framework. Luckily, Python has a swift and very lightweight solution called Flask – a microframework, which is also quite an active programming tool. Don’t forget to install it into your Python environment.
pip install flask
The next required library – requests. It is one of the possible solutions for HTTP requests handling.
pip install requests
Now you can create a folder for a web-app and .py file. Let’s use Bootstrap for a prettified HTML layout – an open-sourced library for many CSS templates.
Next, we will create a templates subfolder with all the layout snippets. Each of them will be executed after the backside data processing. You need to have a method-handler per each unique data action. This method should render a template with a dynamic response creating.
Next, let’s use Jinja2 – a method of connecting Python code with HTML templates. It’s a syntax language for Python commands using mark-up. Okay, let’s now code something!
First, let’s create a base.html file that will be a basic template for all of the next steps.
<!doctype html> <html lang="en"> <head> <!-- Required meta tags --> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <!-- Bootstrap CSS --> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous"> <!-- Optional JavaScript --> <!-- jQuery first, then Popper.js, then Bootstrap JS --> <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.6/umd/popper.min.js" integrity="sha384-wHAiFfRlMFy6i5SRaxvfOCifBUQy1xHdJ/yoi7FRNXMRBu5WHdZYu1hA6ZOblgut" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js" integrity="sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k" crossorigin="anonymous"></script> <title>{% block title %} Base page {% endblock %}</title> </head> <body> {% block body %} Body block {% endblock %} </body> </html>
Here we include all the required style files and create blocks for the dynamic data.
Now we can try to work with the .py file.
Paste the following lines in it:
from flask import Flask, render_template, request import requests app = Flask(__name__) url = "https://spoonacular-recipe-food-nutrition-v1.p.rapidapi.com/" headers = { 'x-rapidapi-host': "spoonacular-recipe-food-nutrition-v1.p.rapidapi.com", 'x-rapidapi-key': "<YOUR_RAPID_API_KEY>", } random_joke = "food/jokes/random" find = "recipes/findByIngredients" randomFind = "recipes/random" @app.route('/') def search_page(): joke_response = str(requests.request("GET", url + random_joke, headers=headers).json()['text']) return render_template('search.html', joke=joke_response) if __name__ == '__main__': app.run()
Now we’ll create some global variables for the endpoints.
Let’s also route the home page with the search.
After receiving the joke, we pass it to the template.
Now create and modify search.html in the following way:
{% extends 'base.html' %} {% block title %} Recipes searcher {% endblock %} {% block body %} <center> <h2 style="padding-top: 3%;"> It's time for cooking! What do you have in the fridge? <br> <small class="text-muted"> Let's warm up with a joke: {{ joke }} </small> </h2> <br><br> <form action="/recipes"> <div class="input-group mb-3" style="max-width: 50%;"> <input type="text" class="form-control" placeholder="Apple, flour, sugar" aria-label="Ingridients" aria-describedby="button-addon2" name="ingridients"> <div class="input-group-append"> <button class="btn btn-outline-secondary" type="submit" id="button-addon2">Search</button> </div> </div> </form> </center> {% endblock %}
Pretty simple layout creation. But let’s try to execute our project by running the .py file.
Now let’s display the search results.
Let’s display them in a list, so we will need one more method-handler + template.
We can start with the first one.
Paste the following code under the search_page method within the .py file.
@app.route('/recipes') def get_recipes(): if (str(request.args['ingridients']).strip() != ""): # If there is a list of ingridients -> list querystring = {"number":"5","ranking":"1","ignorePantry":"false","ingredients":request.args['ingridients']} response = requests.request("GET", url + find, headers=headers, params=querystring).json() return render_template('recipes.html', recipes=response) else: # Random recipes querystring = {"number":"5"} response = requests.request("GET", url + randomFind, headers=headers, params=querystring).json() print(response) return render_template('recipes.html', recipes=response['recipes'])
Here we will request two different endpoints depending on the search results.
But don’t forget about the templates.
Create a recipes.html file and paste the following lines:
{% extends 'base.html' %} {% block title %} Recipes searcher {% endblock %} {% block body %} <h2 style="text-align: center"> <a href="/" style="text-decoration: none; color:red"> Recipes for you: </a></h2> <div style="margin-left:35%;"> <ul class="list-unstyled"> {% for recipe in recipes %} <li class="media"> <img src="{{recipe['image']}}" class="align-self-center mr-3" alt="..." width="15%" height="15%"> <div class="media-body"> <h5 class="mt-0 mb-1"><a href="/recipe?id={{ recipe['id'] }}">{{ recipe['title'] }}</a></h5> {% if 'likes' not in recipe%} How many minutes for preparation? {{recipe['preparationMinutes']}} <br> How many minutes for cooking? {{recipe['cookingMinutes']}} <br> How many likes has this recipe? {{recipe['aggregateLikes']}} <br> {% else %} How many your ingridients? {{recipe['usedIngredientCount']}} <br> How many missed ingridients? {{recipe['missedIngredientCount']}} <br> How many likes has this recipe? {{recipe['likes']}} <br> {% endif %} </div> </li> <br> {% endfor %} </ul> </div > {% endblock %}
Again, there is a clear separation of two different ways of generating recipes.
Now let’s test it. Let’s try searching for something:
Here are the results for “pork, lemon, honey”.
The user can compare the original recipe and the pointed products.
But how will our app work without any search?
When no search is performed, five random dishes are displayed, including the amount of time required for preparing and cooking.
Now, let’s get a detailed display of the recipes. Let’s start with a usual method in the .py file.
@app.route('/recipe') def get_recipe(): recipe_id = request.args['id'] recipe_info_endpoint = "recipes/{0}/information".format(recipe_id) ingedientsWidget = "recipes/{0}/ingredientWidget".format(recipe_id) equipmentWidget = "recipes/{0}/equipmentWidget".format(recipe_id) recipe_info = requests.request("GET", url + recipe_info_endpoint, headers=headers).json() recipe_headers = { 'x-rapidapi-host': "spoonacular-recipe-food-nutrition-v1.p.rapidapi.com", 'x-rapidapi-key': "<YOUR_RAPID_API_KEY>", 'accept': "text/html" } querystring = {"defaultCss":"true", "showBacklink":"false"} recipe_info['inregdientsWidget'] = requests.request("GET", url + ingedientsWidget, headers=recipe_headers, params=querystring).text recipe_info['equipmentWidget'] = requests.request("GET", url + equipmentWidget, headers=recipe_headers, params=querystring).text return render_template('recipe.html', recipe=recipe_info)
Here you’ll see some interesting new lines of code.
First, let’s execute three requests, instead of one.
Second, we will create sub-headers to satisfy the accept header requirements for the content type.
Finally, we will include a default CSS for the widget integration.
Create a recipe.html template and paste the following snippet:
{% extends 'base.html' %} {% block title %} {{recipe['title']}} {% endblock %} {% block body %} <div style="max-width: 70%; margin: auto; padding-top:3%"> <div class="media"> <img src="{{recipe['image']}}" class="mr-3" alt="..." width="20%" height="20%"> <div class="media-body"> <h5 class="mt-0">{{recipe['title']}}</h5> {{recipe['instructions']}} </div> </div><br> {{recipe['inregdientsWidget'] | safe }}<br> {{recipe['equipmentWidget'] | safe}} </div> {% endblock %}
Voila! The app is completed.
Of course, it isn’t ideal yet, but even now it has many interesting aspects to surf.
The most important thing: “| safe” keyword.
This code indicates HTML markup, so all tags and scripts will be executed. Rerun your project and visit some recipe pages.
Today we have introduced the Spoonacular API.
It is a powerful and multi-functional solution for food nutrition.
We created a visible and robust web application.
The basis of this app was made via RapidAPI endpoints.
Our project can propose fresh recipes depending on the contents of your fridge.
We're thrilled to announce the latest update to the Rapid Enterprise API Hub (version 2024.3)!…
Are you curious about what your API consumers are searching for? Is your Hub effectively…
The RapidAPI team is excited to announce the February 2024 update (version 2024.2) for the…
This January's release brings exciting features and improvements designed to empower you and your developers.…
Rapid API is committed to providing its users with the best possible experience, and the…
In today's fast-paced digital world, APIs (Application Programming Interfaces) have become the backbone of modern…
View Comments
Hi,
does it work the same way for Wagtail ? I mean the way to install the API :)
Have a good day :)
Looks good! Is there a basic folder with all the files to make this usable on a localhost...no way for me to code such a use of an api; plus I can't afford for someone to write such code.
This post is really amazing and very informative
your blog inspiration for beginners
Thank for sharing your knowledge