A step-by-step guide on how to create custom API endpoints with strapi
Published: 2023-08-16 00:29:44



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pw0fk2e7a051n9nlbwv7.png)

## How to Create a Custom API Endpoint in Strapi?
Strapi offers a collection of potent APIs that enable programmers to design unique API endpoints. We'll be building a custom API endpoint from scratch in this article.

## Prerequisites
Before you can jump into this content, you need to have the following:

1. Basic knowledge of JavaScript
2. Basic understanding of Strapi - [get started here] (https://strapi.io/documentation/developer-docs/latest/getting-started/introduction.html)

## Installing Strapi
The following command will install a new Strapi instance with some preset configurations and data.

```
npx create-strapi-app plugins-v4-1 --template corporate
```

Please, [See the create-strapi-app node package page to learn about the various Strapi installation options.](https://www.npmjs.com/package/create-strapi-app)

You must select Custom as the installation type if you are using the --template corporate flag. Set the default database to sqlite.

```
    ? Choose your installation type Custom (manual settings)
    ? Choose your default database client sqlite
    ? Filename: .tmp/data.db
```
Ensure that the current directory in the terminal is the project directory. Fire up the development server.

```
cd plugins-v4-1/
yarn develop --watch-admin
```
The front-end development server and autoReload are both enabled when the application is started using the --watch-admin flag. It enables programmers to alter the administrative panel.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c48l43p1u6t29ldt4s97.png)

The browser automatically creates a new tab after the installation is finished. Visit `http://localhost:8000/admin/ ` if you need to.

In the event that port `8000` is already in use by another process, please verify the alternative port listed in the CLI output. Typically, the value would be `8080`.

Fill out the form to add the application's initial administrator user.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gsrbfk08fhwnolcjbjyk.png)

The front-end development server and autoReload are both enabled when the application is started using the --watch-admin flag. It enables programmers to alter the administrative panel.

The corporate template automatically creates a single type, a collection of types, and components.

Components:
 - User
 - Page
 - Lead From submission

Single Types:
 - Global

Components:
A lot of components for Elements, Layout, Links, Meta, and Sections. The template also provides us with some pre-filled data to play around with. All of these happen just by providing the `--template corporate` flag at the time of Strapi installation.

## Setting-up a Use Case
We have a pre-populated collection-type page with some information.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9zoa7iqk8utvaps0xsxu.png)

Strapi delivers the entire page, filled with all of its components and dynamic-zone component data, in response to a get request to `http://localhost:1337/api/pages?populate=*`.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wxkbyo92mif9y71gwi1x.png)

In order to offer a condensed summary of the pages, a custom API Endpoint GET `/api/pages-report` must be created.

```
[
      { "id": 1, "name": "Home", "metaTitle": "Strapi corporate site starter" },
      { "id": 2, "name": "Pricingg", "metaTitle": "Pricing" },
      { "id": 3, "name": "Secret", "metaTitle": "Secret page" },
      { "id": 4, "name": "Contact", "metaTitle": "Contact" }
    ]
```
Exactly this is what we are going to construct in this post.

## Generating a Basic API
A CLI session that is interactive is launched by the `npx strapi generate` command. If your system has yarn and `strapi` installed globally, you are welcome to use `yarn` in place of the `npx` command.

You can choose from the choices listed below. Please take note of the word "report" in the name of our API pages.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3c2jxb77jnt7vh1oqgfq.png)

Within the `src/api` directory, this command creates a directory called pages-reports. `Controllers`, `routes` , and `services` are three directories that are part of the `pages-report`.

