Using the Strapi API Endpoints
Learn how to consume the API endpoints that Strapi creates with each collection.
Overview
Now that we know how to create content-types and content using the Strapi admin panel, it’s time we start using those content types in our frontend so our users can interact with our application. In this lesson, we’ll first learn about automatically generated endpoints and the permissions required to access those endpoints.
Automatically generated endpoints
Whenever we create a collection type in our Content-type Builder, Strapi automatically generates a folder in our source code with the name of that collection. This folder is created in the /api
folder—which is already present in the code—and it contains four subfolders: content-types
, routes
, controllers
, and services
. Let’s get into some more details about the content and purpose of these folders.
Please use the following widget to locate the files that we’ll discuss in this lesson:
'use strict'; module.exports = { /** * An asynchronous register function that runs before * your application is initialized. * * This gives you an opportunity to extend the code. */ register(/*{ strapi }*/) {}, /** * An asynchronous bootstrap function that runs before * your application gets started. * * This gives you an opportunity to set up your data model, * run jobs, or perform some special logic. */ bootstrap(/*{ strapi }*/) {}, };
The content-types
folder
This folder contains the schema of the content-type in a .json
file. This is all the information Strapi requires about the content that will be saved in this content-type. The file is at the path: /src/api/content-types/recipe/schema.json
.
Once the content-type has been created, we can also make edits to our schema from this file without having to use the Strapi admin panel. This is what a schema.json
file looks like:
{"kind": "collectionType","collectionName": "recipes","info": {"singularName": "recipe","pluralName": "recipes","displayName": "Recipe"},"options": {"draftAndPublish": true},"pluginOptions": {},"attributes": {"strMeal": {"type": "string"},"strThumb": {"type": "string"},"strArea": {"type": "string"},"strCategory": {"type": "string"},"strInstructions": {"type": "text"},"strTags": {"type": "string"},"strIngredient1": {"type": "string"},"strIngredient2": {"type": "string"},"strIngredient3": {"type": "string"},"strIngredient4": {"type": "string"},"strIngredient5": {"type": "string"},"strIngredient6": {"type": "string"},"strIngredient7": {"type": "string"},"strIngredient8": {"type": "string"},"strIngredient9": {"type": "string"},"strIngredient10": {"type": "string"},"strIngredient11": {"type": "string"},"strIngredient12": {"type": "string"},"strIngredient13": {"type": "string"},"strIngredient14": {"type": "string"},"strIngredient15": {"type": "string"},"strIngredient16": {"type": "string"},"strIngredient17": {"type": "string"},"strIngredient18": {"type": "string"},"strIngredient19": {"type": "string"},"strIngredient20": {"type": "string"},"strMeasure1": {"type": "string"},"strMeasure2": {"type": "string"},"strMeasure3": {"type": "string"},"strMeasure4": {"type": "string"},"strMeasure5": {"type": "string"},"strMeasure6": {"type": "string"},"strMeasure7": {"type": "string"},"strMeasure8": {"type": "string"},"strMeasure9": {"type": "string"},"strMeasure10": {"type": "string"},"strMeasure11": {"type": "string"},"strMeasure12": {"type": "string"},"strMeasure13": {"type": "string"},"strMeasure14": {"type": "string"},"strMeasure15": {"type": "string"},"strMeasure16": {"type": "string"},"strMeasure17": {"type": "string"},"strMeasure18": {"type": "string"},"strMeasure19": {"type": "string"},"strMeasure20": {"type": "string"},"idMeal": {"type": "integer","unique": true,"required": true}}}
The routes
folder
This folder contains all the route files. By default, it only has one file, :singularApiId.js
. This is what the file looks like:
'use strict';/*** recipe router*/const { createCoreRouter } = require('@strapi/strapi').factories;module.exports = createCoreRouter('api::recipe.recipe');
In line 7 of the file, Strapi uses the factories
function of its package to create the core routes. With this function, we can pass configuration options to the default routes. We can also disable routes in case we need to use custom routes instead of the core ones.
In line 9, they are exported so we can use them. The createCoreRouter
is returned from the factories
method and contains the default routes. Let’s take a quick look at the core routes of the API:
find
: This is aGET
route with the path/api/:pluralApiId
. It gets all the entries of the collection.findOne
: This is also aGET
route, but its path is/api/:pluralApiId/:id
. It gets the entry that has the ID mentioned in the route. For example, a request toapi/tests/1
returns the entry withid=1
ornull
(if the entry doesn’t exist).create
: This is aPOST
route with the path/api/:pluralApiId
. It creates a new entry in the collection.update
: This is aPUT
route with the path/api/:pluralApiId/:id
. It updates the entry that has the ID mentioned in the route.delete
: This is aDELETE
route with the path/api/:pluralApiId/:id
. It deletes the entry that has the ID mentioned in the route.
These are the five basic REST API routes that the Strapi application creates. We can disable these basic routes as well as add custom ones in order to create our custom functionality.
The controllers
folder
This folder contains our controller file named :singularApiId.js
. It looks very similar to the route files, with the one difference being that it uses createCoreController
function and not the createCoreRouter
function. This is what the file looks like:
'use strict';/*** recipe controller*/const { createCoreController } = require('@strapi/strapi').factories;module.exports = createCoreController('api::recipe.recipe');
This file contains the set of functions that are called when a route is accessed. Each route is assigned to a controller function, which are called actions. The logic that the route is meant to perform for the user is present here. The action is also responsible for generating an appropriate response for the route.
The createCoreController
function automatically generates actions for the automatically generated routes. It also allows us to create new controllers as well as extend or replace the default-generated controllers.
The services
folder
The purpose of the services
folder is to help developers have an easy-to-maintain codebase. The /services/:singularApiId
file is home to reusable functions that are being used in controllers. The file looks like this:
'use strict';/*** recipe service*/const { createCoreService } = require('@strapi/strapi').factories;module.exports = createCoreService('api::recipe.recipe');
The createCoreService
function contains all the services that are used by the created controllers.
Now that we know about the default API endpoints that Strapi automatically generates for us, we can easily use them in our applications. However, we also need to allow access to these endpoints.
Allowing access to endpoints
The access rights to the API can be changed from the “Settings” panel of the Strapi Dashboard. The “Settings” can be accessed from the main navigation bar on the left side of the admin panel screen. Here is how we can change access to the application’s API:
Click the “Settings” button at the bottom of the navigation menu.
Click the “Roles” option under the “Users and Permissions Plugin” section in the subnavigation of “Settings.”
Click the the “Edit” icon of the “Public” or the “Authenticated” role, depending on the requirements.
Select all the routes that are required for the application.
With these steps, our application’s endpoints will become accessible to the user. We can test out the find
and findOne
routes in a browser because they’re GET
methods.
Creating custom routes
First, let’s discuss why we need custom routes in our application. The frontend of the application that we have created in the previous section uses TheMealDB API. That API uses the idMeal
field as its unique identifier, and we need to do the same here. Let’s use the code widget below to discuss how to do that:
Note: A Strapi administrator user has already been created for this course. The details of the user are as follows:
Email: jane.doe@email.com
Password: Password123
'use strict'; module.exports = { /** * An asynchronous register function that runs before * your application is initialized. * * This gives you an opportunity to extend code. */ register(/*{ strapi }*/) {}, /** * An asynchronous bootstrap function that runs before * your application gets started. * * This gives you an opportunity to set up your data model, * run jobs, or perform some special logic. */ bootstrap(/*{ strapi }*/) {}, };
In the code above, we’re making some changes to make our application compatible with TheMealDB API that we’re using in our application. Let’s take a look at those files:
The
/src/api/recipe/routes/custom.js
file: Here, we create a custom route for our Recipe content-type. We require this because our TheMealDB API usesidMeal
as the unique identifier, but Strapi defaults to theid
field; therefore, we need to override theid
field with theidMeal
field. This route will only be used to find meals using theidMeal
field, not theid
field.The
/src/api/recipe/controllers/recipe.js
file: This field is home to our default controllers, but we can also override thefindOne
controller to makeidMeal
our unique identifier. We create a newfindOne
function in this file, which will be the handler for our/recipe/:idMeal
route that we created in the/src/api/recipe/routes/custom.js
file.