Simply copy and paste the following command line in your terminal to create your first Strapi project.
npx create-strapi-app
my-project
Strapi provides a set of powerful APIs to let the developers create custom API end-points. In this article, we will be learning about Strapi Customization by creating a Strapi custom API endpoint from scratch.
Before you can jump into this content, you need to have the following:
The following command will install a new Strapi instance with some ready-made configurations and data.
npx create-strapi-app plugins-v4-1 --template corporate
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 Strapi 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": "daviddoe@strapi.io"
},
{
"id": 2,
"title": "This shrimp is awesome",
"category": "nature",
"publishedDate": "Fri May 20 2022",
"authorName": "David Doe",
"authorEmail": "daviddoe@strapi.io"
},
{
"id": 3,
"title": "A bug is becoming a meme on the internet",
"category": "tech",
"publishedDate": "Fri May 20 2022",
"authorName": "Sarah Baker",
"authorEmail": "sarahbaker@strapi.io"
},
{
"id": 4,
"title": "Beautiful picture",
"category": "nature",
"publishedDate": "Fri May 20 2022",
"authorName": "Sarah Baker",
"authorEmail": "sarahbaker@strapi.io"
},
{
"id": 5,
"title": "What's inside a Black Hole",
"category": "news",
"publishedDate": "Fri May 20 2022",
"authorName": "Sarah Baker",
"authorEmail": "sarahbaker@strapi.io"
}
]
As seen above, we can make requests to the Strapi custom endpoint.
The npx strapi generate
command starts an interactive CLI session. In case you have yarn
and strapi
installed globally in your system, feel free to replace the npx
command with yarn
.
The following options may be selected. Please, notice that we have named our API posts-report
.
Navigate to your demoapp
folder and run npx strapi generate
to create a custom Strapi 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
.
Requests sent to the Strapi API URL or Strapi custom endpoint are handled by routes. By default, Strapi generates routes for all the content-types (see REST API documentation). 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 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.
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'));
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 demoapp
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.
In this article, we have learned about Strapi Customization by creating a Strapi custom API endpoint from scratch.
We used Strapi’s Entity Service API to fetch and filter the results. It’s not the only way to accomplish this task. In Strapi, the fetching and filtering of results can be done using Rest API, Query Engine API, and GraphQL API as well.
The Entity Service is the layer that handles Strapi's complex data structures like components and dynamic zones and uses the Query Engine API under the hood to execute database queries. This makes it a reasonable choice for this use case. Our example can be made as flexible as we need using the filtering & advanced population techniques of the Entity Service API.
You can go to this Git Repository and check the readme file for complete guide. Let me know if you have any suggestions and what you will be building with the knowledge.
When I’m not working, I love to write, learn something new & read non-fiction.