chore(docs): document subscription type (#593)

closes #157
This commit is contained in:
Jason Kuhrt 2020-11-02 09:41:05 -05:00 committed by GitHub
parent 9f01342248
commit 2de6f8971e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 188 additions and 9 deletions

View File

@ -0,0 +1,150 @@
---
title: subscriptionType
codeStyle: true
---
## subscriptionType
```ts
subscriptionType(typeName:string, fn: SubscriptionTypeConfig): NexusSubscriptionType
```
Create a GraphQL `Subscription` type.
A subscription type configuration field is like an object type with the following differences:
1. It has a `subscribe` field. You should return an async iterator here. This is called once for each subscription a client sends.
2. The `root` param of the `resolve` field is called for each promise returned by the async iterator setup. The resolver is responsible for transforming the shape of data returned by your subscription stream into types that conform to your GraphQL schema.
Here is a runnable example using Apollo Server and Apollo PubSub with Express.
```ts
import { ApolloServer, PubSub } from 'apollo-server-express'
import express from 'express'
import * as HTTP from 'http'
import * as path from 'path'
import {
arg,
inputObjectType,
makeSchema,
mutationType,
objectType,
subscriptionType,
} from '@nexus/schema'
const pubsub = new PubSub()
const schema = makeSchema({
shouldExitAfterGenerateArtifacts:
process.env.NEXUS_SHOULD_EXIT_AFTER_GENERATE_ARTIFACTS === 'true',
outputs: {
typegen: path.join(__dirname, 'node_modules/@types/nexus-typegen/index.d.ts'),
schema: path.join(__dirname, './api.graphql'),
},
types: [
mutationType({
definition(t) {
t.field('createOneUser', {
type: 'User',
args: {
data: arg({
required: true,
type: inputObjectType({
name: 'CreateOneUserInput',
definition(t) {
t.string('email', { required: true })
},
}),
}),
},
async resolve(_, args) {
const data = args.data
await pubsub.publish('user_added', { data })
return data
},
})
},
}),
subscriptionType({
definition(t) {
t.field('createOneUser', {
type: 'User',
subscribe() {
return pubsub.asyncIterator('user_added')
},
async resolve(userPromise) {
const user = await userPromise.data
return user
},
})
},
}),
objectType({
name: 'User',
definition(t) {
t.string('email')
},
}),
],
})
const apollo = new ApolloServer({ schema })
const app = express()
const http = HTTP.createServer(app)
apollo.applyMiddleware({ app })
apollo.installSubscriptionHandlers(http)
http.listen(4000, () => {
console.log(`🚀 GraphQL service ready at http://localhost:4000/graphql`)
})
```
Here is a runnable example with a minimalistic schema.
```ts
import { ApolloServer } from 'apollo-server-express'
import express from 'express'
import * as HTTP from 'http'
import * as path from 'path'
import { makeSchema, subscriptionType } from '@nexus/schema'
const schema = makeSchema({
shouldExitAfterGenerateArtifacts:
process.env.NEXUS_SHOULD_EXIT_AFTER_GENERATE_ARTIFACTS === 'true',
outputs: {
typegen: path.join(__dirname, 'node_modules/@types/nexus-typegen/index.d.ts'),
schema: path.join(__dirname, './api.graphql'),
},
types: [
subscriptionType({
definition(t) {
t.boolean('truths', {
subscribe() {
return (async function*() {
while (true) {
await new Promise(res => setTimeout(res, 1000))
yield Math.random() > 0.5
}
})()
},
resolve(eventData) {
return eventData
},
})
},
}),
],
})
const apollo = new ApolloServer({ schema })
const app = express()
const http = HTTP.createServer(app)
apollo.applyMiddleware({ app })
apollo.installSubscriptionHandlers(http)
http.listen(4000, () => {
console.log(`🚀 GraphQL service ready at http://localhost:4000/graphql`)
})
```

View File

@ -0,0 +1,29 @@
---
title: subscriptionField
codeStyle: true
---
## subscriptionField
Often times you want to split up subscription fields into different domains of your application.
Like `queryField` and `mutationField` except that like `subscriptionType` the `subscribe` field is required on the type configuration. Refer to [`subscriptionType`](/api/subscription-type) docs for details
```ts
import { subscriptionField } from '@nexus/schema'
export const SubscriptionField = subscriptionField('truths', {
type: 'Boolean',
subscribe() {
return (async function*() {
while (true) {
await new Promise(res => setTimeout(res, 1000))
yield Math.random() > 0.5
}
})()
},
resolve(eventData) {
return eventData
},
})
```

View File

@ -1,5 +1,5 @@
import { extendType } from './extendType'
import { SubscribeFieldConfig } from './subscriptionType'
import { SubscriptionTypeConfig } from './subscriptionType'
/**
* Add one field to the Subscription type
@ -7,8 +7,8 @@ import { SubscribeFieldConfig } from './subscriptionType'
export function subscriptionField<FieldName extends string>(
fieldName: FieldName,
config:
| SubscribeFieldConfig<'Subscription', FieldName>
| (() => SubscribeFieldConfig<'Subscription', FieldName>)
| SubscriptionTypeConfig<'Subscription', FieldName>
| (() => SubscriptionTypeConfig<'Subscription', FieldName>)
) {
return extendType({
type: 'Subscription',

View File

@ -1,12 +1,12 @@
import { GraphQLResolveInfo } from 'graphql'
import { ArgsValue, GetGen, MaybePromise, MaybePromiseDeep, ResultValue } from '../typegenTypeHelpers'
import { IsEqual } from '../utils'
import { BaseScalars } from './_types'
import { CommonOutputFieldConfig, NexusOutputFieldDef } from './definitionBlocks'
import { ObjectDefinitionBuilder, objectType } from './objectType'
import { AllNexusOutputTypeDefs } from './wrapping'
import { BaseScalars } from './_types'
export interface SubscribeFieldConfigBase<FieldName extends string, Event = any> {
export interface SubscriptionTypeConfigBase<FieldName extends string, Event = any> {
resolve(
root: Event,
args: ArgsValue<'Subscription', FieldName>,
@ -27,11 +27,11 @@ export interface SubscribeFieldConfigBase<FieldName extends string, Event = any>
// prettier-ignore
export type FieldShorthandConfig<FieldName extends string> =
CommonOutputFieldConfig<'Subscription', FieldName>
& SubscribeFieldConfigBase<FieldName>
& SubscriptionTypeConfigBase<FieldName>
// prettier-ignore
export interface SubscribeFieldConfig<TypeName extends string, FieldName extends string>
extends SubscribeFieldConfigBase<FieldName>,
export interface SubscriptionTypeConfig<TypeName extends string, FieldName extends string>
extends SubscriptionTypeConfigBase<FieldName>,
CommonOutputFieldConfig<'Subscription', FieldName>
{
type: GetGen<'allOutputTypes'> | AllNexusOutputTypeDefs
@ -71,7 +71,7 @@ export class SubscriptionBuilder {
}
// prettier-ignore
field<FieldName extends string>(name: FieldName, fieldConfig: SubscribeFieldConfig<'Subscription', FieldName>) {
field<FieldName extends string>(name: FieldName, fieldConfig: SubscriptionTypeConfig<'Subscription', FieldName>) {
this.typeBuilder.addField(this.decorateField({ name, ...fieldConfig } as any))
}