Can we remove media formats stream from core API Responses?

System Information
  • Strapi Version: 4.1.1
  • Operating System: MacOS
  • Database: SQLite/MariaDB
  • Node Version: 12.22.6
  • NPM Version: 7.24.2

Hi, I would like to know if it is possible to filter the fields outputted for the media fields?
I have a Post entity that have a cover image and I’d like to remove unnecessary fields such as
cover.data.attributes.formats.medium.stream

Thanks for your answers!

I’ve tried something but I’m not completely satisfied with the end result as it must be implemented for each entity that must be modified. I’d like to find something more generic that will be applied to all media data output.

// src/api/post/services/post.js

const PostModel = require('../content-types/post/schema.json');
const { createCoreService } = require('@strapi/strapi').factories;

module.exports = createCoreService('api::post.post', ({strapi}) => ({

  /**
   * Scan the model to find media field and returns the fields name
   * @return {string[]}
   */
  getModelMediaFields() {
    return Object.entries(PostModel.attributes)
      .filter((field) => field[1].type === "media")
      .map(field => field[0]);
  },

  /**
   * Remove the stream property of a core media data
   * @param data
   * @return {*}
   */
  transformMediaData(data) {
    for(const formatName in data.formats) {
      if (data.formats[formatName].stream)
        delete (data.formats[formatName].stream);
    }

    return data;
  },

  /**
   * Change the default Post output by removing the *.media.stream properties
   * @param entityId
   * @param params
   * @return {Promise<any>}
   */
  async findOne(entityId, params = {}) {
    // Gets the default output from strapi
    const entity = await strapi.entityService
      .findOne('api::post.post', entityId, this.getFetchParams(params));

    // Transform each media field on the root object to remove the stream property
    for(const field of this.getModelMediaFields()) {
      entity[field] = this.transformMediaData(entity[field]);
    }

    return entity;
  },

}));

Strapi version : 4.1.1

TLTR:

The following steps will help you to remove the stream property that was present on each media object.

  1. Go to your src/index.js file :
const FileUploadOverride = require('./extensions/file-upload-override');

module.exports = {
  // ...
  register({ strapi }) {
    // Load our override module
    FileUploadOverride.register(strapi);
  },
  // ...
  1. Next create the file src/extensions/file-upload-override.js :

const _ = require('lodash')

module.exports = {
  /**
   * Register the module
   * @param strapi
   */
  register (strapi) {
    // Register custom methods on the service under override property to clearly identify them
    strapi.plugin('upload').services.upload.override = {
      generateBlurredFilePlaceholder: this.generateBlurredFilePlaceholder,
      transformMediaObject: this.transformMediaObject
    }

    // Override the uploadFileAndPersist method to hook or custom functions
    strapi.plugin('upload').services.upload.uploadFileAndPersist = this.uploadFileAndPersist;
  },

  /**
   * Override the upload service method to add our function
   *
   * @see {import('@strapi/plugin-upload/server/services/upload')}
   *
   * {@link https://forum.strapi.io/t/adding-blurhash-to-image-uploads/1802/13}
   * {@link
    * https://github.com/strapi/strapi/blob/637f51270fd95bc1d59bf5dfe7d837e0b8b1cada/packages/core/upload/server/services/upload.js#L158
  *   The method source code}
   *
   * @param fileData
   * @param user
   * @return {Promise<*>}
   */
  uploadFileAndPersist: async function (fileData, { user } = {}) {
    const config = strapi.config.get('plugin.upload')

    const {
      getDimensions,
      generateThumbnail,
      generateResponsiveFormats,
      isSupportedImage
    } = strapi.plugin('upload').service('image-manipulation')

    await strapi.plugin('upload').service('provider').upload(fileData)

    if (await isSupportedImage(fileData)) {
      const thumbnailFile = await generateThumbnail(fileData)

      if (thumbnailFile) {
        await strapi.plugin('upload').service('provider').upload(thumbnailFile)


        delete thumbnailFile.buffer
        _.set(fileData, 'formats.thumbnail', thumbnailFile)
      }

      const formats = await generateResponsiveFormats(fileData)

      if (Array.isArray(formats) && formats.length > 0) {
        for (const format of formats) {
          if (!format) { continue }

          const { key, file } = format

          strapi.plugin('upload').service('provider').upload(file)

          // Remove any stream property from the file data
          this.override.transformMediaObject(fileData);

          _.set(fileData, ['formats', key], file)
        }
      }

      const { width, height } = await getDimensions(fileData)

      _.assign(fileData, {
        provider: config.provider,
        width,
        height
      })
    }

    return this.add(fileData, { user })
  },


  /**
   * Transform a fileData object before persist it into the DB
   * @param fileData
   */
  transformMediaObject: (fileData) => {
    if (!_.isNil(fileData.stream))
      delete (fileData.stream);
  },
}
  1. Restart your server and you are good to go !

Detailled

I was searching a way to remove the stream property that was on each media format and which was containing the entire buffer of each format file. It was stored in the DB (even if files was stored on the server) and returned into the API. To avoid getting +1MB request size for getting my post, I removed them.

The code above is highly inspired of the solution found on this thread Adding Blurhash to image uploads - #13 by SoftCreatR

1 Like

Code Correction for transformMediaObject method:

  transformMediaObject: (fileData) => {
    for (const format in fileData.formats) {
      if (!_.isNil(fileData.formats[format].stream))
        delete (fileData.formats[format].stream);
    }
  },