Where to write reusable code to access in all the models

System Information
  • Strapi Version: 3.2.5
  • Operating System: Ubuntu
  • Database: Postgresql
  • Node Version:14.15.3
  • NPM Version: 6.14.9
  • Yarn Version: 1.22.10

Hi i have a piece of code which i am using for external id encryption and decrytion.
The code is working fine.
but i am facing the code redundancy issue. as i have placed same code in all the models/{modelName}.js

Here is the small snippet i am trying to use…
./api/{apiName}/models/{modelName}.js

const Hashids = require("hashids/cjs");
const hashids = new Hashids("RandomSalt", 10);

/**
 * Read the documentation (https://strapi.io/documentation/v3.x/concepts/models.html#lifecycle-hooks)
 * to customize this model
 */
function decrypt(id) {
  id = hashids.decode(id);
  if (id.length === 0) return 0;
  else if (id.length === 1) return Number(id[0]);
  return id;
}
function decryptId(params) {
  if (params.id) params.id = decrypt(params.id);
  return params;
}
module.exports = {
  /**
   * Triggered before products find
   */

      lifecycles: {
        async beforeFind(params, populate) {
          params = decryptId(params);
        },
    }
}

const Hashids = require(“hashids/cjs”);
const hashids = new Hashids(“RandomSalt”, 10);
function decrypt(id){..}
function decryptId(params){...} 

now where can i add this reusable functionality
so that somehow i can call them at all the models/{ModelName}.js.
Thank you.

1 Like

You should not write business logic inside the model/{model}.js files.

For these purposes you can use functions:
https://strapi.io/documentation/developer-docs/latest/concepts/configurations.html#functions

Create a file under ./config/functions/encryption.js

With the content:

const Hashids = require("hashids/cjs");
const hashids = new Hashids("RandomSalt", 10);

module.exports = {
  async decrypt(id) {
     id = hashids.decode(id);
     if (id.length === 0) return 0;
     else if (id.length === 1) return Number(id[0]);
     return id;
  },
  async decryptId(params) {
     if (params.id) params.id = decrypt(params.id);
     return params;
  }
}

Now these functions are accessible from anywhere as follows:

  • await strapi.config.functions['encryption'].decrypt(id)
  • await strapi.config.functions['encryption'].decryptId(params)
3 Likes

Thank you very much :slight_smile:

Hey Sunny, great answer. Just out of curiosity for learning purposes, why should we not write core business functions inside the model.js files?

They are used for life cycles, and this structure will change likely later on in 2021.

2 Likes

I tried the same for Strapi v4, but it does not work. Is this still supposed to work the same way?

const slug = await strapi.config.functions['utils'].slugify(data.name);

error: Cannot read properties of undefined (reading 'utils')

TypeError: Cannot read properties of undefined (reading 'utils')

    at Object.afterUpdate ((...)\src\api\cookbook\content-types\cookbook\lifecycles.js:13:51)

    at modelsLifecyclesSubscriber ((...)\node_modules\@strapi\database\lib\lifecycles\subscribers\models-lifecycles.js:15:41)

    at Object.run ((...)\node_modules\@strapi\database\lib\lifecycles\index.js:47:17)

    at Object.update ((...)\node_modules\@strapi\database\lib\entity-manager.js:260:27)

    at async Object.update ((...)\node_modules\@strapi\strapi\lib\services\entity-service\index.js:219:18)

    at async Object.<anonymous> ((...)\node_modules\@strapi\strapi\lib\services\entity-service\index.js:67:20)

    at async Object.update ((...)\node_modules\@strapi\plugin-content-manager\server\controllers\collection-types.js:123:27)

    at async returnBodyMiddleware ((...)\node_modules\@strapi\strapi\lib\services\server\compose-endpoint.js:52:18)

    at async module.exports ((...)\node_modules\@strapi\plugin-content-manager\server\middlewares\routing.js:39:3)

    at async policiesMiddleware ((...)\node_modules\@strapi\strapi\lib\services\server\policy.js:24:5)    at async (...)\node_modules\@strapi\strapi\lib\middlewares\body.js:24:7

    at async (...)\node_modules\@strapi\strapi\lib\middlewares\logger.js:22:5

    at async (...)\node_modules\@strapi\strapi\lib\middlewares\powered-by.js:16:5

    at async cors ((...)\node_modules\@koa\cors\index.js:95:16)

    at async (...)\node_modules\@strapi\strapi\lib\middlewares\errors.js:13:7

    at async (...)\node_modules\@strapi\strapi\lib\services\metrics\middleware.js:29:5

You can create a file called index.js inside the config folder. Inside it you can define functions like this

    module.exports = {
      async something(param) {
        
      },
    };

Then use it somewhere like this: strapi.config.index.something(param);

5 Likes

This works for me thanks very much!

Is there any way to access the strapi object in these functions, e.g. await strapi.service("api::list.list").find(...)

worked for v4.4, also your file name in config folder can be everything, it’s not have to called index.js