Cache
The PrismicCachedResolver is a decorator for a resolver that returns Prismic Content. It caches the results at a resolver level with references to the documents.
In order to create references from prismic to the cached documents, we need to
ensure that the PrismicCachedResolver receives a
Content
type from your resolver. The resolver can either cache a singleton Content, or
a list of Content.
Resolver Cache API
PrismicCachedResolver(resolver[, options])
Returns a resolver that caches the result of the given resolver.
Arguments:
resolver: A custom resolver that returns aContentor an array ofContent,options: An object with the following properties:mapParamsToIdA function that maps the resolver parameters to a unique id.contentPropertyThe name of the property that contains the Content.
Usage
To use the PrismicCachedResolver you need to import it into your
resolvers.js and wrap your resolver with decorator.
import PrismicCachedResolver from "prismic/server/modules/prismic/core/cache/PrismicCachedResolver";
export default {
Query: {
resolver: PrismicCachedResolver((_, __, { loaders }) =>
loaders.MyModule.loadAll()
),
},
};
Singleton Content
This is the most simple usecase. The PrismicCachedResolver will cache a
singleton Content.
So let's say we want to cache a resolver that loads a single Faq entry, we can simply decorate our original resolver
import PrismicCachedResolver from "prismic/server/modules/prismic/core/cache/PrismicCachedResolver";
export default {
Query: {
faqEntry: PrismicCachedResolver((source, { slug }, { loaders }) => {
return loaders.FaqLoader.loadBySlug(slug); // returns Promise<Content>
}),
},
};
Now the faqEntry resolver will always load the same cached faq entry.
To avoid this issue, map the slug parameter to the cache key, by passing the
mapParamsToId option to the PrismicCachedResolver.
import PrismicCachedResolver from "prismic/server/modules/prismic/core/cache/PrismicCachedResolver";
export default {
Query: {
- faqEntry: PrismicCachedResolver((source, {slug}, {loaders}) =>{
- return loaders.FaqLoader.loadBySlug(slug);
- }),
+ faqEntry: PrismicCachedResolver((source, {slug}, {loaders}) =>{
+ return loaders.FaqLoader.loadBySlug(slug);
+ }, {
+ mapParamsToId: (_, { slug }) => slug,
+ }),
},
};
List Content
When caching a list of Content we expect to receive an Array containing the Content.
import PrismicCachedResolver from "prismic/server/modules/prismic/core/cache/PrismicCachedResolver";
export default {
Query: {
faqList: PrismicCachedResolver((_, __, { loaders }) => {
return ctx.loaders.FaqLoader.loadAll(); // returns Promise<Content[]>
}),
},
};
You can also define a contentProperty, this is for a more advanced usecase,
where you want to return an object with a property containing the Content array,
for example with pagination
import PrismicCachedResolver from "prismic/server/modules/prismic/core/cache/PrismicCachedResolver";
export default {
Query: {
faqList: PrismicCachedResolver(
(_, __, { loaders }) => {
// returns Promise<{
// list: [Content, Content],
// total: 10
// }>
return ctx.loaders.FaqLoader.loadAll();
},
{
contentProperty: "list",
}
),
},
};
contentProperty can also be used with singleton Content.
NullContent
The NullContent has been introduced to allow caching of resolvers that return
null.
Lets say that you return a tag based on an id, but you only want to return the
tags which are in the allow list, in this case, we will return null for the
tags that are not in the allow list.
const allowList = ["tag1", "tag2"];
export default {
Query: {
tag: PrismicCachedResolver((parent, args, { loaders }) => {
const tag = loaders.TagLoader.loadById(args.id);
return allowList.includes(tag.name) ? tag : null;
}),
},
};
The issue we have here is that there is no way to create a reference to the Tag
document in prismic, so we won't be able to know that tag3 or tag4 should
cache null. For this we have the NullContent.
The NullContent takes in a single parameter, contentOrDcoumentId, which is
either the Content object that should be cached as null, or the direct id to
the document parent document.
import NullContent from "prismic/server/domain/NullContent";
const allowList = ["tag1", "tag2"];
export default {
Query: {
tag: PrismicCachedResolver((parent, args, { loaders }) => {
const tag = loaders.TagLoader.loadById(args.id);
- return allowList.includes(tag.name) ? tag : null;
+ return allowList.includes(tag.name) ? tag : NullContent(tag);
}),
},
};
The direct id of the document is usefull when the caching is based on the parent
of the document, for example when you want to cache the tag inside a Faq
document.
export default {
Fax: {
tag: PrismicCachedResolver((parent, args, { loaders }) => {
const tag = loaders.DocumentLoader.loadTagByDocumentID(
source.documentMetadata.documentID
);
return allowList.includes(tag.name)
? tag
: NullContent(source.documentMetadata.documentID);
}),
},
};
Advanced Usecase
What if we want to manipulate the data after it is retrieved either from the cache or the resolver?
The PrismicCachedResolver is a resolver like any other, so you can call it at
any time within a resolver, as soon as you propagate the resolver parameters to
the PrismicCachedResolver.
import PrismicCachedResolver from "prismic/server/modules/prismic/core/cache/PrismicCachedResolver";
export default {
Query: {
faqList: async (...params) => {
const list = await PrismicCachedResolver((_, __, { loaders }) => {
return ctx.loaders.FaqLoader.loadAll(); // returns Promise<Content[]>
})(...params); // propogate the params to `PrismicCachedResolver`
if (!list) {
return null;
}
return {
list,
total: list.length,
};
},
faqEntry: async (...params) => {
const [source, { slug }, { loaders }] = params; // we can also reuse the params from the current resolver
const entry = await PrismicCachedResolver(
() => {
return loaders.FaqLoader.loadBySlug(slug); // returns Promise<Content>
},
{
mapParamsToId: () => slug,
}
)(...params);
if (!entry) {
return null;
}
return entry;
},
},
};