npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@sahareth/strapi-handler

v2.0.3

Published

Strapi-Handler assists in managing queries to Strapi's REST API services by constructing the queries on behalf of the developer, streamlining the process.

Downloads

11

Readme

Strapi-Handler

What is Strapi?

Strapi is a leading open-source headless Content Management System (CMS) that offers a fully customizable, 100% JavaScript-based solution for developers. It revolutionizes the way database calls are managed by utilizing a REST API system, providing a layer of abstraction from the database itself. Strapi makes developers' lives easier by offering a powerful and flexible CMS experience.

The Challenge

However, composing certain types of queries with Strapi can be cumbersome and time-consuming. The complexity of URLs required for these queries can quickly become a developer's worst nightmare, resulting in a less efficient workflow and increased development time.

Introducing Strapi-Handler

To address this challenge, Strapi-Handler was developed as a comprehensive solution to streamline REST calls for Collections (excluding single types) in Strapi. By employing simple method chaining, developers can now craft the perfect query within seconds and maintain a clear, readable structure for their code.

Key Features of Strapi-Handler

  1. Simplified REST calls: Strapi-Handler simplifies the process of making REST calls for Collections, allowing developers to focus on creating feature-rich applications without the hassle of managing complex URLs.
  2. Method chaining: With Strapi-Handler's intuitive method chaining, developers can easily create queries by chaining together various methods, resulting in clean and organized code.
  3. Normalized responses: Strapi-Handler goes the extra mile by normalizing Strapi's responses, ensuring a consistent format and structure for the data received.
  4. Enhanced readability: By employing method chaining and normalizing responses, Strapi-Handler significantly improves the readability of your code, making it easier for developers to understand, maintain, and collaborate on projects.

Strapi-Handler is an invaluable tool for developers working with Strapi, as it simplifies and optimizes the process of crafting REST calls for Collections. Its approach to method chaining and response normalization results in clean, readable code, ultimately leading to faster development times and increased productivity. Embrace the power of Strapi-Handler and revolutionize your headless CMS experience today.

Importing Strapi-Handler

import StrapiHandler from '@sahareth/strapi-handler';

Defining a StrapiHandler class

const strapiUrl = 'YOUR_STRAPI_URL';
const apiKey = 'YOUR_API_KEY';

const strapi = new StrapiHandler(strapiUrl, apiKey);

StrapiHandler instance

At this point you have four methods exposed in the StrapiHandler instance, which are:

StrapiHandler.create

public async create<T>(collectionName: string, obj: Partial<T>): Promise<T>

It accepts

| Parameter | Meaning | | --- | --- | | T | An optional parameter that specify of which type should be the returned object. Highly recommended | | collectioName | The “plural” name of the collection to create | | obj | The object to create. It should a partial* of type T. Do NOT se the the id manually. |

*See on the “Types” paragraph why is this a partial.

It returns

The object created on Strapi. It should be equal beside the id.

StrapiHandler.createMany

public async createMany<T>(collectionName: string, objects: Partial<T>[]): Promise<T[]>

It accepts

| Parameter | Meaning | | --- | --- | | T | An optional parameter that specify of which type should be the returned array of objects. Highly recommended | | collectioName | The “plural” name of the collection to create | | obj | An array of objects to create. It should a partial* of type T. Do NOT se the the id manually. |

*See on the “Types” paragraph why is this a partial.

It returns

An array of objects created on Strapi. They should be equivalent beside the id.

Note

This call N times the Strapi endpoint, since the bulk create is not implemented yet.

StrapiHandler.findOne

It accepts

| Parameter | Meaning | | --- | --- | | entries | The “plural” name of the collection to create |

It returns

A class of type StrapiFindOne.

You don’t need to know anything about StrapiFindOne beside its methods, that are the core of the package.

StrapiFindOne

It has a series all methods, almost all of them* can be chained, here exhaustive list:

