How to customize Strapi backend (content-manager) controllers, services and validation?

Hi all!

From what I understand, the API controllers for content-type are triggered only when the API are consumed from outside Strapi. So, If I would customize for example the update() method for a content type in the backend, have I to turn to the content-manager plugin logic, right? But how can I modify the controllers, the services and the valuators of the content-manager. For example I see that content-manager relies, for the services (and the validation), on strapi/lib/services, that is part of the core…

Hey @aminta :wave:,

To extend the controllers or service of the content-manager you will need to dig into the strapi-plugin-content-manager package and use plugin extensions to (partly) modify the behaviour of the content-manager functions.

I hope this helps you out, let me know if you have any questions. :+1:

Please do not the warning :warning: in the docs!

Hi @MattieBelt and thanks for the quick answer!

I try to explain better. What I’m trying to achieve is to check if a user leave a relation field blank in the backend editing a content type item and, if the relation field is blank, throw a validation error and to stop the saving process.

So, I now that this process is manages, in Strapi, by (in Strapi/lib/services/entity-service.js):

async update({ params, data, files }, { model }) {
const modelDef = db.getModel(model);
const existingEntry = await db.query(model).findOne(params);

const isDraft = contentTypesUtils.isDraft(existingEntry, modelDef);

const validData = await entityValidator.validateEntityUpdate(modelDef, data, {
  isDraft,
});

How can I “hook” this async update method?

Thanks!

For the default controllers and services, you do what is an overwrite method. Using the examples provided in:

In your case, you are looking at a service, depending on what you are intending to do (such as returning an error to the user) I would usually suggest modifying the controller for validation related stuff.

So for your model you will find an “empty” file at ./api/yourModel/controllers/yourModel.js where you would put something like:

const { parseMultipartData, sanitizeEntity } = require('strapi-utils');

module.exports = {
  /**
   * Update a record.
   *
   * @return {Object}
   */

  async update(ctx) {
    const { id } = ctx.params;

    if (!missing something) {
      return ctx.badRequest('Some error message')
    }

    let entity;
    if (ctx.is('multipart')) {
      const { data, files } = parseMultipartData(ctx);
      entity = await strapi.services.restaurant.update({ id }, data, {
        files,
      });
    } else {
      entity = await strapi.services.restaurant.update({ id }, ctx.request.body);
    }

    return sanitizeEntity(entity, { model: strapi.models.restaurant });
  },
};