GraphQL Yoga v3 documentation (superseded by v5): Persisted operations is a mechanism for preventing the execution of arbitrary GraphQL operation documents.
Persisted operations is a mechanism for preventing the execution of arbitrary GraphQL operation
documents. By default, the persisted operations plugin follows the
the APQ Specification
for SENDING hashes to the server.
However, you can customize the protocol to comply to other implementations e.g. used by
Relay persisted queries.
change this behavior by overriding the getPersistedOperationKey option to support Relay’s
specification for example.
Quick Start
Persisted operations requires installing a separate package.
The recommended way of extracting the persisted operations from your client is to use
GraphQL Code Generator.
For people not using the client-preset the is also the standalone
graphql-codegen-persisted-query-ids
plugin for extracting a map of persisted query ids and their corresponding GraphQL documents from
your application/client-code in a JSON file.
If you validate your persisted operations while building your store, we recommend to skip the
validation on the server. So this will reduce the work done by the server and the latency of the
requests.
Using AST and skipping validations will reduce the amount of work the server has to do, so the
requests will have less latency.
Allowing arbitrary GraphQL operations
Sometimes it is handy to allow non-persisted operations aside from the persisted ones. E.g. you want
to allow developers to execute arbitrary GraphQL operations on your production server.
This can be achieved using the allowArbitraryOperations option.
import { createYoga, createSchema } from 'graphql-yoga'import { createServer } from 'node:http'import { usePersistedOperations } from '@graphql-yoga/plugin-persisted-operations'const store = { ecf4edb46db40b5132295c0291d62fb65d6759a9eedfa4d5d612dd5ec54a6b38: '{__typename}'}const yoga = createYoga({ schema: createSchema({ typeDefs: /* GraphQL */ ` type Query { hello: String! } ` }), plugins: [ usePersistedOperations({ extractPersistedOperationId(params: GraphqlParams & { doc_id?: unknown }) { return typeof params.doc_id === 'string' ? params.doc_id : null } getPersistedOperation(key: string) { return store[key] }, }), ],})const server = createServer(yoga)server.listen(4000, () => { console.info('Server is running on http://localhost:4000/graphql')})
Using an external Persisted Operation Store
As a project grows the amount of GraphQL Clients and GraphQL Operations can grow a lot. At some
point it might become impractible to store all persisted operations in memory.
In such a scenario you can use an external persisted operation store.
You can return a Promise from the getPersistedOperation function and call any database or
external service to retrieve the persisted operation.
Use external persisted operation store
import { createServer } from 'node:http'import { createYoga } from 'graphql-yoga'import { usePersistedOperations } from '@graphql-yoga/plugin-persisted-operations'const yoga = createYoga({ plugins: [ usePersistedOperations({ async getPersistedOperation(key: string) { return await fetch(`https://localhost:9999/document/${key}`).then(res => res.json()) } }) ]})const server = createServer(yoga)server.listen(4000, () => { console.info('Server is running on http://localhost:4000/graphql')})
Customize errors
This plugin can throw three different types of errors::
PersistedOperationNotFound: The persisted operation cannot be found.
PersistedOperationKeyNotFound: The persistence key cannot be extracted from the request.
PersistedOperationOnly: An arbitrary operation is rejected because only persisted operations are
allowed.
Each error can be customized to change the HTTP status or add a translation message ID, for example.
Customize errors
import { createServer } from 'node:http'import { createYoga } from 'graphql-yoga'import { usePersistedOperations } from '@graphql-yoga/plugin-persisted-operations'import { CustomErrorClass } from './custom-error-class'const yoga = createYoga({ plugins: [ usePersistedOperations({ customErrors: { // You can change the error message notFound: 'Not Found', // Or customize the error with a GraphqlError options object, allowing you to add extensions keyNotFound: { message: 'Key Not Found', extensions: { http: { status: 404 } } }, // Or customize with a factory function allowing you to use your own error class or format persistedQueryOnly: () => { return new CustomErrorClass('Only Persisted Operations are allowed') } } }) ]})const server = createServer(yoga)server.listen(4000, () => { console.info('Server is running on http://localhost:4000/graphql')})
This site uses cookies for analytics and improving your experience.