--- title: createWithCache description: |- Creates a utility function that executes an asynchronous operation like `fetch` and caches the result according to the strategy provided. Use this to call any third-party APIs from loaders or actions. By default, it uses the `CacheShort` strategy. api_version: 2023-10 api_name: hydrogen source_url: html: 'https://shopify.dev/docs/api/hydrogen/2023-10/utilities/createwithcache' md: 'https://shopify.dev/docs/api/hydrogen/2023-10/utilities/createwithcache.md' --- # create​With​Cache Creates a utility function that executes an asynchronous operation like `fetch` and caches the result according to the strategy provided. Use this to call any third-party APIs from loaders or actions. By default, it uses the `CacheShort` strategy. ## create​With​Cache([input1](#arguments-propertydetail-input1)​) ### Parameters * input1 CreateWithCacheOptions required ### Returns * CreateWithCacheReturn\ ### CreateWithCacheOptions * cache An instance that implements the \[Cache API]\(https://developer.mozilla.org/en-US/docs/Web/API/Cache) ```ts Cache ``` * waitUntil The \`waitUntil\` function is used to keep the current request/response lifecycle alive even after a response has been sent. It should be provided by your platform. ```ts ExecutionContext ``` * request The \`request\` object is used to access certain headers for debugging ```ts CrossRuntimeRequest ``` ```ts { /** An instance that implements the [Cache API](https://developer.mozilla.org/en-US/docs/Web/API/Cache) */ cache: Cache; /** The `waitUntil` function is used to keep the current request/response lifecycle alive even after a response has been sent. It should be provided by your platform. */ waitUntil: ExecutionContext['waitUntil']; /** The `request` object is used to access certain headers for debugging */ request?: CrossRuntimeRequest; } ``` ### CrossRuntimeRequest * url ```ts string ``` * method ```ts string ``` * headers ```ts { [key: string]: any; get?: (key: string) => string; } ``` ```ts { url?: string; method?: string; headers: { get?: (key: string) => string | null | undefined; [key: string]: any; }; } ``` ### CreateWithCacheReturn This is a caching async function. Whatever data is returned from the \`actionFn\` will be cached according to the strategy provided. Use the \`CachingStrategy\` to define a custom caching mechanism for your data. Or use one of the built-in caching strategies: \`CacheNone\`, \`CacheShort\`, \`CacheLong\`. * cacheKey ```ts CacheKey ``` * strategy ```ts AllCacheOptions ``` * actionFn ```ts () => U | Promise ``` interface Promise\ { /\*\* \* Attaches callbacks for the resolution and/or rejection of the Promise. \* @param onfulfilled The callback to execute when the Promise is resolved. \* @param onrejected The callback to execute when the Promise is rejected. \* @returns A Promise for the completion of which ever callback is executed. \*/ then\(onfulfilled?: ((value: T) => TResult1 | PromiseLike\) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike\) | undefined | null): Promise\; /\*\* \* Attaches a callback for only the rejection of the Promise. \* @param onrejected The callback to execute when the Promise is rejected. \* @returns A Promise for the completion of the callback. \*/ catch\(onrejected?: ((reason: any) => TResult | PromiseLike\) | undefined | null): Promise\; }, interface Promise\ { }, Promise: PromiseConstructor, interface Promise\ { readonly \[Symbol.toStringTag]: string; }, interface Promise\ { /\*\* \* Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The \* resolved value cannot be modified from the callback. \* @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). \* @returns A Promise for the completion of the callback. \*/ finally(onfinally?: (() => void) | undefined | null): Promise\ } ```ts interface Promise { /** * Attaches callbacks for the resolution and/or rejection of the Promise. * @param onfulfilled The callback to execute when the Promise is resolved. * @param onrejected The callback to execute when the Promise is rejected. * @returns A Promise for the completion of which ever callback is executed. */ then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): Promise; /** * Attaches a callback for only the rejection of the Promise. * @param onrejected The callback to execute when the Promise is rejected. * @returns A Promise for the completion of the callback. */ catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): Promise; }, interface Promise { }, Promise: PromiseConstructor, interface Promise { readonly [Symbol.toStringTag]: string; }, interface Promise { /** * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The * resolved value cannot be modified from the callback. * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). * @returns A Promise for the completion of the callback. */ finally(onfinally?: (() => void) | undefined | null): Promise } ``` ```ts type CreateWithCacheReturn = ( cacheKey: CacheKey, strategy: CachingStrategy, actionFn: () => U | Promise, ) => Promise; ``` ### CacheKey The cache key is used to uniquely identify a value in the cache. ```ts string | readonly unknown[] ``` ### AllCacheOptions Override options for a cache strategy. * mode The caching mode, generally \`public\`, \`private\`, or \`no-store\`. ```ts string ``` * maxAge The maximum amount of time in seconds that a resource will be considered fresh. See \`max-age\` in the \[MDN docs]\(https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#:\~:text=Response%20Directives-,max%2Dage,-The%20max%2Dage). ```ts number ``` * staleWhileRevalidate Indicate that the cache should serve the stale response in the background while revalidating the cache. See \`stale-while-revalidate\` in the \[MDN docs]\(https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#stale-while-revalidate). ```ts number ``` * sMaxAge Similar to \`maxAge\` but specific to shared caches. See \`s-maxage\` in the \[MDN docs]\(https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#s-maxage). ```ts number ``` * staleIfError Indicate that the cache should serve the stale response if an error occurs while revalidating the cache. See \`stale-if-error\` in the \[MDN docs]\(https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#stale-if-error). ```ts number ``` ```ts export interface AllCacheOptions { /** * The caching mode, generally `public`, `private`, or `no-store`. */ mode?: string; /** * The maximum amount of time in seconds that a resource will be considered fresh. See `max-age` in the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#:~:text=Response%20Directives-,max%2Dage,-The%20max%2Dage). */ maxAge?: number; /** * Indicate that the cache should serve the stale response in the background while revalidating the cache. See `stale-while-revalidate` in the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#stale-while-revalidate). */ staleWhileRevalidate?: number; /** * Similar to `maxAge` but specific to shared caches. See `s-maxage` in the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#s-maxage). */ sMaxAge?: number; /** * Indicate that the cache should serve the stale response if an error occurs while revalidating the cache. See `stale-if-error` in the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#stale-if-error). */ staleIfError?: number; } ``` Examples ### Examples * #### Example code ##### Description I am the default example ##### JavaScript ```js // In your app's `server.ts` file: import * as remixBuild from '@remix-run/dev/server-build'; import {createWithCache, CacheLong} from '@shopify/hydrogen'; // Use another `createRequestHandler` if deploying off oxygen import {createRequestHandler} from '@shopify/remix-oxygen'; export default { async fetch(request, env, executionContext) { const cache = await caches.open('my-cms'); const withCache = createWithCache({ cache, waitUntil: executionContext.waitUntil.bind(executionContext), request, }); // Create a custom utility to query a third-party API: const fetchMyCMS = (query) => { // Prefix the cache key and make it unique based on arguments. return withCache(['my-cms', query], CacheLong(), async () => { return await ( await fetch('my-cms.com/api', { method: 'POST', body: query, }) ).json(); }); }; const handleRequest = createRequestHandler({ build: remixBuild, mode: process.env.NODE_ENV, getLoadContext: () => ({ /* ... */ fetchMyCMS, }), }); return handleRequest(request); }, }; ``` ##### TypeScript ```ts // In your app's `server.ts` file: import * as remixBuild from '@remix-run/dev/server-build'; import {createWithCache, CacheLong} from '@shopify/hydrogen'; // Use another `createRequestHandler` if deploying off oxygen import {createRequestHandler} from '@shopify/remix-oxygen'; export default { async fetch( request: Request, env: Record, executionContext: ExecutionContext, ) { const cache = await caches.open('my-cms'); const withCache = createWithCache({ cache, waitUntil: executionContext.waitUntil.bind(executionContext), request, }); // Create a custom utility to query a third-party API: const fetchMyCMS = (query: string) => { // Prefix the cache key and make it unique based on arguments. return withCache(['my-cms', query], CacheLong(), async () => { return await ( await fetch('my-cms.com/api', { method: 'POST', body: query, }) ).json(); }); }; const handleRequest = createRequestHandler({ build: remixBuild, mode: process.env.NODE_ENV, getLoadContext: () => ({ // Make sure to update remix.env.d.ts to include `fetchMyCMS` fetchMyCMS, }), }); return handleRequest(request); }, }; ```