Published on April 14, 2021
The most frequently asked questions in DevRel when I started with Contentful were about how to display links or linked entries and assets inside the Contentful Rich Text field on the front end. It’s no secret that those of you who tuned in to my Twitch streams after I had started at Contentful saw me struggle with the concept of links as well!
So, I set out to explore and investigate the inner workings of the Contentful REST API and GraphQL API in terms of linking assets and entries on a content type in order to understand how we can render links inside Contentful Rich Text fields.
Sign up for your free Contentful account and start building in minutes.
If you’re looking for information on how to render linked assets and entries returned as part of the Contentful Rich Text field response using REST or GraphQL in JavaScript, check out this post.
Links are Contentful’s way of modelling relationships between content types and entries. Entries in Contentful can contain link fields that point to other assets or entries, and those entries can link to other assets or entries, and so on. For example:
A blog post can have an author
A team can have many authors
A company can have many teams
You can liken this to working with relational databases, where you would define one to one or one to many relationships within your data structures or models. For more information on the concept of links in Contentful, visit the documentation.
Here’s the content model that we’ll be working with in this article. The screenshot of the blog post content model below shows that the Author field is a Reference field type, which is a link.
If you’re using the Content Delivery and Content Preview REST API, Contentful provides a number of SDKs (Software Development Kits) in the most popular programming languages. These will resolve your linked entries and assets for you. In this example, we’ll be taking a look at the JavaScript SDK.
If you’re using the GraphQL API, you control how your entries are resolved in the construction of your GraphQL query. And by understanding how the REST API works and how the SDKs resolve links, you’ll be all set.
Let’s take a look!
The following examples focus on using the JavaScript ecosystem to query data from this example blog post. The example blog post is served on an application built with Next.js — but we won’t be going into Next.js in this post.
Take this example request URL.
It is querying the Contentful Delivery API with the following parameters:
spaceId: Our space ID
accessToken: Our access token for the Content Delivery API
content_type: blogPost
fields.slug: the-power-of-the-contentful-rich-text-field
Return the blogPost entry that has this slug
include: 10
Return linked entries and assets up to 10 levels deep (this is the maximum include
parameter value on the Content Delivery API) - we will unpack this later!
The raw JSON response from the request above contains the following top level properties and nodes in a flat structure.
items
contains the requested entries (the entry with the matching slug in this case). Each entry contains a subset of the fields
defined on the content type of this entry and some internal system information (sys
). Notice how the linked author
entry is missing the fields
property. It only holds the sys
information including the linkType
and id
.
Where are the author fields? Let’s find out!
The includes
object contains two array nodes:
"Entry"
for all referenced entries in items
(such as the the blog post author which we saw returned as a “type”: “Link”
in the response above)
"Asset"
for all referenced assets in items
(such as images, which might be a featured image on a blog post, for example)
In the case of the author
, which is a linked entry on our blogPost
, we see the full author object returned in includes.Entry[0]
— including another link to an image asset.
The response includes all the data that you need to render the blog post to the front end. However, the data is spread across items
and includes
, and you — as a developer — would expect all that data to be returned as one object, right? 🤯
For example, in React, you might want to do something like this to show the author’s name on the front end:
However, we need to do some more work before we can make this happen — we need to resolve the linked entries — and this is where we can use the Contentful JavaScript SDK.
Currently, the blogPost item references the author by sys.id
:
You could cross-reference the items[0].fields.author.sys.id
with the includes.Entry
array, find the item in the array that has the id
that matches, and resolve the data from there. It sounds pretty straightforward in this example, but when your content model gets more complex with many entries linking to other entries, it could get unwieldy.
Let’s look at how the JavaScript SDK can help us out.
Under the hood, the JavaScript SDK uses the contentful-resolve-response package, which converts the raw nodes into a rich tree of data. The one limitation of the Contentful Delivery API to bear in mind is that it will only return linked entries up to a maximum of 10 levels deep that can be resolved.
include
request parameterSpecify the depth of the resolved tree using the include
parameter in the request to the API, either as a parameter on the GET request URL, like this:
or via a call to the JavaScript SDK:
Both examples above make the same request to the Contentful API — except the SDK example is resolving your linked entries as part of the process using contentful-resolve-response. Neat!
include
parameter affects the length of the includes
responseSay you have a blog post, which has a reference to an author, which has a reference to a team.
To visualise this in an object graph:
If you specify includes=1
in your request, your includes
array on the response will contain one item in this example, the author
object (1 level deep).
If you specify includes=2
in your request, your includes
array on the response will contain two items, the author
object and the team
object. (2 levels deep).
If your blogPost
had another top level reference, say a heroBanner
, includes=1
would return both the author
and heroBanner
inside the includes
array.
Regardless of the include
depth you specify — the SDK — which uses the contentful-resolve-response package, will link all available and responded entries and assets that are returned in the includes
response.
Read more about the include param on the Contentful docs.
Our very own GraphQL Content API doesn’t require an SDK to handle linked entries — but understanding the concepts covered previously helps us out here.
The response from the GraphQL API gives you a rich object graph as standard (so you won’t find includes
in the response).
With GraphQL you specify the equivalent depth of the includes
response through the construction of your query. The only limit here is the complexity of your GraphQL query. Technically, if you construct your query cleverly, you can reach data hundreds of levels deep! Read more about GraphQL complexity limits here.
Here’s the GraphQL query that we would use to fetch the same blog post data with the author name and image as referenced in the first example:
And here’s how we can query the Contentful GraphQL API using fetch:
To compare this query to the include
levels in the REST API:
Level 1
blogPost
Level 2
blogPost.author
Level 3
blogPost.author.image
Due to how we constructed our GraphQL query to fetch the linked entries and assets, the raw response from the GraphQL contains the data for the linked assets and entries in the nodes we would expect — at a content type level only.
Here’s the response for the above query from the GraphQL API:
In the response above, the data for author
appeared in the node tree exactly where we expected it, and we can access the name on the front end — for example, via data.blogPostCollection.items[0].author.name
— without having to use an SDK to resolve the entries.
In comparison to the REST API, where you usually fetch the blog post data and link the entries after the fact, a GraphQL API query is entirely flexible to your needs. There’s always the caveat, however, that a complex GraphQL query with many nested link assets and entries might surpass the maximum complexity permitted on the GraphQL API. Read more about GraphQL complexity limits here.
Understanding the structure of the data responses from Contentful and how linked assets are returned and then resolved via the Contentful SDKs, empowers you to choose which APIs and methods are best suited to your applications.
And, hey, if you want to resolve the linked assets and entries yourself, then you’re well equipped.
Check out some further reading on how you can resolve linked assets and entries from the Contentful Rich Text field response in both the REST API and GraphQL API. If you're enjoying the experience of using Contentful, share the good news with your network so they can can sign up for a free Contentful account (no credit card required).
And remember, build stuff, learn things and love what you do.
Subscribe for updates
Build better digital experiences with Contentful updates direct to your inbox.