1
- import { HttpStatus } from '@nestjs/common' ;
2
1
import { loadPackage } from '@nestjs/common/utils/load-package.util' ;
3
2
import { isFunction } from '@nestjs/common/utils/shared.utils' ;
4
3
import { AbstractGraphQLDriver } from '@nestjs/graphql' ;
5
- import {
6
- ApolloError ,
7
- ApolloServerBase ,
8
- ApolloServerPluginLandingPageDisabled ,
9
- ApolloServerPluginLandingPageGraphQLPlayground ,
10
- AuthenticationError ,
11
- ForbiddenError ,
12
- PluginDefinition ,
13
- UserInputError ,
14
- } from 'apollo-server-core' ;
4
+
15
5
import { GraphQLError , GraphQLFormattedError } from 'graphql' ;
16
6
import * as omit from 'lodash.omit' ;
17
7
import { ApolloDriverConfig } from '../interfaces' ;
18
8
import { createAsyncIterator } from '../utils/async-iterator.util' ;
19
9
20
- const apolloPredefinedExceptions : Partial <
21
- Record < HttpStatus , typeof ApolloError | typeof UserInputError >
22
- > = {
23
- [ HttpStatus . BAD_REQUEST ] : UserInputError ,
24
- [ HttpStatus . UNAUTHORIZED ] : AuthenticationError ,
25
- [ HttpStatus . FORBIDDEN ] : ForbiddenError ,
10
+ import { ApolloServer , type BaseContext } from '@apollo/server' ;
11
+ import { ApolloServerErrorCode } from '@apollo/server/errors' ;
12
+ import { expressMiddleware } from '@apollo/server/express4' ;
13
+ import { ApolloServerPluginLandingPageLocalDefault } from '@apollo/server/plugin/landingPage/default' ;
14
+ import * as express from 'express' ;
15
+ import * as http from 'node:http' ;
16
+
17
+ import { fastifyApolloHandler } from '@as-integrations/fastify' ;
18
+ import { HttpStatus } from '@nestjs/common' ;
19
+
20
+ const apolloPredefinedExceptions : Partial < Record < HttpStatus , string > > = {
21
+ [ HttpStatus . BAD_REQUEST ] : ApolloServerErrorCode . BAD_USER_INPUT ,
22
+ [ HttpStatus . UNAUTHORIZED ] : 'UNAUTHENTICATED' ,
23
+ [ HttpStatus . FORBIDDEN ] : 'FORBIDDEN' ,
26
24
} ;
27
25
28
26
export abstract class ApolloBaseDriver <
29
27
T extends Record < string , any > = ApolloDriverConfig ,
30
28
> extends AbstractGraphQLDriver < T > {
31
- protected _apolloServer : ApolloServerBase ;
29
+ protected apolloServer : ApolloServer < BaseContext > ;
32
30
33
- get instance ( ) : ApolloServerBase {
34
- return this . _apolloServer ;
31
+ get instance ( ) : ApolloServer < BaseContext > {
32
+ return this . apolloServer ;
35
33
}
36
34
37
35
public async start ( apolloOptions : T ) {
@@ -48,7 +46,7 @@ export abstract class ApolloBaseDriver<
48
46
}
49
47
50
48
public stop ( ) {
51
- return this . _apolloServer ?. stop ( ) ;
49
+ return this . apolloServer ?. stop ( ) ;
52
50
}
53
51
54
52
public async mergeDefaultOptions ( options : T ) : Promise < T > {
@@ -67,11 +65,7 @@ export abstract class ApolloBaseDriver<
67
65
typeof options . playground === 'object' ? options . playground : undefined ;
68
66
defaults = {
69
67
...defaults ,
70
- plugins : [
71
- ApolloServerPluginLandingPageGraphQLPlayground (
72
- playgroundOptions ,
73
- ) as PluginDefinition ,
74
- ] ,
68
+ plugins : [ ApolloServerPluginLandingPageLocalDefault ( playgroundOptions ) ] ,
75
69
} ;
76
70
} else if (
77
71
( options . playground === undefined &&
@@ -80,7 +74,7 @@ export abstract class ApolloBaseDriver<
80
74
) {
81
75
defaults = {
82
76
...defaults ,
83
- plugins : [ ApolloServerPluginLandingPageDisabled ( ) as PluginDefinition ] ,
77
+ plugins : [ ApolloServerPluginLandingPageLocalDefault ( ) ] ,
84
78
} ;
85
79
}
86
80
@@ -115,68 +109,79 @@ export abstract class ApolloBaseDriver<
115
109
) ;
116
110
}
117
111
118
- protected async registerExpress (
119
- apolloOptions : T ,
120
- { preStartHook } : { preStartHook ?: ( ) => void } = { } ,
121
- ) {
122
- const { ApolloServer } = loadPackage (
123
- 'apollo-server-express' ,
124
- 'GraphQLModule' ,
125
- ( ) => require ( 'apollo-server-express' ) ,
126
- ) ;
127
- const { disableHealthCheck, path, onHealthCheck, cors, bodyParserConfig } =
128
- apolloOptions ;
112
+ protected async registerExpress ( options : T , hooks ?: any ) {
113
+ if ( hooks ?. preStartHook ) {
114
+ hooks ?. preStartHook ( ) ;
115
+ }
116
+
117
+ const cors = loadPackage ( 'cors' , null , ( ) => require ( 'cors' ) ) ;
118
+
119
+ const { path, typeDefs, resolvers, schema } = options ;
129
120
130
121
const httpAdapter = this . httpAdapterHost . httpAdapter ;
131
122
const app = httpAdapter . getInstance ( ) ;
123
+ const httpServer = http . createServer ( app ) ;
132
124
133
- preStartHook ?.( ) ;
125
+ // Set up Apollo Server
126
+ const server = new ApolloServer ( {
127
+ typeDefs,
128
+ resolvers,
129
+ schema,
130
+ ...options ,
131
+ /**
132
+ * @TODO
133
+ * should remove serverWillStart from default plugins.
134
+ * after include plugins here
135
+ */
136
+ // TODO: fix - dont override plugins
137
+ // plugins: [ApolloServerPluginDrainHttpServer({ httpServer })],
138
+ } ) ;
134
139
135
- const apolloServer = new ApolloServer ( apolloOptions as any ) ;
136
- await apolloServer . start ( ) ;
140
+ await server . start ( ) ;
137
141
138
- apolloServer . applyMiddleware ( {
139
- app,
142
+ app . use (
140
143
path ,
141
- disableHealthCheck,
142
- onHealthCheck,
143
- cors,
144
- bodyParserConfig,
145
- } ) ;
144
+ cors ( options . cors ) ,
145
+ express . json ( ) ,
146
+ expressMiddleware ( server ) ,
147
+ ) ;
146
148
147
- this . _apolloServer = apolloServer ;
149
+ this . apolloServer = server ;
148
150
}
149
151
150
- protected async registerFastify (
151
- apolloOptions : T ,
152
- { preStartHook } : { preStartHook ?: ( ) => void } = { } ,
153
- ) {
154
- const { ApolloServer } = loadPackage (
155
- 'apollo-server-fastify' ,
156
- 'GraphQLModule' ,
157
- ( ) => require ( 'apollo-server-fastify' ) ,
152
+ protected async registerFastify ( options : T , hooks ?: any ) {
153
+ if ( hooks ?. preStartHook ) {
154
+ hooks ?. preStartHook ( ) ;
155
+ }
156
+
157
+ const cors = loadPackage ( '@fastify/cors' , null , ( ) =>
158
+ require ( '@fastify/cors' ) ,
158
159
) ;
159
160
160
161
const httpAdapter = this . httpAdapterHost . httpAdapter ;
161
162
const app = httpAdapter . getInstance ( ) ;
162
163
163
- preStartHook ?.( ) ;
164
- const apolloServer = new ApolloServer ( apolloOptions as any ) ;
165
- await apolloServer . start ( ) ;
166
-
167
- const { disableHealthCheck, onHealthCheck, cors, bodyParserConfig, path } =
168
- apolloOptions ;
169
- await app . register (
170
- apolloServer . createHandler ( {
171
- disableHealthCheck,
172
- onHealthCheck,
173
- cors,
174
- bodyParserConfig,
175
- path,
176
- } ) ,
177
- ) ;
164
+ const { path, typeDefs, resolvers, schema } = options ;
165
+ const server = new ApolloServer < BaseContext > ( {
166
+ typeDefs,
167
+ resolvers,
168
+ schema,
169
+ ...options ,
170
+ // TODO: fix - dont override plugin
171
+ //plugins: [fastifyApolloDrainPlugin(app)],
172
+ } ) ;
178
173
179
- this . _apolloServer = apolloServer ;
174
+ await server . start ( ) ;
175
+
176
+ app . route ( {
177
+ url : path ,
178
+ method : [ 'GET' , 'POST' , 'OPTIONS' ] ,
179
+ handler : fastifyApolloHandler ( server ) ,
180
+ } ) ;
181
+
182
+ await app . register ( cors , options . cors ) ;
183
+
184
+ this . apolloServer = server ;
180
185
}
181
186
182
187
private wrapFormatErrorFn ( options : T ) {
@@ -201,22 +206,26 @@ export abstract class ApolloBaseDriver<
201
206
const exceptionRef = originalError ?. extensions ?. exception ;
202
207
const isHttpException =
203
208
exceptionRef ?. response ?. statusCode && exceptionRef ?. status ;
204
-
205
209
if ( ! isHttpException ) {
206
210
return originalError as GraphQLFormattedError ;
207
211
}
208
- let error : ApolloError ;
212
+ let error : GraphQLError ;
209
213
210
214
const httpStatus = exceptionRef ?. status ;
211
215
if ( httpStatus in apolloPredefinedExceptions ) {
212
- error = new apolloPredefinedExceptions [ httpStatus ] (
213
- exceptionRef ?. message ,
214
- ) ;
216
+ error = new GraphQLError ( exceptionRef ?. message , {
217
+ extensions : {
218
+ code : apolloPredefinedExceptions [ httpStatus ] ,
219
+ } ,
220
+ } ) ;
215
221
} else {
216
- error = new ApolloError ( exceptionRef . message , httpStatus ?. toString ( ) ) ;
222
+ error = new GraphQLError ( exceptionRef . message , httpStatus ?. toString ( ) ) ;
217
223
}
218
224
219
225
error . stack = exceptionRef ?. stacktrace ;
226
+ //TODO: we need to verify if previous behavior is to be kept
227
+ // if so we must open a PR on Apollo to include response inside the raised exception
228
+ //https://github.com/apollographql/apollo-server/blob/e6d0d6d9cbd78d4914adf2abb04d84710991849a/packages/server/src/errorNormalize.ts#L58
220
229
error . extensions [ 'response' ] = exceptionRef ?. response ;
221
230
return error ;
222
231
} ;
0 commit comments