## Routes
Routes manage requests sent to Strapi on any URL. According to the [REST API specification](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/rest-api.html), Strapi automatically constructs [routes](https://docs.strapi.io/developer-docs/latest/development/backend-customization/routes.html#implementation) for every content type. It is possible to add and configure routes. Once a route is established, using it causes a controller to run some logic.

The following lines of code should be added to `src/api/pages-report/routes/pages-report.js`.

```
module.exports = {
      routes: [
        {
         method: 'GET',
         path: '/pages-report',
         handler: 'pages-report.findAll',
         config: {
           policies: [],
           middlewares: [],
         },
        },
      ],
    };
```
## Controllers vs Services
A collection of methods called actions are contained in controllers, which are JavaScript files that are accessed by the client in accordance with the desired [route](https://docs.strapi.io/developer-docs/latest/development/backend-customization/routes.html). The action executes the business logic code and provides the [response](https://docs.strapi.io/developer-docs/latest/development/backend-customization/requests-responses.html#responses) whenever a client requests the route. The C in the model-view-controller (MVC) pattern is represented by the [controller](https://docs.strapi.io/developer-docs/latest/development/backend-customization/services.html). Most of a project's business logic will be found in the [controllers](https://strapi.gitee.io/documentation/v3.x/concepts/controllers.html). However, when a controller's logic grows more intricate, it's a good idea to use services to divide the code into sections that can be reused.

A set of reusable operations make up services. They are very helpful for simplifying controller logic and adhering to the DRY (don't repeat yourself) programming principle.

## Creating a Service
Services essentially don't know about the request and response ctx objects of Koa. It is planned for this function to be adaptable and reusable.

Replace the following lines of code in `/src/api/pages-report/services/pages-report.js`:

```
'use strict';

    module.exports = {
      pagesReport: async () => {
        try {
          // fetching the data
          // we dont really need contentSections for this example.
          // its kept here, just for your reference
          const entries = await strapi.entityService.findMany('api::page.page', {
            fields: ['id', 'shortName'],
            populate: {
              metadata: {
                fields: ['metaTitle']
              },
              contentSections: {
                populate: '*'
              }
            }
          });

          // reducing the data to a simple array
          let entriesReduced;
          if (entries && Array.isArray(entries)) {
            entriesReduced = entries.reduce((acc, item) => {
              acc = acc || [];
              console.log(acc);
              acc.push({
                id: item.id,
                name: item.shortName || '',
                metaTitle: item.metadata?.metaTitle || ''
              });
              return acc;
            }, [])

            // returning the reduced data
            return entriesReduced;
          }
        } catch (err) {
          return err;
        }
      }
    }
```
To fetch all pages, we are using the [Entity Service API](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/entity-service-api.html) for Strapi in this code. Read the documentation for the [Populating the Entity Service API](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/entity-service/populate.html#advanced-populating) to find out more about the flexible ways to populate the response.

The following data will be returned by the pagesReport service:

```
 [
      { "id": 1, "name": "Home", "metaTitle": "Strapi corporate site starter" },
      { "id": 2, "name": "Pricingg", "metaTitle": "Pricing" },
      { "id": 3, "name": "Secret", "metaTitle": "Secret page" },
      { "id": 4, "name": "Contact", "metaTitle": "Contact" }
    ]
```
Once a service is created, it's accessible from controllers or from other services:

```
  // access an API service
    strapi.service('api::apiName.serviceName');
    // access a plugin service
    strapi.service('plugin::pluginName.serviceName');
```
Controllers and services can log the list of available services:

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

## Creating a Controller
A controller function is in charge of invoking our service upon request and returning the results to the `response` because it has direct access to the Koa's ctx.

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

```
  'use strict';

    module.exports = {
      async findAll(ctx, next) {
        try {
          const data = await strapi.service('api::pages-report.pages-report').pagesReport();
          ctx.body = data;
        } catch (err) {
          ctx.badRequest('Page report controller error', { moreDetails: err })
        }
      }
    };
```

## Setting Permissions for the API
For the use case, it is all the code that is needed. `/api/pages-report `should receive a get request. A 403 error will most likely appear.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vcuh4fex308b2qfrj84h.png)

Please navigate to Setting > Roles > Public on the Strapi dashboard to enable public access to the end-point. Please review the results for the pages-report route before pressing the save button.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0g9073ztpgmtacxedh5d.png)

Currently, the public can use the customised API:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w7r5y75d91nkldmuhyg4.png)

To obtain and filter the results for this article, we made use of Strapi's [Entity Service API](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/entity-service-api.html). It's not the only method available to complete this assignment. Using the Rest API, [Query Engine API](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/query-engine-api.html), and GraphQL API, users of Strapi can fetch and filter results.

The layer that manages Strapi's intricate data structures, such as [components](https://docs.strapi.io/developer-docs/latest/development/backend-customization/models.html#components) and [dynamic zones](https://docs.strapi.io/developer-docs/latest/development/backend-customization/models.html#dynamic-zones), leverages the Query Engine API to power database operations. It is therefore a logical option for this use scenario. Using the [filtering](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/entity-service/filter.html#logical-operators) and [advanced](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/entity-service/populate.html#advanced-populating) population techniques of the Entity Service API, we can adapt our example to meet our needs.