From cd6403c724b038b03a51231424ba468bb5dba1e6 Mon Sep 17 00:00:00 2001 From: Laurin Quast Date: Thu, 28 Jul 2022 12:55:59 +0200 Subject: [PATCH] add docs --- packages/plugins/response-cache/README.md | 3 + website/routes.ts | 1 + website/v3/docs/features/response-caching.mdx | 201 ++++++++++++++++++ 3 files changed, 205 insertions(+) create mode 100644 packages/plugins/response-cache/README.md create mode 100644 website/v3/docs/features/response-caching.mdx diff --git a/packages/plugins/response-cache/README.md b/packages/plugins/response-cache/README.md new file mode 100644 index 0000000000..02da9b6e91 --- /dev/null +++ b/packages/plugins/response-cache/README.md @@ -0,0 +1,3 @@ +# @graphql-yoga/plugin-response-cache + +For the documentation check `http://graphql-yoga.com/docs/response-cache` diff --git a/website/routes.ts b/website/routes.ts index 55f5551004..854c6420b3 100644 --- a/website/routes.ts +++ b/website/routes.ts @@ -103,6 +103,7 @@ export function getDocsV3Routes(): IRoutes { ['testing', 'Testing'], ['persisted-operations', 'Persisted Operations'], ['automatic-persisted-queries', 'Automatic Persisted Queries'], + ['response-caching', 'Response Caching'], ], }, integrations: { diff --git a/website/v3/docs/features/response-caching.mdx b/website/v3/docs/features/response-caching.mdx new file mode 100644 index 0000000000..272465c705 --- /dev/null +++ b/website/v3/docs/features/response-caching.mdx @@ -0,0 +1,201 @@ +--- +id: response-caching +title: Response Caching +sidebar_label: Resposne Caching +--- + +Response caching is a technique for reducing server load by caching GraphQL query operation results. + +## Installation + + + +## Quick Start + +```ts +import { createYoga } from 'graphql-yoga' +import { createServer } from 'node:http' +import { useResponseCache } from '@graphql-yoga/plugin-response-cache' + +const yoga = createYoga({ + schema: { + typeDefs: `type Query { slow: String}`, + resolvers: { + Query: { + slow: async () => { + await new Promise((resolve) => setTimeout(resolve, 5000)) + return 'I am slow.' + }, + }, + }, + }, + plugins: [ + useResponseCache({ + // global cache + session: () => null, + }), + ], +}) + +const server = createServer(yoga) +server.listen(4000) +``` + +``` +curl -X POST -H 'Content-Type: application/json' http://localhost:4000/graphql \ +-d '{"query":"{__typename}"}' -w '\nTotal time : %{time_total}' +``` + +This will output something like the following: + +``` +{"data":{"slow":"I am slow."}} +Total time:5.026632 +``` + +After executing the same curl statement a second time, the duration is significantly lower. + +``` +{"data":{"slow":"I am slow."}} +Total time:0.007571% +``` + +## Session based caching + +If your GraphQL API returns specific data depending on the viewer's session, you can use the `session` option to cache the response per session. + +```ts +useResponseCache({ + // cache based on the authentication header + session: (request) => request.headers.get('authentication'), +}) +``` + +## TTL + +It is possible to give cached operations a time to live. Either globally, based on [schema coordinates](https://github.com/graphql/graphql-wg/blob/main/rfcs/SchemaCoordinates.md) or object types. +If a query operation result contains multiple objects of the same type, the lowest TTL is picked. + +```ts +useResponseCache({ + session: () => null, + // by default cache all operations for 2 seconds + ttl: 2_000, + ttlPerType: { + // only cache query operations containing User for 500ms + User: 500, + }, + ttlPerSchemaCoordinate: { + // cache operations selecting Query.lazy for 10 seconds + 'Query.lazy': 10_000, + }, +}) +``` + +## Invalidatios via Mutation + +When executing a mutation operation the cached query results that contain type entities within the Mutation result will be automatically be invalidated. + +```graphql +mutation { + updateUser(id: 1, newName: "John") { + __typename + id + name + } +} +``` + +```json +{ + "data": { + "updateLaunch": { + "__typename": "User", + "id": "1", + "name": "John" + } + } +} +``` + +All cached query results that contain the type `User` with the id `1` will be invalidated. + +This behavior can be disabled by setting the `invalidateViaMutation` option to `false`. + +```ts +useResponseCache({ + session: (request) => null, + invalidateViaMutation: false, +}) +``` + +## Manual Invalidation + +You can invalidate a type or specific instances of a type using the cache invalidation API. + +In order to use the API, you need to manually instantiate the cache an pass it to the `useResponseCache` plugin. + +```ts +import { + useResponseCache, + createInMemoryCache, +} from '@graphql-yoga/plugin-response-cache' + +const cache = createInMemoryCache() + +useResponseCache({ + session: () => null, + cache, +}) +``` + +Then in your business logic you can call the `invalidate` method on the cache instance. + +Invalidate all GraphQL query results that referance a specific type: + +```ts +cache.invalidate([{ type: 'User' }]) +``` + +Invalidate all GraphQL query results that reference a specific entity of a type: + +```ts +cache.invalidate([{ type: 'User', id: '1' }]) +``` + +Invalidate all GraphQL query results multiple entities in a single call. + +```ts +cache.invalidate([ + { type: 'Post', id: '1' }, + { type: 'User', id: '2' }, +]) +``` + +## External Cache + +By default the response cache stores all the cached query results in memory. + +If you want a cache that is shared between multiple server instances you can use the Redis cache implementation. + + + +```ts +import { useResponseCache } from '@graphql-yoga/plugin-response-cache' +import Redis from 'ioredis' + +const redis = new Redis({ + host: 'my-redis-db.example.com', + port: '30652', + password: '1234567890', +}) + +const redis = new Redis('rediss://:1234567890@my-redis-db.example.com:30652') + +const cache = createRedisCache({ redis }) + +useResponseCache({ + session: () => null, + cache, +}) +```