2.0.3 • Published 1 year ago

@sahareth/strapi-handler v2.0.3

Weekly downloads
-
License
MIT
Repository
github
Last release
1 year ago

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

ParameterMeaning
TAn optional parameter that specify of which type should be the returned object. Highly recommended
collectioNameThe “plural” name of the collection to create
objThe 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

ParameterMeaning
TAn optional parameter that specify of which type should be the returned array of objects. Highly recommended
collectioNameThe “plural” name of the collection to create
objAn 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

ParameterMeaning
entriesThe “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:

NameEffectStrapi Equivalent
offsetStartSet the pagination startpaginationstart=value
offsetLimitSet the pagination limitpaginationlimit=value
hideIdHide the id from the response objectNo equivalent, new feature
populatePopulate the first level of a relationship.populate=field
deepPopulatePopulate the second level of a relationship.populatefield0=field2
renameRename an field with another name. Acts after every other operatorNo equivalent, new feature
fieldSpecify which field to select. If there are more than once, chain this method multiple times or use “fields”field0=value
fieldsSpecify which fields to select.field0=value&field1=value
hideIdHide the id in the responseNo equivalent, new feature
generateUuidGenerate an Uuid v4. Should be useless for normal functionality of the libraryNo equivalent. Useless for the end-user
filterCreate a filter. Check the apposite chapterfiltersfilter=value
andChain the previous “and” or “filter” to use the AND logic operator. Works like the filter. Can’t be chained with orEquivalent of appending $and in the filter section
orChain the previous “or” or “filter” to use the OR logic operator. Works like the filter. Can’t be chained with andEquivalent of appending $or in the filter section
showOnlyIdA chain terminator that returns only the id (or null, if not found). It’s optimised** to return only the idEquivalent of making the GET and parsing the object
showA chain terminator that returns the full object (or the filtered and renamed one)Equivalent of making the GET call and parsing the object
updateA chain terminator that update the object foundEquivalent of making the GET call, and a PUT with the id found
deleteA chain terminator that delete the object foundEquivalent 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

ParameterMeaning
entriesThe “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.

NameEffectStrapi Equivalent
offsetStartSet the pagination startpaginationstart=value
offsetLimitSet the pagination limitpaginationlimit=value
hideIdHide the id from the response objectNo equivalent, new feature
populatePopulate the first level of a relationship. Strapi does support a two-level deep populate, but that’s not implemented yet.populate=field
deepPopulatePopulate the second level of a relationship.populatefield0=field2
sortSort the request by a parametersortcounter=field
pageSet the page to request for the next requestpaginationpage=value
pageSizeSet the pageSize of the next requestpaginationpageSize=value
renameRename an field with another name. Acts after every other operatorNo equivalent, new feature
fieldSpecify which field to select. If there are more than once, chain this method multiple times or use “fields”field0=value
fieldsSpecify which fields to select.field0=value&field1=value
filterCreate a filter. Check the apposite chapterfiltersfilter=value
andChain the previous “and” or “filter” to use the AND logic operator. Works like the filter. Can’t be chained with orEquivalent of appending $and in the filter section
orChain the previous “or” or “filter” to use the OR logic operator. Works like the filter. Can’t be chained with andEquivalent of appending $or in the filter section
showOnlyIdsA chain terminator that returns only the ids. It’s optimised** to return only the idEquivalent of making the GET and parsing the object
showA 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
2.0.3

1 year ago

2.0.2

1 year ago

2.0.1

1 year ago

2.0.0

1 year ago

1.0.3

1 year ago

1.0.2

1 year ago

1.0.1

1 year ago

1.0.0

1 year ago