Skip to content

Commit 1dc229a

Browse files
Merge pull request #2636 from nestjs/next
feat: upgrade Mercurius, Apollo, GraphQL to the latest versions
2 parents 3d5af0c + e667c69 commit 1dc229a

File tree

117 files changed

+5320
-4200
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

117 files changed

+5320
-4200
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,6 @@ test-schema.graphql
1919

2020
# dist
2121
packages/**/dist
22-
**/*.tsbuildinfo
22+
**/*.tsbuildinfo
23+
24+
.yarn/

lerna.json

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
{
2-
"packages": [
3-
"packages/*"
4-
],
5-
"version": "10.2.0",
2+
"packages": ["packages/*"],
3+
"version": "11.0.0-next.2",
64
"npmClient": "yarn",
75
"useWorkspaces": true,
86
"changelog": {

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
"prepare": "husky install"
2727
},
2828
"resolutions": {
29-
"graphql": "15.8.0"
29+
"graphql": "16.6.0"
3030
},
3131
"devDependencies": {
3232
"@commitlint/cli": "17.4.4",
@@ -45,7 +45,7 @@
4545
"eslint-config-prettier": "8.7.0",
4646
"eslint-plugin-import": "2.27.5",
4747
"eslint-plugin-prettier": "4.2.1",
48-
"graphql": "15.8.0",
48+
"graphql": "16.6.0",
4949
"graphql-subscriptions": "2.0.0",
5050
"husky": "8.0.3",
5151
"jest": "29.5.0",
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './apollo.constants';

packages/apollo/lib/decorators/plugin.decorator.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { SetMetadata } from '@nestjs/common';
2-
import { PLUGIN_METADATA } from '../apollo.constants';
2+
import { PLUGIN_METADATA } from '../constants';
33

44
/**
55
* Decorator that marks a class as an Apollo plugin.

packages/apollo/lib/drivers/apollo-base.driver.ts

Lines changed: 90 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,31 @@
1+
import { ApolloServer, type BaseContext } from '@apollo/server';
2+
import { ApolloServerPluginLandingPageGraphQLPlayground } from '@apollo/server-plugin-landing-page-graphql-playground';
3+
import { ApolloServerErrorCode } from '@apollo/server/errors';
4+
import { expressMiddleware } from '@apollo/server/express4';
5+
import { ApolloServerPluginLandingPageDisabled } from '@apollo/server/plugin/disabled';
6+
import { ApolloServerPluginDrainHttpServer } from '@apollo/server/plugin/drainHttpServer';
17
import { HttpStatus } from '@nestjs/common';
28
import { loadPackage } from '@nestjs/common/utils/load-package.util';
39
import { isFunction } from '@nestjs/common/utils/shared.utils';
410
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';
1511
import { GraphQLError, GraphQLFormattedError } from 'graphql';
1612
import * as omit from 'lodash.omit';
1713
import { ApolloDriverConfig } from '../interfaces';
1814
import { createAsyncIterator } from '../utils/async-iterator.util';
1915

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,
16+
const apolloPredefinedExceptions: Partial<Record<HttpStatus, string>> = {
17+
[HttpStatus.BAD_REQUEST]: ApolloServerErrorCode.BAD_REQUEST,
18+
[HttpStatus.UNAUTHORIZED]: 'UNAUTHENTICATED',
19+
[HttpStatus.FORBIDDEN]: 'FORBIDDEN',
2620
};
2721

2822
export abstract class ApolloBaseDriver<
2923
T extends Record<string, any> = ApolloDriverConfig,
3024
> extends AbstractGraphQLDriver<T> {
31-
protected _apolloServer: ApolloServerBase;
25+
protected apolloServer: ApolloServer<BaseContext>;
3226

33-
get instance(): ApolloServerBase {
34-
return this._apolloServer;
27+
get instance(): ApolloServer<BaseContext> {
28+
return this.apolloServer;
3529
}
3630

3731
public async start(apolloOptions: T) {
@@ -48,7 +42,7 @@ export abstract class ApolloBaseDriver<
4842
}
4943

5044
public stop() {
51-
return this._apolloServer?.stop();
45+
return this.apolloServer?.stop();
5246
}
5347

5448
public async mergeDefaultOptions(options: T): Promise<T> {
@@ -68,9 +62,7 @@ export abstract class ApolloBaseDriver<
6862
defaults = {
6963
...defaults,
7064
plugins: [
71-
ApolloServerPluginLandingPageGraphQLPlayground(
72-
playgroundOptions,
73-
) as PluginDefinition,
65+
ApolloServerPluginLandingPageGraphQLPlayground(playgroundOptions),
7466
],
7567
};
7668
} else if (
@@ -80,7 +72,7 @@ export abstract class ApolloBaseDriver<
8072
) {
8173
defaults = {
8274
...defaults,
83-
plugins: [ApolloServerPluginLandingPageDisabled() as PluginDefinition],
75+
plugins: [ApolloServerPluginLandingPageDisabled()],
8476
};
8577
}
8678

@@ -116,67 +108,80 @@ export abstract class ApolloBaseDriver<
116108
}
117109

118110
protected async registerExpress(
119-
apolloOptions: T,
111+
options: T,
120112
{ preStartHook }: { preStartHook?: () => void } = {},
121113
) {
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;
114+
const { path, typeDefs, resolvers, schema } = options;
129115

130116
const httpAdapter = this.httpAdapterHost.httpAdapter;
131117
const app = httpAdapter.getInstance();
118+
const drainHttpServerPlugin = ApolloServerPluginDrainHttpServer({
119+
httpServer: httpAdapter.getHttpServer(),
120+
});
132121

133122
preStartHook?.();
134123

135-
const apolloServer = new ApolloServer(apolloOptions as any);
136-
await apolloServer.start();
124+
const server = new ApolloServer({
125+
typeDefs,
126+
resolvers,
127+
schema,
128+
...options,
129+
plugins: options.plugins
130+
? options.plugins.concat([drainHttpServerPlugin])
131+
: [drainHttpServerPlugin],
132+
});
133+
134+
await server.start();
137135

138-
apolloServer.applyMiddleware({
139-
app,
136+
app.use(
140137
path,
141-
disableHealthCheck,
142-
onHealthCheck,
143-
cors,
144-
bodyParserConfig,
145-
});
138+
expressMiddleware(server, {
139+
context: options.context,
140+
}),
141+
);
146142

147-
this._apolloServer = apolloServer;
143+
this.apolloServer = server;
148144
}
149145

150146
protected async registerFastify(
151-
apolloOptions: T,
147+
options: T,
152148
{ preStartHook }: { preStartHook?: () => void } = {},
153149
) {
154-
const { ApolloServer } = loadPackage(
155-
'apollo-server-fastify',
150+
const { fastifyApolloDrainPlugin, fastifyApolloHandler } = loadPackage(
151+
'@as-integrations/fastify',
156152
'GraphQLModule',
157-
() => require('apollo-server-fastify'),
153+
() => require('@as-integrations/fastify'),
158154
);
159155

160156
const httpAdapter = this.httpAdapterHost.httpAdapter;
161157
const app = httpAdapter.getInstance();
162158

159+
const { path, typeDefs, resolvers, schema } = options;
160+
const apolloDrainPlugin = fastifyApolloDrainPlugin(app);
161+
163162
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,
163+
164+
const server = new ApolloServer<BaseContext>({
165+
typeDefs,
166+
resolvers,
167+
schema,
168+
...options,
169+
plugins: options.plugins
170+
? options.plugins.concat([apolloDrainPlugin])
171+
: [apolloDrainPlugin],
172+
});
173+
174+
await server.start();
175+
176+
app.route({
177+
url: path,
178+
method: ['GET', 'POST', 'OPTIONS'],
179+
handler: fastifyApolloHandler(server, {
180+
context: options.context,
176181
}),
177-
);
182+
});
178183

179-
this._apolloServer = apolloServer;
184+
this.apolloServer = server;
180185
}
181186

182187
private wrapFormatErrorFn(options: T) {
@@ -201,19 +206,25 @@ export abstract class ApolloBaseDriver<
201206
const exceptionRef = originalError?.extensions?.exception;
202207
const isHttpException =
203208
exceptionRef?.response?.statusCode && exceptionRef?.status;
204-
205209
if (!isHttpException) {
206210
return originalError as GraphQLFormattedError;
207211
}
208-
let error: ApolloError;
212+
let error: GraphQLError;
209213

210214
const httpStatus = exceptionRef?.status;
211215
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+
});
215221
} else {
216-
error = new ApolloError(exceptionRef.message, httpStatus?.toString());
222+
error = new GraphQLError(exceptionRef.message, {
223+
extensions: {
224+
code: ApolloServerErrorCode.INTERNAL_SERVER_ERROR,
225+
status: httpStatus,
226+
},
227+
});
217228
}
218229

219230
error.stack = exceptionRef?.stacktrace;
@@ -227,18 +238,26 @@ export abstract class ApolloBaseDriver<
227238
originalOptions: ApolloDriverConfig = { ...targetOptions },
228239
) {
229240
if (!targetOptions.context) {
230-
targetOptions.context = ({ req, request }) => ({ req: req ?? request });
241+
targetOptions.context = async (contextOrRequest) => {
242+
return {
243+
// New ApolloServer fastify integration has Request as first parameter to the Context function
244+
req: contextOrRequest.req ?? contextOrRequest,
245+
};
246+
};
231247
} else if (isFunction(targetOptions.context)) {
232248
targetOptions.context = async (...args: unknown[]) => {
233249
const ctx = await (originalOptions.context as Function)(...args);
234-
const { req, request } = args[0] as Record<string, unknown>;
235-
return this.assignReqProperty(ctx, req ?? request);
250+
const contextOrRequest = args[0] as Record<string, unknown>;
251+
return this.assignReqProperty(
252+
ctx,
253+
contextOrRequest.req ?? contextOrRequest,
254+
);
236255
};
237256
} else {
238-
targetOptions.context = ({ req, request }: Record<string, unknown>) => {
257+
targetOptions.context = async (contextOrRequest) => {
239258
return this.assignReqProperty(
240259
originalOptions.context as Record<string, any>,
241-
req ?? request,
260+
contextOrRequest.req ?? contextOrRequest,
242261
);
243262
};
244263
}

packages/apollo/lib/drivers/apollo-federation.driver.ts

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common';
22
import { loadPackage } from '@nestjs/common/utils/load-package.util';
33
import { ModulesContainer } from '@nestjs/core';
44
import { extend, GraphQLFederationFactory } from '@nestjs/graphql';
5+
import { GraphQLSchema } from 'graphql';
56
import { ApolloDriverConfig } from '../interfaces';
67
import { PluginsExplorerService } from '../services/plugins-explorer.service';
78
import { ApolloBaseDriver } from './apollo-base.driver';
@@ -24,24 +25,19 @@ export class ApolloFederationDriver extends ApolloBaseDriver {
2425
this.pluginsExplorerService.explore(options),
2526
);
2627

27-
const adapterOptions = await this.graphqlFederationFactory.mergeWithSchema(
28-
options,
29-
);
30-
await this.runExecutorFactoryIfPresent(adapterOptions);
31-
3228
if (options.definitions && options.definitions.path) {
3329
const { printSubgraphSchema } = loadPackage(
3430
'@apollo/subgraph',
3531
'ApolloFederation',
3632
() => require('@apollo/subgraph'),
3733
);
3834
await this.graphQlFactory.generateDefinitions(
39-
printSubgraphSchema(adapterOptions.schema),
35+
printSubgraphSchema(options.schema),
4036
options,
4137
);
4238
}
4339

44-
await super.start(adapterOptions);
40+
await super.start(options);
4541

4642
if (options.installSubscriptionHandlers || options.subscriptions) {
4743
// TL;DR <https://github.com/apollographql/apollo-server/issues/2776>
@@ -51,11 +47,7 @@ export class ApolloFederationDriver extends ApolloBaseDriver {
5147
}
5248
}
5349

54-
private async runExecutorFactoryIfPresent(apolloOptions: ApolloDriverConfig) {
55-
if (!apolloOptions.executorFactory) {
56-
return;
57-
}
58-
const executor = await apolloOptions.executorFactory(apolloOptions.schema);
59-
apolloOptions.executor = executor;
50+
public generateSchema(options: ApolloDriverConfig): Promise<GraphQLSchema> {
51+
return this.graphqlFederationFactory.generateSchema(options);
6052
}
6153
}

packages/apollo/lib/drivers/apollo-gateway.driver.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,8 @@ export class ApolloGatewayDriver extends ApolloBaseDriver<ApolloGatewayDriverCon
4343
server: await super.mergeDefaultOptions(options?.server ?? {}),
4444
};
4545
}
46+
47+
public generateSchema(_: ApolloGatewayDriverConfig) {
48+
return null;
49+
}
4650
}

packages/apollo/lib/drivers/apollo.driver.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,12 @@ export class ApolloDriver extends ApolloBaseDriver {
2020
this.pluginsExplorerService = new PluginsExplorerService(modulesContainer);
2121
}
2222

23-
public async start(apolloOptions: ApolloDriverConfig) {
24-
apolloOptions.plugins = extend(
25-
apolloOptions.plugins || [],
26-
this.pluginsExplorerService.explore(apolloOptions),
23+
public async start(options: ApolloDriverConfig) {
24+
options.plugins = extend(
25+
options.plugins || [],
26+
this.pluginsExplorerService.explore(options),
2727
);
2828

29-
const options =
30-
await this.graphQlFactory.mergeWithSchema<ApolloDriverConfig>(
31-
apolloOptions,
32-
);
33-
3429
if (options.definitions && options.definitions.path) {
3530
await this.graphQlFactory.generateDefinitions(
3631
printSchema(options.schema),

0 commit comments

Comments
 (0)