-
Notifications
You must be signed in to change notification settings - Fork 1k
/
Copy pathgraphql.ts
138 lines (117 loc) · 4.23 KB
/
graphql.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import fastifyUrlData from '@fastify/url-data'
import fg from 'fast-glob'
import type {
FastifyInstance,
HTTPMethods,
HookHandlerDoneFunction,
FastifyReply,
FastifyRequest,
} from 'fastify'
import fastifyRawBody from 'fastify-raw-body'
import type { Plugin } from 'graphql-yoga'
import { createGraphQLYoga } from '@redwoodjs/graphql-server'
import type { GraphQLYogaOptions } from '@redwoodjs/graphql-server'
import { getPaths } from '@redwoodjs/project-config'
/**
* Transform a Fastify Request to an event compatible with the RedwoodGraphQLContext's event
* which is based on the AWS Lambda event
*/
import { lambdaEventForFastifyRequest } from '../requestHandlers/awsLambdaFastify'
export interface RedwoodFastifyGraphQLOptions {
redwood: {
apiRootPath: string
graphql?: GraphQLYogaOptions
}
}
/**
* Redwood GraphQL Server Fastify plugin based on GraphQL Yoga
*
* @param {FastifyInstance} fastify Encapsulated Fastify Instance
* @param {GraphQLYogaOptions} options GraphQLYogaOptions options used to configure the GraphQL Yoga Server
*/
export async function redwoodFastifyGraphQLServer(
fastify: FastifyInstance,
options: RedwoodFastifyGraphQLOptions,
done: HookHandlerDoneFunction
) {
// These two plugins are needed to transform a Fastify Request to a Lambda event
// which is used by the RedwoodGraphQLContext and mimics the behavior of the
// api-server withFunction plugin
if (!fastify.hasPlugin('@fastify/url-data')) {
await fastify.register(fastifyUrlData)
}
await fastify.register(fastifyRawBody)
try {
const method = ['GET', 'POST', 'OPTIONS'] as HTTPMethods[]
// Load the graphql options from the graphql function if none are explicitly provided
if (!options.redwood.graphql) {
const [graphqlFunctionPath] = await fg('dist/functions/graphql.{ts,js}', {
cwd: getPaths().api.base,
absolute: true,
})
const { __rw_graphqlOptions } = await import(graphqlFunctionPath)
options.redwood.graphql = __rw_graphqlOptions as GraphQLYogaOptions
}
const graphqlOptions = options.redwood.graphql
// Here we can add any plugins that we want to use with GraphQL Yoga Server
// that we do not want to add the the GraphQLHandler in the graphql-server
// graphql function.
//
// These would be plugins that need a server instance such as Redwood Realtime
if (graphqlOptions.realtime) {
const { useRedwoodRealtime } = await import('@redwoodjs/realtime')
const originalExtraPlugins: Array<Plugin<any>> =
graphqlOptions.extraPlugins || []
originalExtraPlugins.push(useRedwoodRealtime(graphqlOptions.realtime))
graphqlOptions.extraPlugins = originalExtraPlugins
// uses for SSE single connection mode with the `/graphql/stream` endpoint
if (graphqlOptions.realtime.subscriptions) {
method.push('PUT')
}
}
const { yoga } = createGraphQLYoga(graphqlOptions)
const graphQLYogaHandler = async (
req: FastifyRequest,
reply: FastifyReply
) => {
const response = await yoga.handleNodeRequest(req, {
req,
reply,
event: lambdaEventForFastifyRequest(req),
requestContext: {},
})
for (const [name, value] of response.headers) {
reply.header(name, value)
}
reply.status(response.status)
reply.send(response.body)
return reply
}
const routePaths = ['', '/health', '/readiness', '/stream']
for (const routePath of routePaths) {
fastify.route({
url: `${options.redwood.apiRootPath}${formatGraphQLEndpoint(
yoga.graphqlEndpoint
)}${routePath}`,
method,
handler: async (req, reply) => await graphQLYogaHandler(req, reply),
})
}
fastify.addHook('onReady', (done) => {
console.info(`GraphQL Yoga Server endpoint at ${yoga.graphqlEndpoint}`)
console.info(
`GraphQL Yoga Server Health Check endpoint at ${yoga.graphqlEndpoint}/health`
)
console.info(
`GraphQL Yoga Server Readiness endpoint at ${yoga.graphqlEndpoint}/readiness`
)
done()
})
done()
} catch (e) {
console.log(e)
}
}
function formatGraphQLEndpoint(endpoint: string) {
return endpoint.replace(/^\//, '').replace(/\/$/, '')
}