<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Igbinoba Ebenezer</title>
    <description>The latest articles on DEV Community by Igbinoba Ebenezer (@eben4real).</description>
    <link>https://dev.to/eben4real</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1139767%2F62192c98-7e87-4d3e-ab0a-f5153b1040c4.jpeg</url>
      <title>DEV Community: Igbinoba Ebenezer</title>
      <link>https://dev.to/eben4real</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/eben4real"/>
    <language>en</language>
    <item>
      <title>A step-by-step guide on how to create custom API endpoints with strapi</title>
      <dc:creator>Igbinoba Ebenezer</dc:creator>
      <pubDate>Wed, 16 Aug 2023 00:29:44 +0000</pubDate>
      <link>https://dev.to/eben4real/a-step-by-step-guide-on-how-to-get-started-with-strapi-1gkg</link>
      <guid>https://dev.to/eben4real/a-step-by-step-guide-on-how-to-get-started-with-strapi-1gkg</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpw0fk2e7a051n9nlbwv7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpw0fk2e7a051n9nlbwv7.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Create a Custom API Endpoint in Strapi?
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before you can jump into this content, you need to have the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Basic knowledge of JavaScript&lt;/li&gt;
&lt;li&gt;Basic understanding of Strapi - &lt;a href="https://strapi.io/documentation/developer-docs/latest/getting-started/introduction.html" rel="noopener noreferrer"&gt;get started here&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Installing Strapi
&lt;/h2&gt;

&lt;p&gt;The following command will install a new Strapi instance with some preset configurations and data.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

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


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Please, &lt;a href="https://www.npmjs.com/package/create-strapi-app" rel="noopener noreferrer"&gt;See the create-strapi-app node package page to learn about the various Strapi installation options.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You must select Custom as the installation type if you are using the --template corporate flag. Set the default database to sqlite.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

    ? Choose your installation type Custom (manual settings)
    ? Choose your default database client sqlite
    ? Filename: .tmp/data.db


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Ensure that the current directory in the terminal is the project directory. Fire up the development server.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

cd plugins-v4-1/
yarn develop --watch-admin


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc48l43p1u6t29ldt4s97.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc48l43p1u6t29ldt4s97.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The browser automatically creates a new tab after the installation is finished. Visit &lt;code&gt;http://localhost:8000/admin/&lt;/code&gt; if you need to.&lt;/p&gt;

&lt;p&gt;In the event that port &lt;code&gt;8000&lt;/code&gt; is already in use by another process, please verify the alternative port listed in the CLI output. Typically, the value would be &lt;code&gt;8080&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Fill out the form to add the application's initial administrator user.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgsrbfk08fhwnolcjbjyk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgsrbfk08fhwnolcjbjyk.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;The corporate template automatically creates a single type, a collection of types, and components.&lt;/p&gt;

&lt;p&gt;Components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User&lt;/li&gt;
&lt;li&gt;Page&lt;/li&gt;
&lt;li&gt;Lead From submission&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Single Types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Global&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Components:&lt;br&gt;
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 &lt;code&gt;--template corporate&lt;/code&gt; flag at the time of Strapi installation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting-up a Use Case
&lt;/h2&gt;

&lt;p&gt;We have a pre-populated collection-type page with some information.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9zoa7iqk8utvaps0xsxu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9zoa7iqk8utvaps0xsxu.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwxkbyo92mif9y71gwi1x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwxkbyo92mif9y71gwi1x.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In order to offer a condensed summary of the pages, a custom API Endpoint GET &lt;code&gt;/api/pages-report&lt;/code&gt; must be created.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

[
      { "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" }
    ]


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Exactly this is what we are going to construct in this post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generating a Basic API
&lt;/h2&gt;

&lt;p&gt;A CLI session that is interactive is launched by the &lt;code&gt;npx strapi generate&lt;/code&gt; command. If your system has yarn and &lt;code&gt;strapi&lt;/code&gt; installed globally, you are welcome to use &lt;code&gt;yarn&lt;/code&gt; in place of the &lt;code&gt;npx&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;You can choose from the choices listed below. Please take note of the word "report" in the name of our API pages.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3c2jxb77jnt7vh1oqgfq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3c2jxb77jnt7vh1oqgfq.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Within the &lt;code&gt;src/api&lt;/code&gt; directory, this command creates a directory called pages-reports. &lt;code&gt;Controllers&lt;/code&gt;, &lt;code&gt;routes&lt;/code&gt; , and &lt;code&gt;services&lt;/code&gt; are three directories that are part of the &lt;code&gt;pages-report&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Routes
&lt;/h2&gt;

&lt;p&gt;Routes manage requests sent to Strapi on any URL. According to the &lt;a href="https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/rest-api.html" rel="noopener noreferrer"&gt;REST API specification&lt;/a&gt;, Strapi automatically constructs &lt;a href="https://docs.strapi.io/developer-docs/latest/development/backend-customization/routes.html#implementation" rel="noopener noreferrer"&gt;routes&lt;/a&gt; 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.&lt;/p&gt;

&lt;p&gt;The following lines of code should be added to &lt;code&gt;src/api/pages-report/routes/pages-report.js&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

module.exports = {
      routes: [
        {
         method: 'GET',
         path: '/pages-report',
         handler: 'pages-report.findAll',
         config: {
           policies: [],
           middlewares: [],
         },
        },
      ],
    };


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Controllers vs Services
&lt;/h2&gt;

&lt;p&gt;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 &lt;a href="https://docs.strapi.io/developer-docs/latest/development/backend-customization/routes.html" rel="noopener noreferrer"&gt;route&lt;/a&gt;. The action executes the business logic code and provides the &lt;a href="https://docs.strapi.io/developer-docs/latest/development/backend-customization/requests-responses.html#responses" rel="noopener noreferrer"&gt;response&lt;/a&gt; whenever a client requests the route. The C in the model-view-controller (MVC) pattern is represented by the &lt;a href="https://docs.strapi.io/developer-docs/latest/development/backend-customization/services.html" rel="noopener noreferrer"&gt;controller&lt;/a&gt;. Most of a project's business logic will be found in the &lt;a href="https://strapi.gitee.io/documentation/v3.x/concepts/controllers.html" rel="noopener noreferrer"&gt;controllers&lt;/a&gt;. 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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;
&lt;h2&gt;
  
  
  Creating a Service
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Replace the following lines of code in &lt;code&gt;/src/api/pages-report/services/pages-report.js&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

'use strict';

    module.exports = {
      pagesReport: async () =&amp;gt; {
        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 &amp;amp;&amp;amp; Array.isArray(entries)) {
            entriesReduced = entries.reduce((acc, item) =&amp;gt; {
              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;
        }
      }
    }


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To fetch all pages, we are using the &lt;a href="https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/entity-service-api.html" rel="noopener noreferrer"&gt;Entity Service API&lt;/a&gt; for Strapi in this code. Read the documentation for the &lt;a href="https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/entity-service/populate.html#advanced-populating" rel="noopener noreferrer"&gt;Populating the Entity Service API&lt;/a&gt; to find out more about the flexible ways to populate the response.&lt;/p&gt;

&lt;p&gt;The following data will be returned by the pagesReport service:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

 [
      { "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" }
    ]


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Once a service is created, it's accessible from controllers or from other services:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

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


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Controllers and services can log the list of available services:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&lt;p&gt;console.log('strapi.services ', strapi.services);&lt;br&gt;
    console.log('pages-report', strapi.service('api::pages-report.pages-report'));&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Creating a Controller&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;A controller function is in charge of invoking our service upon request and returning the results to the &lt;code&gt;response&lt;/code&gt; because it has direct access to the Koa's ctx.&lt;/p&gt;

&lt;p&gt;Replace the following lines of code in &lt;code&gt;src/api/pages-report/controllers/pages-report.js&lt;/code&gt;:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&lt;p&gt;'use strict';&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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 })
    }
  }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Setting Permissions for the API&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;For the use case, it is all the code that is needed. &lt;code&gt;/api/pages-report&lt;/code&gt;should receive a get request. A 403 error will most likely appear.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvcuh4fex308b2qfrj84h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvcuh4fex308b2qfrj84h.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Please navigate to Setting &amp;gt; Roles &amp;gt; 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.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0g9073ztpgmtacxedh5d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0g9073ztpgmtacxedh5d.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Currently, the public can use the customised API:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw7r5y75d91nkldmuhyg4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw7r5y75d91nkldmuhyg4.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To obtain and filter the results for this article, we made use of Strapi's &lt;a href="https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/entity-service-api.html" rel="noopener noreferrer"&gt;Entity Service API&lt;/a&gt;. It's not the only method available to complete this assignment. Using the Rest API, &lt;a href="https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/query-engine-api.html" rel="noopener noreferrer"&gt;Query Engine API&lt;/a&gt;, and GraphQL API, users of Strapi can fetch and filter results.&lt;/p&gt;

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

</description>
    </item>
  </channel>
</rss>
