Logo

dev-resources.site

for different kinds of informations.

Creating a Searchable Reading List with Strapi CMS Custom API

Published at
1/20/2024
Categories
strapi
idea
cms
Author
njfamirm
Categories
3 categories in total
strapi
open
idea
open
cms
open
Author
8 person written this
njfamirm
open
Creating a Searchable Reading List with Strapi CMS Custom API

Hi everyone!

As programmers, we are constantly learning and reading articles, blog posts, and documentation. Maybe this is the most important part of programming lifestyle!

Unfortunately, we do not keep those resource anywhere, and even if we keep them on our notes because it is not accessible through searching, we can't access them anymore.

Idea

An interesting solution for our problem is a searchable reading list that's I got this idea from the esif.dev blog.

At the end, you can setup and maintain a searchable-reading-list of valuable resources that you encounter during your programming journey!

Roadmap

Since we may read several articles in a day and need to put it in the reading-list, We needed to have a CMS, so that I could put the links there very quickly and easily and not think about anything else.

Also, our reading list page should work with the API and not need to be built statically like other pages with Eleventy. So I decided to use Strapi as a beautiful, dynamic, and easy-to-use CMS.

Preparing the environment

Before we can start building our reading-list, we need to create a new Strapi project.

yarn create strapi-app reading-list --ts
Enter fullscreen mode Exit fullscreen mode

Create Content Type

First, we need to create a content-type that we can put our reading-list in, So to create a content type for our reading-list, we can use the Strapi CLI and run the following command in our project directory. This will generate a new content type with the specified name and fields.

This command will create a new content type called reading-list and generate the necessary files and fields to get started building our custom API.

yarn strapi generate

  ? Strapi Generators content-type - Generate a content type for an API
  ? Content type display name Reading List
  ? Content type singular name reading-list
  ? Content type plural name reading-lists
  ? Please choose the model type Collection Type
  ? Use draft and publish? No
  ? Do you want to add attributes? Yes
  ? Name of attribute title
  ? What type of attribute string
  ? Do you want to add another attribute? Yes
  ? Name of attribute url
  ? What type of attribute string
  ? Do you want to add another attribute? Yes
  ? Name of attribute keyword
  ? What type of attribute text
  ? Do you want to add another attribute? Yes
  ? Name of attribute description
  ? What type of attribute richtext
  ? Do you want to add another attribute? Yes
  ? Name of attribute keyword
  ? What type of attribute text
  ? Do you want to add another attribute? No
  ? Where do you want to add this model? Add model to new API
  ? Name of the new API? reading-list
  ? Bootstrap API related files? Yes
  ✔ ++ /api/reading-list/content-types/reading-list/schema.json
  ✔ +- /api/reading-list/content-types/reading-list/schema.json
  ✔ ++ /api/reading-list/controllers/reading-list.ts
  ✔ ++ /api/reading-list/services/reading-list.ts
  ✔ ++ /api/reading-list/routes/reading-list.ts
Enter fullscreen mode Exit fullscreen mode

This is a base schema, but we can improve them by adding regex and unique to the url field and also making the title and the url required, this is result of the schema can put under api/reading-list/content-types/reading-list/schema.json:

