GraphQL Yoga v3 documentation (superseded by v5): Migrate from Yoga V1 to Yoga V2. Learn about the new features and how to upgrade.
Installation
You can start with updating graphql-yoga package.
npm i graphql-yoga
yarn add graphql-yoga
pnpm add graphql-yoga
bun add graphql-yoga
Server setup
Yoga v1 no longer uses a class for constructing the server, the createYoga function is now used.
Also the typeDefs and resolvers config options must now be passed to a schema property with
createSchema.
Yoga v1
import { GraphQLServer } from 'graphql-yoga'import { resolvers, typeDefs } from './schema'const server = new GraphQLServer({ typeDefs, resolvers })server.start()
Yoga v3
import { createServer } from 'http'import { createSchema, createYoga } from 'graphql-yoga'import { resolvers, typeDefs } from './schema'const yoga = createYoga({ schema: createSchema({ typeDefs, resolvers })})const server = createServer(yoga)server.listen(4000, () => { console.info('Server is running on http://localhost:4000/graphql')})
Load type definitions from a file
In Yoga v1 it was possible to provide a file path for the typeDefs.
Yoga v1
import * as path from 'path'import { GraphQLServer } from 'graphql-yoga'import { resolvers } from './schema'const server = new GraphQLServer({ typeDefs: path.join(__dirname, 'type-definitions.graphql'), resolvers})server.start()
In Yoga v3 you now need to use the fs module for Node.js.
Yoga v3
import * as fs from 'fs'import { createServer } from 'http'import * as path from 'path'import { createSchema, createYoga } from 'graphql-yoga'import { resolvers } from './schema'const yoga = createYoga({ schema: createSchema({ typeDefs: fs.readFileSync(path.join(__dirname, 'type-definitions.graphql'), 'utf-8'), resolvers })})const server = createServer(yoga)server.listen(4000, () => { console.info('Server is running on http://localhost:4000/graphql')})
import { GraphQLServer } from 'graphql-yoga'import { resolvers } from './schema'import { uppercaseDirectiveResolverImplementation } from './uppercase-directive-resolver-implementation'const server = new GraphQLServer({ typeDefs: /* GraphQL */ ` type Query { hi: String } `, directiveResolvers: uppercaseDirectiveResolverImplementation})server.start()
Before deciding upon using schema directives, you should consider whether your custom directive
could be instead implemented via a field argument (abstraction).
In Yoga v3 you have to leverage the mapSchema API from graphql-tools.
npm i @graphql-tools/utils
yarn add @graphql-tools/utils
pnpm add @graphql-tools/utils
bun add @graphql-tools/utils
npm i @graphql-tools/schema
yarn add @graphql-tools/schema
pnpm add @graphql-tools/schema
bun add @graphql-tools/schema
Yoga v3
import { createServer } from 'http'import { defaultFieldResolver } from 'graphql'import { createYoga, Plugin } from 'graphql-yoga'import { makeExecutableSchema } from '@graphql-tools/schema'import { getDirective, MapperKind, mapSchema } from '@graphql-tools/utils'import { resolvers, typeDefs } from './schema'let schema = makeExecutableSchema({ typeDefs: [ typeDefs, /* GraphQL */ ` directive @uppercase on FIELD_DEFINITION ` ], resolvers})schema = mapSchema(schema, { [MapperKind.OBJECT_FIELD]: fieldConfig => { const upperDirective = getDirective(schema, fieldConfig, 'uppercase')?.[0] if (upperDirective) { const { resolve = defaultFieldResolver } = fieldConfig return { ...fieldConfig, resolve: async function (source, args, context, info) { const result = await resolve(source, args, context, info) if (typeof result === 'string') { return result.toUpperCase() } return result } } } }})const yoga = createYoga({ schema })
In GraphQL Yoga v2 you can use the context property in the same way as GraphQL Yoga v1. The value
returned from the context factory will be merged with the initial context.
The request property within the initial context is now a
Fetch API Request. It can be used for
accessing all the HTTP request parameters, such as headers or
the method (POST, GET).
import { GraphQLServer } from 'graphql-yoga'import { db } from './db'import { resolvers, typeDefs } from './schema'const server = new GraphQLServer({ typeDefs, resolvers, context(initialContext) { const authHeader = initialContext.request.headers['authorization'] ?? null return { ...initialContext, db, authHeader } }})const server = createServer(yoga)server.listen(4000, () => { console.info('Server is running on http://localhost:4000/graphql')})
Yoga v3
import { createServer } from 'http'import { createSchema, createYoga } from 'graphql-yoga'import { db } from './db'import { resolvers, typeDefs } from './schema'const yoga = createYoga({ schema: createSchema({ typeDefs, resolvers }), context(initialContext) { const authHeader = initialContext.request.headers.get('authorization') ?? null return { db, authHeader } }})const server = createServer(yoga)server.listen(4000, () => { console.info('Server is running on http://localhost:4000/graphql')})
Middlewares
GraphQL Yoga v1 included graphql-middleware for
wrapping resolver functions with common logic. GraphQL Yoga v2 no longer includes
graphql-middleware by default as using it can result in bad performance as it wraps all field
resolvers within the schema.
Because of the protocol change you must migrate your GraphQL clients that execute GraphQL
subscription operations to use the new protocol. Please use the code snippets for your GraphQL
client as listed on the
handle subscription on the client documentation.
Advantages of SSE over Websockets
Transported over simple HTTP instead of a custom protocol
Built in support for re-connection and event-id Simpler protocol
No trouble with corporate firewalls doing packet inspection
With GraphQL Yoga v1 used the unmaintained package graphql-subscriptions for the PubSub
implementation. In GraphQL Yoga v2+, a new maintained PubSub implementation is built-in.
Yoga v1
import { PubSub } from 'graphql-yoga'const pubSub = new PubSub()
Yoga v2
import { createPubSub } from 'graphql-yoga'const pubSub = createPubSub()
Type-safe PubSub Usage
The old PubSub implementation was not type-safe. Now it is possible to define all the events and
payloads. For a full reference please check out the
Subscription PubSub documentation.
Yoga v1
import { GraphQLServer, PubSub } from 'graphql-yoga'const pubSub = new PubSub()const server = new GraphQLServer({ context: { pubSub }, typeDefs: /* GraphQL */ ` type Query { _: Boolean } type Subscription { randomNumber: Int! } type Mutation { publishRandomNumber(randomNumber: Int!): Boolean } `, resolvers: { Subscription: { randomNumber: { subscribe: (_, _2, context) => { return context.asyncIterator('randomNumber') }, resolve: value => value } }, Mutation: { publishRandomNumber: (_, args, context) => { context.pubSub.publish('randomNumber', args.randomNumber) } } }})server.start()
Yoga v3
import { createServer } from 'http'import { createPubSub, createSchema, createYoga } from 'graphql-yoga'const pubSub = new PubSub<{ randomNumber: [randomNumber: number]}>()const yoga = createYoga({ context: { pubSub }, schema: createSchema({ typeDefs: /* GraphQL */ ` type Query { _: Boolean } type Subscription { randomNumber: Int! } type Mutation { publishRandomNumber(randomNumber: Int!): Boolean } `, resolvers: { Subscription: { randomNumber: { subscribe: (_, _2, context) => { return context.subscribe('randomNumber') }, resolve: value => value } }, Mutation: { publishRandomNumber: (_, args, context) => { context.pubSub.publish('randomNumber', args.randomNumber) } } } })})const server = createServer(yoga)server.listen(4000, () => { console.info('Server is running on http://localhost:4000/graphql')})
Filtering events
Instead of the withFilter function you can now use the more modular pipe and filter functions
exported from graphql-yoga. You can learn more about filtering and mapping values in the
subscription filter and map values documentation.
Yoga v1
import { GraphQLServer, PubSub, withFilter } from 'graphql-yoga'const pubSub = new PubSub()const server = new GraphQLServer({ context: { pubSub }, typeDefs: /* GraphQL */ ` type Query { _: Boolean } type Subscription { randomNumber(greaterThan: Int!): Int! } type Mutation { publishRandomNumber(randomNumber: Int!): Boolean } `, resolvers: { Subscription: { randomNumber: { subscribe: withFilter( (_, _2, context) => { return context.asyncIterator('randomNumber') }, (payload, args) => payload > args ), resolve: value => value } }, Mutation: { publishRandomNumber: (_, args, context) => { context.pubSub.publish('randomNumber', args.randomNumber) } } }})server.start()
Yoga v3
import { createServer } from 'http'import { createPubSub, createYoga, filter, pipe } from 'graphql-yoga'const pubSub = new PubSub<{ randomNumber: [randomNumber: number]}>()const yoga = createYoga({ context: { pubSub }, schema: createSchema({ typeDefs: /* GraphQL */ ` type Query { _: Boolean } type Subscription { randomNumber(greaterThan: Int!): Int! } type Mutation { publishRandomNumber(randomNumber: Int!): Boolean } `, resolvers: { Subscription: { randomNumber: { subscribe: (_, args, context) => { return pipe( context.subscribe('randomNumber'), filter(value => value > args.greaterThan) ) }, resolve: value => value } }, Mutation: { publishRandomNumber: (_, args, context) => { context.pubSub.publish('randomNumber', args.randomNumber) } } } })})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.