Get Linked Document from a Slice in a Custom Type [Unable to find body in homepage]

Error: api_validation_error - "Unable to find body on homepage"

Notes: Using Slice machine and the latest version of Prismic: @prismicio/client": "^6.6.3,

Query:

{
  homepage {
    body {
      ...on blogs {
        non-repeat {
          blog_title
        }
      }
    }
  }
}

Schema:


A quick response on this will be appreciated

Hi Rehan,

I'll be happy to help you with this.

Can you try using the API ID of slices instead of body?

Thanks.

@Phil - Still not working. Unable to find blogs in homepage.

Screenshot 2022-08-08 at 10.58.43 PM

Query

{
  homepage {
    call_to_action {
      non-repeat {
        blog_title
      }
    }
  }
}

Hi Rehan,

It seems you're querying a Shared Slice, we're currently updating the documentation related to this, but you can see how to do this correctly in the following thread:

And how to test this with the API Browser.

Thanks.

Hi @phil,

That solution worked, however, now I'm only getting the specified slice, not the rest of them. How do I get the rest of the slices along with the specified slice with a more complicated scenario?

Is there a ...restSlices kind param that I can include in this query?

{
  homepage{
    ...homepageFields
    slices {
      ...rest-of-the-slices-please // Something like this?
      ...on blogs {
        variation {
          ...on default {
            primary {
              title
            }
          }
        }
      }
    }
  }
}

Unfortunately, no param like this exists, but I agree it would very useful and have forwarded this idea to the team.

There are 2 ways to get the rest of your content:

  1. Do the query for the rest of your page and Slices in GraphQuery, which can be time-consuming and difficult to maintain.
  2. Do a separate query for the rest of your page content using the normal REST API syntax. The disadvantage is that you'll be running 2 queries, but if you're using a static generated site with Next.js or similar this won't slow your page times down.

I'll follow up with the team about this though.

Thanks.

Hi @Phil, that's unfortunate to hear as most of our content will rely on this kind of query. We're a business with over 200k hits/month and in the final stages of migrating to Prismic and this limitation is kind of big for us.

Is there any way we could add this feature sooner, say in weeks rather than months, and are you sure the team will build out this feature? It seems like a very natural query that should be included.

Hope you understand. I'll try other stuff in the meantime.

Thanks

Hey Rehan,

I don't have any ETA for updates to GraphQuery, but I can safely say this won't be down in the following weeks.

I would recommend doing your whole document query with GraphQuery, so let me clarify what I stated above. When I say it will be time-consuming, I mean writing the query might take 10mins vs 1min for a normal Rest API query and when I said it's difficult to maintain, I just mean you'll have to add any future Slices to the query.

So this is completely doable now with GraphQuery, and I'll be happy to help you work on this.

What is your exact use case here?

Thanks.

From my perspective it's huge limitation as:

  • for advanced and big custom types we need to define very long queries and maintain them -> it's just not cool developer experience.
  • as I understand we are not able to query nested documents in slices differently thant with graphQuery

my model is as follow:

  • I have content type homepage in which I have multiple slices.
  • One of the slices is slice called: Blog Posts Preview
  • Blog Post Preview slice keeps custom type: Blog post
  • Each Blog Posts has linked custom type called Author with fields: name, surname, avatar

I want to get nested fields (name, surname, avatar) from author in my query.

also please update documentation. I spent 1h trying to figure out what is wrong by looking on outdate documentation. :pray:

Yes, I agree it could be improved and the team plans to investigate how to improve this feature in the future.

Depending on the position of the Slice an alternative could be to do a separate query for the blog posts.

The documentation is been updated at the moment.

I've also reached out to the team to see if there are any better ways to maintain this query.

2 Likes

OK, so here is how my colleague maintains 2 queries:

  1. One standard REST API query for all the content
  2. A query only for the linked content

and then incorporates Slices and linked data into the classic array of slices:
https://github1s.com/chamois-d-or/cimsirp/blob/main/pages/index.js

  //Incorporating new slices with linked product data in existing slice array
  let index=0
  const docWithProductLists = {
    ...document,
    data : {
      ...document.data,
      slices: document?.data?.slices?.map(slice => {
        if(slice.slice_type === "product_list_with_cta"){
          index ++
          return {
            ...productListData?.data?.slices[index-1]
          }
        }
        return {
          ...slice
        }
      })
    }
  }


Hopefully, this should make querying and maintaining linked content simpler.

Hi @Phil,

The only problem I see with your code is that it requires the name of the slice and this might be hard to maintain if you have more nested slices with graph query.

If we really have to run 2 queries, this would be the best way to handle it in my opinion.

Hope this helps.

(async () => {
  try {
    const docWithAllSlices = await prismicAPI.getSingle("homepage");
    const docWithNestedSlices = await prismicAPI.getSingle(
      "homepage",
      {
        graphQuery: querySpecificSlices,
      }
    );

   // Prob put this into a utility folder

    const filteredSlices = docWithNestedSlices.data.slices
      .map((slice) =>
        docWithAllSlices.data.slices.filter(
          (nestedSlice) => slice.id !== nestedSlice.id
        )
      )
      .flat();

    const document = {
      ...docWithAllSlices,
      data: {
        slices: filteredSlices.concat(
          docWithNestedSlices.data.slices
        ),
      },
    };

    console.log(document); // this will result in all slices combined + the slices replaced that you don't need to all slices document.

    //
    //
  } catch (error) {
    console.log(error);
  }
})();
1 Like

So my colleague had a look at your code and has 2 comments:

  1. In the first part, I think if there are multiple slices in the GraphQuery this will duplicate all the filtered Slices for each graphqueryslice.
  2. The issue with this way of doing is that you lose the Slices order, as the graphqueryslices will be appended at the end of the array instead of being at their right position

A merge between the two approaches (yours and my colleagues) would allow you to keep the right order of the Slices and not have to specify any Slice ID.

Hi @Phil,

Those are good points and I've addressed both of them in the code given below. However, I do think that this solution should be taken in a small slice list scenario, or else it might have some impact on performance because you loop all slices list for every slice in the nested slices graph query.

Please let me know if I've missed anything. I think I'll be going for a fully custom graph query for my case because I'm very much focused on performance but just posting this solution here in case someone else needs this.

const querySpecificSlices = `{
  homepage{
    slices {
      ...on blogs {
        variation {
          ...on default {
            primary {
              title
            }
          }
        }
      }
    }
  }
}`;

(async () => {
  try {
    const docWithAllSlices = await prismicAPI.getSingle("homepage");
    const docWithNestedSlices = await prismicAPI.getSingle(
      "homepage",
      {
        graphQuery: querySpecificSlices,
      }
    );

    const filteredSlices = docWithNestedSlices.data.slices
      .map((nestedSlice) =>
        docWithAllSlices.data.slices.map((slice) =>
          slice.id === nestedSlice.id ? nestedSlice : slice
        )
      )
      .flat();

    const uniqSlices = filteredSlices.filter(
      (_, idx) =>
        idx <
        filteredSlices.length / docWithNestedSlices.data.slices.length
    );

    const document = {
      ...docWithAllSlices,
      data: {
        slices: uniqSlices,
      },
    };


  } catch (error) {
    console.log(error);
  }
})();