Demo Application
Learn how to build a fully functional React application using the Spoonacular API.
We'll cover the following
This lesson will walks us through a React application integrated with the Spoonacular API. The following endpoints have been used in the application:
- search recipes endpoint
- similar recipes endpoint
- recipe information endpoint
- search ingredients endpoint
- fetch ingredient endpoint
- ingredient substitute by ID endpoint
- search products by query string endpoint
- search products by ingredients endpoint
- product information endpoint
- widget endpoints
Application workflow
This demo application is a food application that provides data on recipes, ingredients, and products as interactive elements. The workflow of the application is as follows:
When we run the application, the landing page is the search page for recipes. There are also similar search pages for ingredients and products. The search results on these pages can be further modified using the provided filters.
The corresponding recipe, ingredient, or product page is opened by clicking any card. Here’s the workflow of each of these pages.
On the specific recipe page, click the “Expand Instructions” button to open the slide set for step-by-step recipe instructions. Use the dropdown menu under the “Recipe Attributes” section to switch between widgets. Finally, we find a list of similar recipes at the very end.
On the specific ingredient page, enter the quantity of the ingredient and click the “Update” button to update the price of the ingredient on the page accordingly. Finally, we find a list of grocery products that contain the specified ingredient.
On the specific product page, there is detailed information about the product. Use the dropdown menu under the “Product Attributes” section to switch between widgets.
Run the application
We can run the demo application by pressing the “Run” button in the widget below. When the React development server starts, click the URL next to “Your app can be found at:” to view the application.
Note: The following widget only shows the files required to explain the Spoonacular API.
import fetch from 'node-fetch'; import express from 'express'; import cors from 'cors'; const app = express(); app.use(cors()); const port = process.env.PORT || 3000; // Function to make a simple API call const makeApiCall = async (apiURL, apiOptions) => { try { // console.log(apiOptions); const options = JSON.parse(apiOptions); const response = await fetch(apiURL, options); console.log(response); return response; } catch (err) { console.error(err); return null; } }; app.all('/', async function(req, res, next) { try { const resObj=await makeApiCall(req.query.apiURL, req.query.apiOptions); if (!resObj) { res.status(404).send({'message': 'Failed API server no reachable'}); } else { const content = await resObj.text(); res.status(resObj.status).send(content); } } catch (err) { res.status(404).send({'message': `API server not reachable ${err}`}); } next(); }); app.listen(port); console.log(`Server started at http://localhost:${port}`);
Code explanation
Let’s dive into the code and see how we’ve integrated different Spoonacular API endpoints into our React application.
To handle CORS for our front-end application, we use a proxy server. We can find the code for it under the backend-server
folder. The server takes the endpoint URL and uses fetch
options as query parameters from the front-end application. The server also makes the API call to Spoonacular and returns the relevant response.
For our React application, the file index.jsx
renders the App
component (App.jsx
) as the root component. Here’s a brief explanation of the App
component:
Line 22: We extract the API key stored in the
keys.json
file and then assign it to theapiKey
variable, which is then passed ahead as aprop
.Lines 29–36: We set the routes for our application here and pass
apiKey
as aprop
to all relevant pages making an API call.Line 29: We set the home page of our application to the recipes page by redirecting to it when the website path is
{EDUCATIVE_APP_URL}/
.
Note: We have created and used a custom hook,
useFetch
, to fetch the data from any API endpoint. To avoid any CORS-related issues, we use a custom proxy server to make API calls.
The general recipes page is rendered by the Recipes
component (Recipes.jsx
), which displays a search bar and a list of recipes. Here’s a brief explanation of the Recipes
component:
Lines 48–56: We define the header parameters and
options
object to make GET requests with a JSON response.Lines 59–78: We declare the query parameters and URL for the search recipes endpoint, which we call using our custom
useFetch
hook.
The general ingredients page is rendered by the Ingredients
component (Ingredients.jsx
), which displays a search bar and a list of ingredients. Here's a brief explanation of the Ingredients
component:
Lines 42–50: We define the header parameters and
options
object to make GET requests with a JSON response.Lines 53–69: We declare the query parameters and URL for the search ingredients endpoint, which we call using our custom
useFetch
hook.
The general products page is rendered by the Products
component (Products.jsx
), which displays a search bar and a list of products. Here’s a brief explanation of the Products
component:
Lines 35–43: We define the header parameters and
options
object to make GET requests with a JSON response.Lines 46–59: We declare the query parameters and URL for the search products by query string endpoint, which we call using our custom
useFetch
hook.
A specific recipes page is rendered by the RecipePage
component (RecipePage.jsx
), which displays details about the recipe and the recipe widgets. Here’s a brief explanation of the RecipePage
component:
Lines 76–84: We define the header parameters and
options
object to make GET requests with a JSON response.Lines 85–93: We define the header parameters and
options
object to make GET requests with an HTML response.Lines 96–103: We declare the query parameters and URL for the recipe information endpoint, which we call using our custom
useFetch
hook.Lines 106–117: We declare the query parameters and URL for the similar recipes endpoint, which we call using our custom
useFetch
hook.Lines 120–131: We declare the query parameters and URL for the recipe nutrition by ID widget endpoint, which we call using our custom
useFetch
hook. Using a dropdown menu, we can change this URL to automatically fetch the HTML data for other recipe widgets and display them.
A specific ingredient page is rendered by the IngredientPage
component (IngredientPage.jsx
), which displays details about the ingredient and suggests any product with the specified ingredient in it. Here’s a brief explanation of the IngredientPage
component:
Lines 30–38: We define the header parameters and
options
object to make GET requests with a JSON response.Lines 41–50: We declare the URL for the ingredient information endpoint, which we call using our custom
useFetch
hook.Lines 53–63: We declare the query parameters and URL for the ingredient substitute by ID endpoint, which we call using our custom
useFetch
hook.
The ProductSuggestions
component (ProductSuggestions.jsx
), a child component of the IngredientPage
, displays product suggestions on a specific ingredient page rather than a separate page. Here’s a brief explanation of the ProductSuggestions
component:
Lines 12–27: We define the header parameters, body parameters, and
options
object to make POST requests with a JSON response.Lines 28–36: We declare the URL for the search products by ingredients endpoint, which we call using our custom
useFetch
hook.
The ProductLoadingCard
component (ProductLoadingCard.jsx
), a child component of ProductSuggestions
, displays a detailed product card after fetching the associated product’s information. Here’s a brief explanation of the ProductLoadingCard
component:
Lines 17–25: We define the header parameters, body parameter, and
options
object to make POST requests with a JSON response.Lines 28–36: We declare the URL for the product information endpoint, which we call using our custom
useFetch
hook.
A specific product page is rendered by the ProductPage
component (ProductPage.jsx
), which displays details about the product and the product widgets. Here’s a brief explanation of the ProductPage
component:
Lines 44–52: We define the header parameters and
options
object to make GET requests with a JSON response.Lines 53–61: We define the header parameters and
options
object to make GET requests with an HTML response.Lines 64–72: We declare the URL for the product information endpoint, which we call using our custom
useFetch
hook.Lines 75–86: We declare the query parameters and URL for the product nutrition by ID widget endpoint, which we call using our custom
useFetch
hook. Using a dropdown menu, we can change this URL to automatically fetch the HTML data for other product widgets and display them.