How to Create a Custom API Endpoint in Strapi

  1. Installing Strapi
  2. Generating a Basic API
  3. Routes
  4. Controllers vs Services
  5. Creating a Service
  6. Creating a Controller
  7. Setting Permissions for the API

In this article, we will be creating a custom API endpoint from scratch.

Installing Strapi

To create a new Strapi project based on a template, run the following command:

1
2
3
4
5
# use yarn
yarn create strapi-app my-project --template <template-package>

# use npm
npx create-strapi-app@latest my-project --template <template-package>

For example:

1
2
3
4
5
# use the full template name
yarn create strapi-app my-project --template @strapi/template-blog

# use the shorthand
yarn create strapi-app my-project --template blog

Once the installation is complete, the browser automatically opens a new tab. If not, navigate to http://localhost:1337/admin/.

If port is already used by an another process, please check the alternate port mentioned mentioned in the CLI output. Most of the time, it would be 8000 , 8080 or 1337.

Complete the form to create the first administrator user of this Strapi application.

The blog template generates components, collection types, and a single type out of the box.

In this example, we show you how to create a custom API Endpoint GET /api/posts-report which will provide a simplified report of collection type article.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
[
{
"id": 1,
"title": "The internet's Own boy",
"category": "story",
"publishedDate": "Fri May 20 2022",
"authorName": "David Doe",
"authorEmail": "[email protected]"
},
{
"id": 2,
"title": "This shrimp is awesome",
"category": "nature",
"publishedDate": "Fri May 20 2022",
"authorName": "David Doe",
"authorEmail": "[email protected]"
},
{
"id": 3,
"title": "A bug is becoming a meme on the internet",
"category": "tech",
"publishedDate": "Fri May 20 2022",
"authorName": "Sarah Baker",
"authorEmail": "[email protected]"
},
{
"id": 4,
"title": "Beautiful picture",
"category": "nature",
"publishedDate": "Fri May 20 2022",
"authorName": "Sarah Baker",
"authorEmail": "[email protected]"
},
{
"id": 5,
"title": "What's inside a Black Hole",
"category": "news",
"publishedDate": "Fri May 20 2022",
"authorName": "Sarah Baker",
"authorEmail": "[email protected]"
}
]

Generating a Basic API

Navigate to your my-project folder and run npx strapi generate to create a custom API endpoint.

1
2
3
4
5
6
7
8
? Strapi Generators (Use arrow keys)
❯ api - Generate a basic API
controller - Generate a controller for an API
content-type - Generate a content type for an API
plugin - Generate a basic plugin
policy - Generate a policy for an API
middleware - Generate a middleware for an API
service - Generate a service for an API

Make sure the api option is selected and click enter.

1
2
? Strapi Generators api - Generate a basic API 
? API name // name your api

I am going to call my posts-report and select N for “Is this API for a plugin?”

1
2
3
? Strapi Generators api - Generate a basic API 
? API name posts-report
? Is this API for a plugin? (Y/n)

This will generate these files below

1
2
3
4
5
6
7
? Strapi Generators api - Generate a basic API
? API name posts-report
? Is this API for a plugin? No

✔ ++ /api/posts-report/routes/posts-report.js
✔ ++ /api/posts-report/controllers/posts-report.js
✔ ++ /api/posts-report/services/posts-report.js

We can find these in the /src/api/posts-report folder.
This command creates a directory called posts-report within src/api directory. The posts-report contains three directories called controllers, routes, and services.

Routes

Requests sent to Strapi on any URL are handled by routes. By default, Strapi generates routes for all the content-types. Routes can be added and configured. Once a route exists, reaching it executes some code handled by a controller.

Replace the code in /src/api/posts-report/routes/posts-report.js with the following lines of code.

1
2
3
4
5
6
7
8
9
10
11
12
13
module.exports = {
routes: [
{
method: "GET",
path: "/posts-report",
handler: "posts-report.postsReport",
config: {
policies: [],
middlewares: [],
},
},
],
};

Controllers vs Services

Controllers are JavaScript files that contain a set of methods called actions, reached by the client according to the requested route. Whenever a client requests the route, the action performs the business logic code and sends back the response. Controllers represent the C in the model-view-controller (MVC) pattern. In most cases, the controllers will contain the bulk of a project’s business logic. But as a controller’s logic becomes more and more complicated, it’s a good practice to use services to organise the code into re-usable parts.

Services are a set of reusable functions. They are particularly useful to respect the DRY (don’t repeat yourself) programming concept and to simplify controllers logic.

Creating a Service

Services are basically not aware of the Koa’s ctx object(request and the response). It is supposed to be a flexible and reusable function.

Replace the contents of /src/api/posts-report/services/posts-report.js with the following lines of code that use Strapi’s Entity Service API to fetch all pages:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
module.exports = {
postsReport: async () => {
try {
// fetching data
const entries = await strapi.entityService.findMany(
"api::article.article",
{
fields: ["id", "title", "slug", "createdAt"],
populate: {
author: {
fields: ["name", "email"],
},
category: {
fields: ["name"],
},
},
}
);

// reduce the data to the format we want to return
let entriesReduced;
if (entries && Array.isArray(entries)) {
entriesReduced = entries.reduce((acc, item) => {
acc = acc || [];
acc.push({
id: item.id,
title: item.title || "",
category: item.category.name || "",
publishedDate: new Date(item.createdAt).toDateString() || "",
authorName: item.author?.name || "",
authorEmail: item.author?.email || "",
});
return acc;
}, []);
}

// return the reduced data
return entriesReduced;
} catch (err) {
return err;
}
},
};

In this code we are using Strapi’s Entity Service API to fetch all pages. To learn more about the flexible ways of populating the response, read the Populating the Entity Service API documentation.

Once a service is created, it’s accessible from controllers or from other services:

1
2
3
4
// access an API service
strapi.service('api::apiName.serviceName');
// access a plugin service
strapi.service('plugin::pluginName.serviceName');

The list of services available can be logged from controllers and services:

1
2
console.log('strapi.services ', strapi.services);
console.log('pages-report', strapi.service('api::pages-report.pages-report'));

Creating a Controller

Controllers are functions that have direct access to the Koa’s ctx, hence a controller function is responsible for invoking our service on request and returning the results to the response.

Replace the code in /src/api/posts-report/controllers/posts-report.js with the following lines of code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
module.exports = {
async postsReport(ctx, next) {
try {
const data = await strapi
.service("api::posts-report.posts-report")
.postsReport();
console.log(data, "data");

ctx.body = data;
} catch (err) {
ctx.badRequest("Post report controller error", { moreDetails: err });
}
},
};

You may need to stop and re-start the server. Stop the server using ctrl + c in the terminal. Start the server using yarn develop. Make sure that your current directory is my-project.

Setting Permissions for the API

That’s all the code required for the use case. Send a get request to /api/posts-report. You will most probably get a 403 error.

In order to make the end-point accessible only to the authenticated users, go to the Settings > Roles > Authenticated. To be able to publicly access the end-point, please go to the Setting > Roles > Public in the Strapi dashboard.

Please, check the postsReport for the Posts-report route and hit the save button.

Now, the custom API is ready for the public:

You can either just go here directly in your browser http://localhost:1337/api/posts-report or make a GET request using a service like postman or insomnia.

You should now see your data coming from your custom controller.

Source: https://strapi.io/blog/how-to-create-a-custom-api-endpoint-in-strapi