Access ctx in resolve (#13)

* feat(ctx): access ctx in resolvers
* fix(typo): fix typo
pull/29/head
Minghe 2022-08-01 22:06:46 +08:00 committed by GitHub
parent ce086cba19
commit 1a31ccfe41
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 86 additions and 37 deletions

View File

@ -6,7 +6,9 @@ import {
GraphQLNonNull,
} from 'graphql'
import { Hono } from 'hono'
import type { Context, Next } from 'hono'
import { errorMessages, graphqlServer } from '.'
import type { RootResolver } from './index'
// Do not show `console.error` messages
jest.spyOn(console, 'error').mockImplementation()
@ -26,14 +28,13 @@ describe('errorMessages', () => {
})
describe('GraphQL Middleware - Simple way', () => {
// Construct a schema, using GraphQL schema language
it('Should return GraphQL response', async () => {
const schema = buildSchema(`
type Query {
hello: String
}
`)
`)
// The root provides a resolver function for each API endpoint
const rootValue = {
hello: () => 'Hello world!',
}
@ -44,7 +45,7 @@ describe('GraphQL Middleware - Simple way', () => {
'/graphql',
graphqlServer({
schema,
rootValue,
rootResolver: () => rootValue,
})
)
@ -53,7 +54,6 @@ describe('GraphQL Middleware - Simple way', () => {
return c.text('fallback')
})
it('Should return GraphQL response', async () => {
const query = 'query { hello }'
const body = {
query: query,
@ -71,6 +71,59 @@ describe('GraphQL Middleware - Simple way', () => {
expect(await res.text()).toBe('{"data":{"hello":"Hello world!"}}')
expect(res.headers.get('foo')).toBeNull() // GraphQL Server middleware should be Handler
})
it('Should access the ctx', async () => {
const schema = buildSchema(`
type Query {
hi: String
}
`)
const rootResolver: RootResolver = (ctx?: Context) => {
const name = ctx?.get('name')
return {
hi: `hi ${name}`
}
}
const app = new Hono()
app.use('*', async (ctx: Context, next: Next) => {
ctx.set('name', 'Jason')
await next()
})
app.use(
'/graphql',
graphqlServer({
schema,
rootResolver,
})
)
app.all('*', (c) => {
c.header('foo', 'bar')
return c.text('fallback')
})
const query = 'query { hi }'
const body = {
query: query,
}
const res = await app.request('http://localhost/graphql', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
})
expect(res).not.toBeNull()
expect(res.status).toBe(200)
expect(await res.text()).toBe('{"data":{"hi":"hi Jason"}}')
expect(res.headers.get('foo')).toBeNull() // GraphQL Server middleware should be Handler
})
})
const QueryRootType = new GraphQLObjectType({

View File

@ -1,6 +1,3 @@
// Based on the code in the `express-graphql` package.
// https://github.com/graphql/express-graphql/blob/main/src/index.ts
import {
Source,
parse,
@ -21,12 +18,13 @@ import type {
} from 'graphql'
import type { Context } from 'hono'
import type { Next } from 'hono'
import { parseBody } from './parse-body'
export type RootResolver = (ctx?: Context) => Promise<unknown> | unknown
type Options = {
schema: GraphQLSchema
rootValue?: unknown
rootResolver?: RootResolver,
pretty?: boolean
validationRules?: ReadonlyArray<ValidationRule>
// graphiql?: boolean
@ -34,12 +32,11 @@ type Options = {
export const graphqlServer = (options: Options) => {
const schema = options.schema
const rootValue = options.rootValue
const pretty = options.pretty ?? false
const validationRules = options.validationRules ?? []
// const showGraphiQL = options.graphiql ?? false
return async (c: Context, next: Next) => {
return async (c: Context) => {
// GraphQL HTTP only supports GET and POST methods.
if (c.req.method !== 'GET' && c.req.method !== 'POST') {
return c.json(errorMessages(['GraphQL only supports GET and POST requests.']), 405, {
@ -119,12 +116,13 @@ export const graphqlServer = (options: Options) => {
}
let result: FormattedExecutionResult
const { rootResolver } = options
try {
result = await execute({
schema,
document: documentAST,
rootValue,
rootValue: rootResolver ? await rootResolver(c) : null,
variableValues: variables,
operationName: operationName,
})
@ -161,8 +159,6 @@ export const graphqlServer = (options: Options) => {
} else {
return c.json(result)
}
await next() // XXX
}
}