'Components not included in Strapi api response

I decided today that I'm going to use Strapi as my headless CMS for my portfolio, I've bumped into some issues though, which I just seem to not be able to find a solution to online. Maybe I'm just too clueless to actually find the real issue.

I have set up a schema for my projects that will be stored in Strapi (everything done in the web), but I've had some issues with my custom components, and that is, they are not part of the API responses when I run it through Postman. (Not just empty keys but not included in the response at all). All other fields, that are not components, are filled out as expected.

At first I thought it might have to do with the permissions, but everything is enabled so it can't be that, I also tried looking into the API in the code, but that logging the answer there didn't include the components either.

Here is an image of some of the fields in the schema, but more importantly the components that are not included in the response.

Some of the fields

So my question is, do I need to create some sort of a parser or anything in the project to be able to include these fields, or why are they not included?



Solution 1:[1]

I had the same problem and was able to fix it by adding populate=* to the end of the API endpoint.

For example:

http://localhost:1337/api/test?populate=*

More info here: https://forum.strapi.io/t/cannot-see-media-field-in-my-endpoint-for-my-content-type/13082/2

edit: Only first-level relations are populated with populate=* . Use the LHS bracket syntax (i.e. [populate]=*) to populate deeper:

For example:

http://localhost:1337/api/test?populate[TestExamples][populate]=*

More info here if you go to Relations population: https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/rest-api.html#fields-selection

Solution 2:[2]

Just to add to the accepted answer, if you are working with a lot of nested collections or nested components (for example using a lot of custom components in Single Types), then it might be worth to write a custom controller.

I need to render a homepage which has a 'Header' component, and the Header has two nested 'Button' components which are repeatable. Additionally, I want to render a collection of 'Clients' which is a one-to-many relationship.

Since this data structure won't change often, I have just written a custom controller so I don't have to worry about this in the front-end.

Let's say you have created a Homepage Single Type to render your homepage, the controller will be available in the following directory: /src/api/homepage/controllers/homepage.js

In the below example I want to render the Header component with the nested header_image and buttons and the Clients component with the nested clients collection.

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

module.exports = createCoreController('api::homepage.homepage', ({ strapi }) => ({
    async find(ctx) {
        const populateList = [
            'Header.header_image',
            'Header.buttons',
            'Clients.clients'
        ]
        // Push any additional query params to the array
        populateList.push(ctx.query.populate)
        ctx.query.populate = populateList.join(',')

        const content = await super.find(ctx)
        return content
    }
}));

There seems to be a significant difference between Strapi V3 and V4 and I find the documentation on populating nested components quite poor for V4. I guess this will be updated in the next couple of weeks as Strapi V4 has only just been released.

If there is a better way to populate deeply nested components or relationships I'd love to hear but I hope that the above also helps some people in the meantime.

Solution 3:[3]

I'm relatively noob to Strapi, especially V4. I have only developed one app with version 3.6.8 in the last year. Unless you haven't seen a problem yet, I believe I solved that issue in the endpoint call. I must also say that I have not deployed it yet. It's just in the development environment.

The data architecture

The endpoint call:

http://localhost:1337/api/profiles/?filters[user]=1&populate[0]=permissions&populate1=permissions.forms.form&populate2=permissions.quiz&populate[3]=permissions.unity&populate[4]=permissions.forms.form.Questions Blockquote

The Endpoint Call

Solution 4:[4]

For people using Angular, it can be quite annoying to create the correct nested QueryParams to use with the HttpClient so I created this DeepQuery class (gist here, in case of issues):

class DeepQuery {
  constructor(public query: any) {

  }

  private isObj(obj: any): boolean {
    return (
      typeof obj === 'object' &&
      obj !== null
    )
  }

  private toQPK(crumbs: string[]): string {
    if (crumbs.length == 0) {
      throw new Error(`Parameter without key`)
    }
    return crumbs[0] + crumbs.slice(1).map(s => `[${s}]`).join("");
  }

  private parse(obj: any, crumbs: string[] = [], memo: {[key: string]: any} = {}) {
    if (!this.isObj(obj)) {
      memo[this.toQPK(crumbs)] = obj;
    } else if (Array.isArray(obj)) {
      for (let i = 0; i < obj.length; i++) {
        crumbs.push(i.toString());
        this.parse(obj[i], crumbs, memo);
        crumbs.pop();
      }
    } else {
      for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
          crumbs.push(key);
          this.parse(obj[key], crumbs, memo)
          crumbs.pop();
        }
      }
    }
    return memo;
  }

  public encode() {
    return this.parse(this.query);
  }
}

Its encode method creates an object that you can pass to any HTTP calls you make:

makeCall(type: string): Observable<any> {
    let populate = {
        authors: ["listing", "publisher"]
    };
    let params = new DeepQuery({populate});
    return this.html.get<any>(url.href, params.encode());
  }

Solution 5:[5]

Gatsbyjs solution!!!: I am using single types and I have a component inside of that single type called for example header settings where users fill stuff like phone number location and so on... and I am also using Gatsbyjs for my front-end and here strapi.js Screenshot is a solution for that too.gatsby-config.js Screenshot Just in case someone has the same issue

Solution 6:[6]

i found this solution with the Strapi plugin to be able to fetch the data of a collectionTypes that have inside a custom component create with Strapi.

To be clearly the my situation is this one, i have a collectionType named "article" that have inside a custom component, and to fetch them apparently we need to deep dive.

here is my solution with the strapi plugin gatsby-source-strapi

{
  resolve: "gatsby-source-strapi",
  options: {
    apiURL:
      process.env.NODE_ENV === "production"
        ? process.env.API_URL
        : "http://localhost:1337/api",
    accessToken: process.env.STRAPI_TOKEN,
    collectionTypes: [
      { name: `descrizioni-home-page` },
      { name: "article", endpoint: "articles?populate=*" },
    ],
    singleTypes: [{ name: "homepage", endpoint: "homepage?populate=*" }],
    queryLimit: 5000,
  },
},

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 BleddP
Solution 3 Dharman
Solution 4
Solution 5 Ahmed Alyasiri
Solution 6 Sergio Bergamo