Resources
So far our example custom coded components and actions had very simple property types: select
, boolean
, string
, etc. But what if your property is a data object like a product, collection or a CMS entry? At Shopstory we call these objects "resources" and you can create as many resource types as you need. They can be connected to any data source (e-commerce platform, CMS, etc) and you're in full control over how data is fetched by your front-end code.
Custom component with resource property
Let's build a simple ProductCard
component that takes 2 properties:
product
-> the object with product data liketitle
,description
,price
, etc. fetched from a mock e-commerce platform service. This property is our resource.hasOverlay
-> simpleboolean
prop controlling appearance
The code of our ProductCard
looks like this:
Schema - resource
field
resource
fieldIn order to register ProductCard
in Shopstory and take into account product
property we must use resource
field type:
Each resource
field must always define resourceType
which in our case is product
.
At this point Shopstory has no knowledge of the resource called product
. When you open Shopstory and add ProductCard
the editor will crash saying that product
widget is not defined.
Registering resource type
Each resource type in Shopstory consists of 2 parts:
widget
fetch function
Widget
Widget defines how resources are browsed and picked by the user in the Shopstory editor. Widget code is run only inside the Shopstory editor and is not involved when you render Shopstory content in your website.
Let's create a widget for our product
resource type. We do this via resourceTypes
property in the Shopstory configuration object:
In this code we tell Shopstory that product
should use a built-in item-picker
widget. Item picker is a simple single-select widget that requires 2 functions to work properly:
getItems
- searches for items by querygetItemById
- standard find-by-id function
After the widget is defined you can add ProductCard
to the Shopstory canvas and use item picker to pick a product:
As you can see the widget works properly but after selecting the product, the component still shows a placeholder. It's because we didn't define a second important part of the resource type: a fetch function.
Fetch function
When user picks a resource the only data saved in Shopstory data is resource identifier. In our example it's the product id
- the id
property returned by getItems
and getItemById
functions. Shopstory doesn't keep any data copies (like product title, description, price, etc) inside of its content so there is no problem with synchronising the data. It also means that if you want to render some content, Shopstory must first first fetch all the resources used by that content. How data is fetched is controlled by so called "fetch functions".
In our example we haven't defined a fetch function for our product
so it's no surprise that the ProductCard
is not rendered. Unsuccessful fetch will result in the field label turning red:
If you look at the console you'll see following error message:
To solve this we must add a fetch function to our product
resource type:
The first parameter of fetch
function is an array of resources that should be fetched. Each resource of this array has a following structure:
id
is the resource unique identifier. type
represents resource type, in this case it's always gonna have value "product"
. In our example fetchParams
and info
are not defined, we'll discuss them later.
The result of the fetch function should be an array of fetched resources. Fetched resource is represented by the same object as input resource with one extra property - either value
(successfully fetched resource data) or error
.
For example for the following input:
The output could look like this:
The products xxx
and yyy
were fetched successfully and in case of zzz
there was some fetching error that you intercepted and provided info about it to Shopstory.
Let's see the end result after adding the fetch function:
Errors in fetch function
If for some reason your fetch
function throws an error then all resources will be treated as if they had an error
property set.
Optional resources
Sometimes the resource are not required to render the component. In such case you can set the flag optional
to true
:
If the resource is not picked or fetching the resource resulted in error, the product
prop for your custom component will be undefined
.
Built-in resource types (connecting CMS data)
Shopstory plugins can register their own resource types. The main application of this feature is connecting CMS data (entries, media, etc) to custom components or actions.
For example, imagine you manage all your website URLs in the CMS (a common pattern when SEO is critical). You've created a content type (or document type) named UrlRoute
and each website URL is represented by the entry of this type. In this scenario, when editor adds a link action to a button in Shopstory, you obviously want to connect this link to some entry of UrlRoute
instead of hardcoding link in a text field. You can achieve such effect with built-in resource types.
Each Shopstory plugin can register its own resource types. CMS plugins, like contentfulPlugin
or sanityPlugin
always add built-in resource types for connecting to CMS-specific data.
Contentful registers 2 resource types:
contentful-entry
(for connecting to entries)contentful-asset
(assets)
Sanity registers 3 resource types:
sanity.document
(connects to other documents)sanity.image
(connects to images)sanity.file
(connects to files).
Each resource types can have its parameters. For example you can easily narrow down contentful-entry
or sanity.document
resource types to specific content types / document types. You can find in-depth specification of CMS-specific resource types with their parameters in CMS Guides.
Our custom link example would look like this in Contentful (transform
function will be described later in this chapter):
Default fetch function
Built-in resource types can come with a default fetch function. It means that if you don't define your own fetch function they'll be fetched in a default way. The default fetch behaviour depends on the CMS, you learn how it works in CMS Guides.
transform
property
transform
propertyIf you want to keep the default fetch but make some transformation of the result data, you can do it using transform
property. In the above-mentioned custom link example, only the { path: link.fields.path }
will be sent to the link component.
Custom fetch
In many cases you will want to completely ignore default fetch
behaviour and override it with your own data fetching. Built-in resource types are no different than custom resource types and you can easily do it with providing your own fetch
function.
In the example below we override how sanity.document
data is fetched:
Your custom fetch
function doesn't have to fetch all the resources from resources
input array. The resource is considered fetched when its value
or error
properties are set. For resources where value
and error
stay undefined
the custom fetcher will be applied after custom fetch
finished running.
Last updated