| Name | Effect | Strapi Equivalent | | --- | --- | --- | | offsetStart | Set the pagination start | pagination[start]=value | | offsetLimit | Set the pagination limit | pagination[limit]=value | | hideId | Hide the id from the response object | No equivalent, new feature | | populate | Populate the first level of a relationship. | populate=field | | deepPopulate | Populate the second level of a relationship. | populate[field][populate][0]=field2 | | rename | Rename an field with another name. Acts after every other operator | No equivalent, new feature | | field | Specify which field to select. If there are more than once, chain this method multiple times or use “fields” | field[0]=value | | fields | Specify which fields to select. | field[0]=value&field[1]=value […] | | hideId | Hide the id in the response | No equivalent, new feature | | generateUuid | Generate an Uuid v4. Should be useless for normal functionality of the library | No equivalent. Useless for the end-user | | filter | Create a filter. Check the apposite chapter | filters[filter]=value | | and | Chain the previous “and” or “filter” to use the AND logic operator. Works like the filter. Can’t be chained with or | Equivalent of appending [$and][group] in the filter section | | or | Chain the previous “or” or “filter” to use the OR logic operator. Works like the filter. Can’t be chained with and | Equivalent of appending [$or][group] in the filter section | | showOnlyId | A chain terminator that returns only the id (or null, if not found). It’s optimised** to return only the id | Equivalent of making the GET and parsing the object | | show | A chain terminator that returns the full object (or the filtered and renamed one) | Equivalent of making the GET call and parsing the object | | update | A chain terminator that update the object found | Equivalent of making the GET call, and a PUT with the id found | | delete | A chain terminator that delete the object found | Equivalent of making the GET call, and a DELETE with the id found |

*And and Or can’t be chained together at the moment. You must use filters and group of Strapi.

** Since there is not a way to return only an id in Strapi, it search for a random field and remove it from the selected list

Note

There is not the possibility of passing an id that is already in the application, thus avoiding the GET call. It will implemented soon.

StrapiHandler.findAll

It accepts

| Parameter | Meaning | | --- | --- | | entries | The “plural” name of the collection to create |

It returns

A class of type StrapiFindAll.

You don’t need to know anything about StrapiFindAll beside its methods, that are the core of the package.

| Name | Effect | Strapi Equivalent | | --- | --- | --- | | offsetStart | Set the pagination start | pagination[start]=value | | offsetLimit | Set the pagination limit | pagination[limit]=value | | hideId | Hide the id from the response object | No equivalent, new feature | | populate | Populate the first level of a relationship. Strapi does support a two-level deep populate, but that’s not implemented yet. | populate=field | | deepPopulate | Populate the second level of a relationship. | populate[field][populate][0]=field2 | | sort | Sort the request by a parameter | sort[counter]=field | | page | Set the page to request for the next request | pagination[page]=value | | pageSize | Set the pageSize of the next request | pagination[pageSize]=value | | rename | Rename an field with another name. Acts after every other operator | No equivalent, new feature | | field | Specify which field to select. If there are more than once, chain this method multiple times or use “fields” | field[0]=value | | fields | Specify which fields to select. | field[0]=value&field[1]=value […] | | filter | Create a filter. Check the apposite chapter | filters[filter]=value | | and | Chain the previous “and” or “filter” to use the AND logic operator. Works like the filter. Can’t be chained with or | Equivalent of appending [$and][group] in the filter section | | or | Chain the previous “or” or “filter” to use the OR logic operator. Works like the filter. Can’t be chained with and | Equivalent of appending [$or][group] in the filter section | | showOnlyIds | A chain terminator that returns only the ids. It’s optimised** to return only the id | Equivalent of making the GET and parsing the object | | show | A chain terminator that returns the full object (or the filtered and renamed one) | Equivalent of making the GET call and parsing the object |

*And and Or can’t be chained together at the moment. You must use filters and group of Strapi.

** Since there is not a way to return only an id in Strapi, it search for a random field and remove it from the selected list

Filters

