How to include content of referenced stories by resolving relations
In our previous articles, you had the chance to learn how to structure your content for a blog, including authors and categories. The next step is to utilize Storyblok and the already available home content entry to create your landing page and enhance it with featured posts.
The demo content
The default home
story that you receive by creating a new space already includes three components: Teaser
, Grid
, and Feature
components. Those components can be removed or adjusted to your needs. What we’re about to do is to extend the list of available components with a new one: featured_posts
.
In this tutorial, we are going to:
- Creating the new
featured_posts
block in the block library - Adding the field named
posts
as a multi-option field. The options are filled with the stories we will create in theposts
folder. We will see how to set the field correctly - Adding the new
featured_posts
in thehome
story - Retrieving the Home story via API
- Resolving the relationship via Content Delivery API, GraphQL, and Javascript SDK (also taking into account the Storyblok JS Bridge)
The featured posts block
The featured_posts
block will be a container for all our post references. Think of it as a section we want to have on our start page beside a teaser
and a grid
containing our articles' information.
We must jump into the Block Library section to create the featured post block.
Let’s start by navigating to Block Library {1} in the left sidebar. Once you’re on the blocks overview, we will create a new block by pressing New Block {2} on the top right corner.
Then, we can start creating the new block, setting the name, and defining the block type.
In the popup dialog window, fill the name of the block as featured_posts
in the Technical name field {1}, select Nestable block for Select block type option {2}, and click the Add Block button {3} to create the new block.
Adding the multi-option field in the new block
Once we create the new featured_posts
block, we must create the field for storing the references with the posts.
For adding the new field into the featured_posts
block, you can fill posts
as Name {1}, then click on the icon on the right of the name {2} for opening the popup to select the field type. In the field type list, select Multi-options {3}, and then click to Add button {4} to add the new field.
In this way, the new posts
field is listed in the block field list.
For editing the attributes of the new field, and setting the relations, select the posts
field {1} in the field list.
Selecting the field, you can access the field options where you can set the relation with other stories (for example, the posts).
To allow the selection of other stories, we will change the Source of the posts
field to Stories
{1}. Now, to limit the selection of the stories that could be added as relations, we can set the path folder where to retrieve the related stories.
In this case, you can choose the Global Reference Field as this field-type already locks the Source to Stories by default. For content editors, using Global Reference Field might be straightforward.
Once you select Stories {1} as the source, you can now write the path posts/
{2} in the now available Path to the folder of stories input located below the dropdown; however, this is optional. You can also allow only specific content types via the Restrict to content type select box {3}.
The last step we need to take with the featured_posts
is to save it by pressing Save & Back to Fields button {4} in the bottom right corner.
Now we have the block {1} in the Block Library, we can start using it in our stories in the content section.
You can navigate back to the content section in the Storyblok space by clicking on Content {1} on the left sidebar. Then, select the Home story {2} that should be available, as Storyblok will create it as an example for new spaces. If you do not have that entry, you can click the Create new button {3} in the top right corner. You won’t have to do that step if you already have the Home story available.
Selecting the Home stories, you will access the Visual Editor.
By default, you will see the quickstart screen showing your draft token, and you can find additional useful information here.
The next step we’re about to do is to use our new featured_posts
component. To do that, we will click the plus + button {1} in the component list on the right-side panel in the proper position we want to add the block.
Then, in the list of the nestable blocks, let’s click on Featured Posts {2} to add it to the content.
Once you click on the component you want to add Storyblok will add the instance to the current content and open that instance in the sidebar. You should now already be able to select the posts you want to feature. Let's feature the first post we created in the initial tutorial. This list will be empty if you do not have any entries in a folder with the slug posts so make sure to have a look at the first blog tutorial.
Once selected, we will have to save and/or publish our content entry to persist the changes and make them available in the Content Delivery API. Pressing the Publish button {1} you will save and publish the content.
Clicking the Save button {2} you will save the content in draft
version.
The next thing to do is to retrieve the content from our API, so you can use it in your application with your preferred technology. We can do this in two ways, namely:
- We can make an API call to fetch the
home
story and make another API call to retrieve thefeatured_posts
using theirUUIDs
. - We can add a query parameter to our API request stating the relationship we want to resolve. With this approach, we won't have to make two API requests.
Retrieving the story content via API
You can either look at our Content Delivery API and learn how to retrieve one story from there, or you can press the little arrow right next to the Publish button to access the Draft JSON (API V2) option. Storyblok will open a new tab with the GET
request that you can use to access your content.
An example URL to the draft JSON can be found here.
We can now follow two approaches to retrieve the post behind that uuid
. We can either choose to send another request and retrieve multiple stories by uuids or we can use the resolve_relations
query param that Storyblok has available.
Resolving the relationship via the Content Delivery API
Remember that the resolved relationship will not be included in the story's content but under the rels
array below story
when using an API request. That said, it will also not be reflected in the input
Storyblok JS Bridge as it is an API operation and changes the default structure. So, disabling the input or checking for your references being uuid
strings or objects needs to be done.
The resolve_relations
parameter is how the API allows you to define a list of component_name.field_name
pairs it should try to resolve. Resolving relationships will work with arrays of uuids
(as we have from the multi-options field type) or with fields that contain one uuid
as a string (the single-option field type, for example). So, what do we have to pass to the resolve_relation
parameter?
Let’s have a look at our data structure: the field that contains the array of uuids
is called posts
, and the component that fields belong to is called featured_posts
so the parameter will be resolve_relations=featured_posts.posts
. Let’s add that to the end of our request and see how the response will change.
The URL should look like this now:
We can see that we now have the whole object of the referenced content available. That allows us to directly access the fields of that referenced content entry, without having to do another request.
If you use the storyblok-js-client
and storyblok-bridge
, the resolved relations (in this case featured_posts
) will be added to the original place of uuids
as well as in rels
. However, when you use an API request, it will be only added to the rels
array.
Reducing the size of the response
Resolve relations allow the information about the stories involved in the relationship to be obtained in a single HTTP call. This has an impact on the size of the response. In case you want to reduce the size of the response at the cost of making two HTTP calls, however, you can proceed as follows:
- Make the first call to get the main history without a relationship resolution
- Retrieve the list of UUIDs of related stories in the body of the response
- Make a second HTTP call to get a list of stories (learn how to retrieve multiple stories in our docs) based on the UUIDs, using either the
by_uuids
parameter (in case the order of related stories is not important) or theby_uuids_ordered
parameter (in case the order is important).
For the HTTP call to retrieve multiple stories, you can specify the excluding_fields
parameter for excluding specific fields of your content type by comma-separated names. This can significantly reduce the size of your API response. An example: excluding_fields=title,content
.
Example:
If you want to explore the Storyblok GraphQL functionalities, you can use the playground at this URL: https://gapi-browser.storyblok.com/?token=insert-here-your-access-token
The result can be seen below.
Resolving relations using the JavaScript Client
In the previous sections, we explored how the APIs (RESTful and GraphQL) work. To simplify the process, you could use the Universal JavaScript Client for Storyblok's API. (storyblok-js-client)
You can retrieve the story and related stories via JavaScript code. To do this, let's see how:
- install the Client
- correctly initialize the library
- retrieve the content
- parse the content
To do all the steps above, we will use the Universal JavaScript Client. If you're using a specific framework like Next.js/React or Nuxt/Vue or Sveltekit/Svelte or whatever, you'll need to refer to the library-specific SDK. Still, the retrieval and initialization logic is the same.
Install the Client
To install the Client, you can use npm
or yarn
:
Once you have installed the Client, you can start using it.
Initialize the Storyblok Client
Creating a new file or, if you are using a framework, in the proper place for loading external data, you can initialize the library. You have to import the StoryblockClient
, and you have to instance it using a proper API key token.
Then, once you have your Storyblok
object instance, you can perform a get on the home story.
Retrieving the content via get() method
Performing a get()
, you have to send also:
- the
version
parameter: set as "draft
" if you want draft content or "published
" if you want to retrieve published data. Remember to use the proper token in theStoryblokClient
initialization (we have aPreview
token that allows you to retrieve draft and published content, and we havePublish
token for retrieving only published content) - the
resolve_relations
option: set with the name of the block name (featured_posts
) and the field name (posts
), for example,featured_posts.posts
.
Once you have the response, you can walk through the structure.
Parsing the content
Considering that to access the story, you have to use the nested object: response.data.story,
and because of the content, once you have your story, you can access to content.body
with the list of the blocks included in your story. One of these blocks is the featured_posts
block, and you can retrieve that via this example code (Obviously, you have to adapt it based on your needs. In this case, we are just performing a console.log()
:
Once you access the right block and access the posts (the name of the field used as a multi-option in the block), you can retrieve the list of the related stories.
Parsing the object that comes from the SDK is easier than using the API directly. Because the API structure exposes the relations in a specific section in the JSON response (the rels
section). Once it retrieves the story via API, the SDK re-arranges the response structure in an object where your relations are nested directly in the parent object.
To allow the JS Client to copy the related story from rels
to the right place in the root story
object, you must set the field name (for example, posts
) with the component's name (for example, featured_posts
) as a prefix, like featured_posts.posts
.
Using the Storyblok Bridge
If you are using Storyblok Bridge, in addition to configuring relationships for API calls, you will need to configure relationship resolution during Storyblok Bridge initialization.
For example, if your relationship in the example above is featured_posts.posts
, you need to initialize the Storyblok Brige using the resolveRelations
option. Pay attention to the fact that for API calls, the option is resolve_relations
(with the underscore) while the initialization of the Storyblok Bridge uses the camel case notation. So to set up correctly the Storyblok Bridge:
Resolving more than 50 relations
If the total number of relationships to be resolved is greater than 50, the API service response will not contain the related stories in the attribute for performance reasons. Instead, the list of identifiers ( uuids
) of the stories that should be resolved is returned. This array of UUIDs is included in the rel_uuids
attribute.
The expansion of the resolved stories is then delegated to the client using the list of identifiers included in the rel_uuids
attribute (an array of strings). Suppose you're using one of the SDKs provided by Storyblok under the hood when the response is received; in that case, additional API calls are made by the SDK (to the stories
endpoint) based on the array of identifiers to retrieve related stories. The SDK then injects the stories into the correct place in the main story structure.
A practical example for retrieving stories via the Storyblok JS Client package:
Using specific framework SDK
If you use some specific SDK for Nuxt Next.js or SvelteKit to start the Storyblok objects and get the content, I will share the basic tutorials with you to make a proper connection. The important thing to consider is to use the resolve_relations
parameter when you fetch the content.
The tutorial specific to the frameworks:
- Connect SvelteKit with Storyblok;
- Connect Next.js with Storyblok;
- Connect Nuxt with Storyblok.
In the case of frameworks like Nuxt, Next,js, or SveltKit, for example, you can use a helper (provided by the framework-specific SDKs) that wraps the Storyblok.get()
method, but the important thing to remember for retrieving the relations is to use the right option parameter resolve_relations
:
Then, it would help if you used the same resolveRelations
array in the Storyblok Bridge initialization. For example, on the mount of your page component, you can use something like this:
Wrapping Up
With the resolve_relations
parameter of Storyblok, you can easily include referenced resources to save API requests, even though we do not charge extra for your API requests, this is a quick and easy-to-use way to save you some time in development. You can use it for featured posts, resolving authors and categories on the post detail page. Maybe reference related or similar products on a product details page without performing another request.