Strapi V4 populate Media and Dynamiczones from Components

Here’s a modification of @urbandale’s solution, which includes the code for overwriting the findOne controller, and maintains default functionality for API requests which do not include populate=*.

This seems to be the best working solution for v4.1.7.

Please see @urbandale’s post for more context.

./src/api/page/controllers/page.js

'use strict'

/**
 *  page controller
 *
 *  info: https://forum.strapi.io/t/strapi-v4-populate-media-and-dynamiczones-from-components/12670/26
 */

const { createCoreController } = require('@strapi/strapi').factories

// declare the uid for the controller
const uid = 'api::page.page'

// see @urbandale's post for context: https://forum.strapi.io/t/strapi-v4-populate-media-and-dynamiczones-from-components/12670/26
const components = {
  Image: true, // get data for media item field called "Image"
  Content: {
    // a dynamic zone with different components,
    // and those components might have some repeatable sub-component too
    // We only seem to need to add the sub-components...
    populate: {
      Image: true, // media field called "Image"
      Buttons: {
        // repeatable sub-component called "Buttons" used in a dynamic zone component
        populate: {
          page: true, // the Button component has a relation to a page item, so populate that...
        },
      },
      Icons: true, // another repeatable sub-component used in a dynamic zone component
    },
  },
}

module.exports = createCoreController(uid, () => {
  return {
    async find(ctx) {
      // overwrite default populate=* functionality
      if (ctx.query.populate === '*') {
        const entity = await strapi.entityService.findMany(uid, {
          ...ctx.query,
          populate: components,
        })
        const sanitizedEntity = await this.sanitizeOutput(entity, ctx)

        return this.transformResponse(sanitizedEntity)
      }
      // maintain default functionality for all other request
      return super.find(ctx)
    },
    async findOne(ctx) {

      const { id } = ctx.request.params

      if (ctx.query.populate === '*') {
        const entity = await strapi.entityService.findOne(uid, id, {
          ...ctx.query,
          populate: components,
        })
        const sanitizedEntity = await this.sanitizeOutput(entity, ctx)

        return this.transformResponse(sanitizedEntity)
      }

      return super.findOne(ctx)
    },
  }
})

1 Like