Search code examples
strapi

Strapi V4 how to modify data response for a component (dynamic zone)


Imagine a case where an editor adds a “Latest Products” component to a page using dynamic zone: they add a title, a summary, and then the latest products will automatically be fetched to be available in the response. How can I add this data to the response of the component?

I know we can override the response for content types using a custom controller, but I can't find anything for how to modify the response for a component.

Maybe there's an alternative approach I haven't thought of, but coming from a Drupal preprocess-everything background this is all I can think of.

Any help appreciated!


Solution

  • I'm sure this isn't the best way, but I created a service for components that can be used in the content type controller to modify the response. Any improvements appreciated!

    /api/custom-page/controllers/custom-page.js

    'use strict';
    
    /**
    *  custom-page controller
    */
    
    const { createCoreController } = require('@strapi/strapi').factories;
    
    module.exports = createCoreController('api::custom-page.custom-page', ({ strapi }) =>  ({
    
    async find(ctx) {
    
    const componentService = strapi.service('api::components.components');
    
    let { data, meta } = await super.find(ctx);
    
    
    data = await Promise.all(data.map(async (entry, index) => {
    
      if(entry.attributes.sections){
        await Promise.all(entry.attributes.sections.map(async (section, index) => {
          const component = await componentService.getComponent(section);
          entry.attributes.sections[index] = component;
        }));
      }
      return entry;
    
    }));
    
    
    return { data, meta };
    },
    
    }));
    

    /components/services/components.js

    'use strict';
    
    /**
     * components service.
     */
    
    module.exports = () => ({
      getComponent: async (input) => {
    
        // Latest products
        if(input.__component === 'sections.latest-products'){
          input.products = 'customdatahere';
        }
    
        return input;
    
      }
    });