The filter accepts three (or four, in some cases) parameters. The most important one is the filter itself, that list of these filters can be imported from the /lib/Interfaces.ts of the package.

export enum FilterOperator {
    IS_EQUAL_TO = '$eq',
    IS_EQUAL_TO_CASE_INSENSITIVE  = '$eqi',
    IS_NOT_EQUAL_TO = '$ne',
    IS_LESS_THAN = '$lt',
    IS_LESS_THAN_OR_EQUAL_TO = '$lte',
    IS_GREATER_THAN = '$gt',
    IS_GREATER_THAN_OR_EQUAL_TO = '$gte',
    IN = '$in',
    NOT_IN = '$notIn',
    CONTAINS = '$contains',
    NOT_CONTAINS = '$notContains',
    CONTAINS_CASE_INSENSITIVE = '$containsi',
    NOT_CONTAINS_CASE_INSENSITIVE = '$notContainsi',
    IS_NULL = '$null',
    IS_NOT_NULL = '$notNull',
    IS_BETWEEN = '$between',
    STARTS_WITH = '$startsWith',
    STARTS_WITH_CASE_INSENSITIVE = '$startsWithi',
}

Complex Filters

The complex filters are... quite complex to be honest and they are not documented yet by Strapi. The strapi group has been implemented 1:1, you can find information on how to do complex query here: https://forum.strapi.io/t/advanced-api-filter-combining-and-and-or/24375 Here is an example of a complex query

await strapi.findAll(tests)
                     .filter('Num', IS_EQUAL_TO, 0, { andGroup: 0, orGroup: 0 })
                     .filter('Str2', IS_EQUAL_TO, 'Test', {andGroup: 1, orGroup: 0})
                     .filter('Num', IS_EQUAL_TO, 5, { andGroup: 2, orGroup: 1})
                     .filter('Str', FilterOperator.IS_NOT_EQUAL_TO, uuidv4(), { andGroup: 3, orGroup: 1})
                     .show<Test>();

That example means - Search all values that have:

(Num === 0 && Str2 === 'Test') || (Num === 5 && Str !== uuidv4())

Types and normalisation

The idea behind the return value of Strapi-Handler methods is to have the cleanest representation of the data or directly what is desired to be used from the database. Imagining a database structure of a Dog with a name that is a string and a weight that is an integer, the Strapi response to a GET with axios to that resource would be:

data: {
  data: {
    id: 0,
    attributes: {
      name: "Carlo",
      weight: 5
    }
  }
  metadata: {...}
}

That’s a lot different from our resource and you need to extract some data!

With the following line

const dog = await strapi.findOne('Dogs').filter('id', IS_EQUAL_TO, 0).show<Dog>(); // Where Strapi is a StrapiHandler up

//WARNING! Dog CAN be null (if not found)

the result will be

{
  id: 0,
  name: "Carlo",
  weight: 5
}

a lot simpler!

Additionally, with the "rename" method and the "hideId" method, the response can be modified in such a way that it fits into one's own TypeScript interface.

Again, the idea is not to necessarily modify the incoming object.

With a findAll, the answer will be similar

const { data, metadata } = await strapi.findAll('Dogs').filter('weight', IS_LESS_THAN_OR_EQUAL_TO, 5).show<Dog>();

data will be

[
  {
    id: 0,
    name: "Carlo",
    weight: 5
  },
  {
    id: 1,
    name: "Oliver",
    weight: 2
  }
]

A nice array of our interface instead of (deconstructing axios data)

{
  data: [
    {
      id: 0,
        attributes: {
          name: "Carlo",
          weight: 5
        }
    },
    id: {
      id: 1,
      attributes: {
        name: "Oliver",
        weight: 2
      }
    }
  ]
  metadata: {...}
}

It’s even nicer with the nested relationship, but the mechanism is the same!

Tests

The library is fully tested E2E, with a 100% coverage. To test it, clone the repository, change the branch to test-ready, and do a yarn command in the Strapi folder inside the repository.

Then you can execute:

yarn test:prep
yarn test