{
  "kind": "collectionType",
  "collectionName": "reading_lists",
  "info": {
    "singularName": "reading-list",
    "pluralName": "reading-lists",
    "displayName": "Reading List",
    "description": ""
  },
  "options": {
    "draftAndPublish": false
  },
  "attributes": {
    "title": {
      "type": "string",
      "required": true
    },
    "url": {
      "type": "string",
      "regex": "https?:\\/\\/(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\\+.~#?&//=]*)",
      "required": true,
      "unique": true
    },
    "description": {
      "type": "richtext"
    },
    "keyword": {
      "type": "text",
      "required": false
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Screenshot of strapi content type

Very good, Now we have simple reading list in strapi, let's make them searchable!

Search Custom API

In this step we'll use the strapi-generate command again to creates a custom API pure file structure.

yarn strapi generate

  ? Strapi Generators api - Generate a basic API
  ? API name reading-list-search
  ? Is this API for a plugin? No
  ✔ ++ /api/reading-list-search/routes/reading-list-search.ts
  ✔ ++ /api/reading-list-search/controllers/reading-list-search.ts
  ✔ ++ /api/reading-list-search/services/reading-list-search.ts
Enter fullscreen mode Exit fullscreen mode

Now we need to fill the files with the correct codes.

Service

Services are a set of reusable functions to simplify controllers' logic. ReadMore

In this step, we use the service to create a function to get the reading list and filter them. The keyword parameter is used to filter the reading-list based on their keywords, and if no keyword is given, it returns all content of reading-list.

api/reading-list-search/services/reading-list-search.js:

import {errors} from '@strapi/utils';

async function search(keyword?: string) {
  try {
    const entries = await strapi.entityService.findMany('api::reading-list.reading-list', {});

    let filteredEntries = entries;
    if (keyword) {
      filteredEntries = entries.filter((entry) => {
        const keywords = entry.keyword.split('\n').map((keyword) => keyword.trim());
        return keywords.includes(keyword);
      });
    }

    return filteredEntries;
  } catch (err) {
    throw new errors.ApplicationError('Something went wrong');
  }
}

export default {search};
Enter fullscreen mode Exit fullscreen mode

this function first gets reading-list with findMany and then filters them using the typescript filter function.

Controller

Controllers contain a set of methods, called actions, reached by the client according to the requested route. ReadMore

To write a controller for the reading-list search function, set the content of the api/reading-list-search/controllers/reading-list-search.js file something like this to pass keyword search query into search service function.

async function search(ctx) {
  try {
    return await strapi.service('api::reading-list-search.reading-list-search').search(ctx.request.query.keyword);
  } catch (err) {
    ctx.badRequest('Reading list search controller error', {detail: err});
  }
}

export default {search};
Enter fullscreen mode Exit fullscreen mode

Route

Requests sent to Strapi on any URL are handled by routes. ReadMore

We must add this endpoint and sets the previous controller as the route handler, put this code to api/reading-list-search/routes/reading-list-search.ts:

export default {
  routes: [
    {
      method: 'GET',
      path: '/reading-list-search',
      handler: 'reading-list-search.search',
      config: {
        policies: [],
      },
    },
  ],
};
Enter fullscreen mode Exit fullscreen mode

Now this route is accessible at /api/reading-list-search, of course if we do the next step 🤓!

Set Permission

By default, this API can't be accessible publicly so set the correct permission.

Screenshot of set permission for strapi custom API

Result

Congratulations 🎉, we create a custom API for searching in our reading-list using Strapi CMS.

Screenshot of reading list custom API response

I hope this article is useful for you, and it is a step towards a society where we grow together ♥️


Thanks @derrickmehaffy for improve this article.

idea Article's
30 articles in total
Favicon
Dev Diaries: Symbolite
Favicon
How to market your idea intro reality.
Favicon
10 Remote SaaS Business Ideas That Will Let You Travel the World
Favicon
The Best Free Alternative to IntelliJ HTTP Client
Favicon
Дашборд для всего
Favicon
Book a Cook
Favicon
Starting a new project - Probtrix
Favicon
How to Validate a SaaS Idea Before Building an MVP
Favicon
JavaScript in IDE scripting console
Favicon
Wednesday Links - Edition 2024-09-18
Favicon
Hotkeys tool for left-handed mouse user.
Favicon
The Power of Full Project Context using LLM's
Favicon
Exciting Java Project Ideas for Beginners 🚀☕
Favicon
How to Grow Online Business Smoothly
Favicon
Github for Story Writing
Favicon
🔥😎 😱Revolutionizing Developer Productivity
Favicon
Deepening the Understanding: A Refined Exploration of Binary Data Stream Analysis
Favicon
Seeking Insights: Enhancing Social Interactions in Games and Apps
Favicon
Ideas for Mobile Applications
Favicon
Help With Solving an App Idea
Favicon
Creating a Searchable Reading List with Strapi CMS Custom API
Favicon
My Intellij IDEA plugin for Maven support - GMaven
Favicon
Beginner Project Idea to Learn Angular and RxJs
Favicon
Unlocking Computational Efficiency in Event Analysis Through Centroids and Blocks: A Conceptual Exploration
Favicon
Redefining Real-Time Machine Learning with Simple Euclidean Points
Favicon
Decoding Pursuer and Evader Points: A New Framework for Understanding Event Dynamics
Favicon
Utilizing Euclidean Space to Represent Tokenized Sequential Data: A Novel Framework for Advancing AI and AGI
Favicon
What would everyone think of a `window.post` variable in JavaScript?
Favicon
Почему важно вести блог
Favicon
How to Transform Your Idea into an Investment by Crafting an Irresistible Pitch

Featured ones: