Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: upgrade Mercurius, Apollo, GraphQL to the latest versions #2636

Merged
merged 72 commits into from
Mar 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
7d0438a
feat(graphql): type check field default value
Aug 12, 2022
779b72d
chore(deps): upgrade graphql and add apollo server v4
luas10c Jan 15, 2023
b6a9b72
feat(add): graphql exceptions
luas10c Jan 15, 2023
29882ae
fix(graphql): fix errors and update graphql v16.6
luas10c Jan 15, 2023
cdf4998
feat(add): add folder constants
luas10c Jan 15, 2023
951f907
fix(graphql): fix writing http status code
luas10c Jan 15, 2023
132f44a
feat(apollo): remove old packages
luas10c Jan 15, 2023
2b4f04d
chore(graphql): update package version
luas10c Jan 15, 2023
6ea10c3
chore(mercurius): update package version
luas10c Jan 15, 2023
82b89db
chore(deps): update lock
luas10c Jan 15, 2023
3c7db81
chore(deps): update deps and lock file
luas10c Jan 29, 2023
2f979fa
feat(apollo): fix cors and add @fastify/cors when wrapped by fastify
luas10c Jan 29, 2023
7aaa398
chore(deps): update dependency rimraf to v4.0.5
renovate[bot] Jan 14, 2023
3d990ff
chore(deps): update dependency eslint to v8.32.0
renovate[bot] Jan 15, 2023
46833e5
chore(deps): update dependency rimraf to v4.0.7
renovate[bot] Jan 15, 2023
e59a936
chore(deps): update typescript-eslint monorepo to v5.48.2
renovate[bot] Jan 16, 2023
e66a795
chore(deps): update dependency eslint-plugin-import to v2.27.5
renovate[bot] Jan 16, 2023
80c3dba
chore(deps): update dependency @types/jest to v29.2.6
renovate[bot] Jan 18, 2023
af08334
chore(deps): update typescript-eslint monorepo to v5.49.0
renovate[bot] Jan 23, 2023
95cb42f
chore(deps): update dependency rimraf to v4.1.2
renovate[bot] Jan 24, 2023
d482f33
chore(deps): update dependency jest to v29.4.0
renovate[bot] Jan 24, 2023
c990c84
chore(deps): update dependency @types/jest to v29.4.0
renovate[bot] Jan 25, 2023
d737999
chore(deps): update apollo graphql packages to v2.3.0
renovate[bot] Jan 25, 2023
6ba05c5
chore(deps): update dependency jest to v29.4.1
renovate[bot] Jan 26, 2023
3a879d9
chore(deps): update dependency eslint to v8.33.0
renovate[bot] Jan 29, 2023
93c27d3
fix(deps): remove git conflict markers and keep latest rimraf version
paologf Feb 1, 2023
e365ea5
fix(graphql): generate fields as optional when they contain arguments
arthurtemple Feb 2, 2023
c49e4b2
Merge pull request #1 from paologf/upgrade/apollo-v4
luas10c Feb 2, 2023
b46d9b4
chore: fixing pipes and code-first spec tests and some code cleanup
lpessoa Feb 2, 2023
250639a
Merge pull request #2 from lpessoa/upgrade/apollo-v4
luas10c Feb 2, 2023
d30f3d0
chore: fixing code first schema spec
lpessoa Feb 3, 2023
fa8f879
Merge pull request #3 from lpessoa/upgrade/apollo-v4
luas10c Feb 3, 2023
02842f8
chore: updating code first tests
lpessoa Feb 3, 2023
29b92da
chore: updated assertion utils and code first tests
lpessoa Feb 4, 2023
b4c1d9f
Merge pull request #4 from lpessoa/upgrade/apollo-v4
luas10c Feb 4, 2023
a198c6a
refactor: decouple schema generation from driver start
CarsonF Oct 5, 2022
e30f085
refactor: always generate schema regardless of http adapter existence
CarsonF Oct 5, 2022
6408c1f
refactor: rename `mergeWithSchema` to `generateSchema`
CarsonF Oct 5, 2022
b995d73
Merge branch 'master' of https://github.com/luas10c/graphql into upgr…
luas10c Feb 6, 2023
140f3bd
chore: resolve conflicts
kamilmysliwiec Feb 7, 2023
df58613
chore: resolve yarn.lock conflicts
kamilmysliwiec Feb 7, 2023
8dac4de
fix: several bug fixes, align tests, upgrade deps
kamilmysliwiec Feb 7, 2023
4a7ab32
Merge branch 'luas10c-upgrade/apollo-v4' into next
kamilmysliwiec Feb 7, 2023
d97e653
feat(mercurius): update mercurius plugins, upgrade deps
kamilmysliwiec Feb 7, 2023
1e099fa
feat(apollo): update drivers, remove deprecated options, fix runners
kamilmysliwiec Feb 7, 2023
a9c9d58
Merge branch 'master' into next
kamilmysliwiec Feb 7, 2023
ea78051
fix(mercurius): update invalid import
kamilmysliwiec Feb 7, 2023
da6a44b
Merge branch 'next' of https://github.com/nestjs/graphql into next
kamilmysliwiec Feb 7, 2023
9e1f08a
chore: remove deprecated gateway hooks
tugascript Feb 7, 2023
c7cc273
Merge pull request #2637 from tugascript/afonso-next
kamilmysliwiec Feb 7, 2023
c845bea
test(mercurius): update gql module options for federation
kamilmysliwiec Feb 7, 2023
942f3e5
chore: remove leftovers, integrate graph serializer
kamilmysliwiec Feb 7, 2023
1e58897
chore: remove leftovers, integrate graph serializer
kamilmysliwiec Feb 7, 2023
14a9aee
chore(deps): bump nestjs/testing to the latest version too
kamilmysliwiec Feb 7, 2023
2577291
chore: resolve conflicts, minor tweaks
kamilmysliwiec Feb 8, 2023
33e423f
Merge branch 'CarsonF-refactor/schema-generation-hook' into next
kamilmysliwiec Feb 8, 2023
ef15aba
chore: upgrade packages, update snapshot
kamilmysliwiec Feb 8, 2023
bfe3a2e
fix: register resolver as an entry provider
kamilmysliwiec Feb 10, 2023
03fc641
v11.0.0-next.1
kamilmysliwiec Feb 14, 2023
a904e67
fix: pass context fn to server middleware
Davide-Gheri Feb 20, 2023
8290923
fix: apollo server expects context to always return a promise
Davide-Gheri Feb 20, 2023
5a1e97c
fix: correctly pass request to context with fastify adapter
Davide-Gheri Feb 20, 2023
291d5c5
test: custom context is available to resolvers
Davide-Gheri Feb 20, 2023
2f6b55d
Merge pull request #2662 from Davide-Gheri/fix/apollo-context
kamilmysliwiec Feb 24, 2023
15fd4e3
Merge pull request #2623 from arthurtemple/make-properties-with-argum…
kamilmysliwiec Feb 24, 2023
6c5d222
Merge pull request #2330 from martinlehoux/master
kamilmysliwiec Feb 24, 2023
741937c
chore: move apollo server to peer deps
kamilmysliwiec Mar 1, 2023
7072504
feat(apollo): add wrapper error classes
kamilmysliwiec Mar 1, 2023
64494db
v11.0.0-next.2
kamilmysliwiec Mar 1, 2023
8df948d
chore: resolve conflicts
kamilmysliwiec Mar 10, 2023
4b2b173
test: update snapshot
kamilmysliwiec Mar 10, 2023
e667c69
test: skip mercurius gateway test
kamilmysliwiec Mar 10, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,6 @@ test-schema.graphql

# dist
packages/**/dist
**/*.tsbuildinfo
**/*.tsbuildinfo

.yarn/
6 changes: 2 additions & 4 deletions lerna.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
{
"packages": [
"packages/*"
],
"version": "10.2.0",
"packages": ["packages/*"],
"version": "11.0.0-next.2",
"npmClient": "yarn",
"useWorkspaces": true,
"changelog": {
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"prepare": "husky install"
},
"resolutions": {
"graphql": "15.8.0"
"graphql": "16.6.0"
},
"devDependencies": {
"@commitlint/cli": "17.4.4",
Expand All @@ -45,7 +45,7 @@
"eslint-config-prettier": "8.7.0",
"eslint-plugin-import": "2.27.5",
"eslint-plugin-prettier": "4.2.1",
"graphql": "15.8.0",
"graphql": "16.6.0",
"graphql-subscriptions": "2.0.0",
"husky": "8.0.3",
"jest": "29.5.0",
Expand Down
1 change: 1 addition & 0 deletions packages/apollo/lib/constants/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './apollo.constants';
2 changes: 1 addition & 1 deletion packages/apollo/lib/decorators/plugin.decorator.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { SetMetadata } from '@nestjs/common';
import { PLUGIN_METADATA } from '../apollo.constants';
import { PLUGIN_METADATA } from '../constants';

/**
* Decorator that marks a class as an Apollo plugin.
Expand Down
161 changes: 90 additions & 71 deletions packages/apollo/lib/drivers/apollo-base.driver.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,31 @@
import { ApolloServer, type BaseContext } from '@apollo/server';
import { ApolloServerPluginLandingPageGraphQLPlayground } from '@apollo/server-plugin-landing-page-graphql-playground';
import { ApolloServerErrorCode } from '@apollo/server/errors';
import { expressMiddleware } from '@apollo/server/express4';
import { ApolloServerPluginLandingPageDisabled } from '@apollo/server/plugin/disabled';
import { ApolloServerPluginDrainHttpServer } from '@apollo/server/plugin/drainHttpServer';
import { HttpStatus } from '@nestjs/common';
import { loadPackage } from '@nestjs/common/utils/load-package.util';
import { isFunction } from '@nestjs/common/utils/shared.utils';
import { AbstractGraphQLDriver } from '@nestjs/graphql';
import {
ApolloError,
ApolloServerBase,
ApolloServerPluginLandingPageDisabled,
ApolloServerPluginLandingPageGraphQLPlayground,
AuthenticationError,
ForbiddenError,
PluginDefinition,
UserInputError,
} from 'apollo-server-core';
import { GraphQLError, GraphQLFormattedError } from 'graphql';
import * as omit from 'lodash.omit';
import { ApolloDriverConfig } from '../interfaces';
import { createAsyncIterator } from '../utils/async-iterator.util';

const apolloPredefinedExceptions: Partial<
Record<HttpStatus, typeof ApolloError | typeof UserInputError>
> = {
[HttpStatus.BAD_REQUEST]: UserInputError,
[HttpStatus.UNAUTHORIZED]: AuthenticationError,
[HttpStatus.FORBIDDEN]: ForbiddenError,
const apolloPredefinedExceptions: Partial<Record<HttpStatus, string>> = {
[HttpStatus.BAD_REQUEST]: ApolloServerErrorCode.BAD_REQUEST,
[HttpStatus.UNAUTHORIZED]: 'UNAUTHENTICATED',
[HttpStatus.FORBIDDEN]: 'FORBIDDEN',
};

export abstract class ApolloBaseDriver<
T extends Record<string, any> = ApolloDriverConfig,
> extends AbstractGraphQLDriver<T> {
protected _apolloServer: ApolloServerBase;
protected apolloServer: ApolloServer<BaseContext>;

get instance(): ApolloServerBase {
return this._apolloServer;
get instance(): ApolloServer<BaseContext> {
return this.apolloServer;
}

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

public stop() {
return this._apolloServer?.stop();
return this.apolloServer?.stop();
}

public async mergeDefaultOptions(options: T): Promise<T> {
Expand All @@ -68,9 +62,7 @@ export abstract class ApolloBaseDriver<
defaults = {
...defaults,
plugins: [
ApolloServerPluginLandingPageGraphQLPlayground(
playgroundOptions,
) as PluginDefinition,
ApolloServerPluginLandingPageGraphQLPlayground(playgroundOptions),
],
};
} else if (
Expand All @@ -80,7 +72,7 @@ export abstract class ApolloBaseDriver<
) {
defaults = {
...defaults,
plugins: [ApolloServerPluginLandingPageDisabled() as PluginDefinition],
plugins: [ApolloServerPluginLandingPageDisabled()],
};
}

Expand Down Expand Up @@ -116,67 +108,80 @@ export abstract class ApolloBaseDriver<
}

protected async registerExpress(
apolloOptions: T,
options: T,
{ preStartHook }: { preStartHook?: () => void } = {},
) {
const { ApolloServer } = loadPackage(
'apollo-server-express',
'GraphQLModule',
() => require('apollo-server-express'),
);
const { disableHealthCheck, path, onHealthCheck, cors, bodyParserConfig } =
apolloOptions;
const { path, typeDefs, resolvers, schema } = options;

const httpAdapter = this.httpAdapterHost.httpAdapter;
const app = httpAdapter.getInstance();
const drainHttpServerPlugin = ApolloServerPluginDrainHttpServer({
httpServer: httpAdapter.getHttpServer(),
});

preStartHook?.();

const apolloServer = new ApolloServer(apolloOptions as any);
await apolloServer.start();
const server = new ApolloServer({
typeDefs,
resolvers,
schema,
...options,
plugins: options.plugins
? options.plugins.concat([drainHttpServerPlugin])
: [drainHttpServerPlugin],
});

await server.start();

apolloServer.applyMiddleware({
app,
app.use(
path,
disableHealthCheck,
onHealthCheck,
cors,
bodyParserConfig,
});
expressMiddleware(server, {
context: options.context,
}),
);

this._apolloServer = apolloServer;
this.apolloServer = server;
}

protected async registerFastify(
apolloOptions: T,
options: T,
{ preStartHook }: { preStartHook?: () => void } = {},
) {
const { ApolloServer } = loadPackage(
'apollo-server-fastify',
const { fastifyApolloDrainPlugin, fastifyApolloHandler } = loadPackage(
'@as-integrations/fastify',
'GraphQLModule',
() => require('apollo-server-fastify'),
() => require('@as-integrations/fastify'),
);

const httpAdapter = this.httpAdapterHost.httpAdapter;
const app = httpAdapter.getInstance();

const { path, typeDefs, resolvers, schema } = options;
const apolloDrainPlugin = fastifyApolloDrainPlugin(app);

preStartHook?.();
const apolloServer = new ApolloServer(apolloOptions as any);
await apolloServer.start();

const { disableHealthCheck, onHealthCheck, cors, bodyParserConfig, path } =
apolloOptions;
await app.register(
apolloServer.createHandler({
disableHealthCheck,
onHealthCheck,
cors,
bodyParserConfig,
path,

const server = new ApolloServer<BaseContext>({
typeDefs,
resolvers,
schema,
...options,
plugins: options.plugins
? options.plugins.concat([apolloDrainPlugin])
: [apolloDrainPlugin],
});

await server.start();

app.route({
url: path,
method: ['GET', 'POST', 'OPTIONS'],
handler: fastifyApolloHandler(server, {
context: options.context,
}),
);
});

this._apolloServer = apolloServer;
this.apolloServer = server;
}

private wrapFormatErrorFn(options: T) {
Expand All @@ -201,19 +206,25 @@ export abstract class ApolloBaseDriver<
const exceptionRef = originalError?.extensions?.exception;
const isHttpException =
exceptionRef?.response?.statusCode && exceptionRef?.status;

if (!isHttpException) {
return originalError as GraphQLFormattedError;
}
let error: ApolloError;
let error: GraphQLError;

const httpStatus = exceptionRef?.status;
if (httpStatus in apolloPredefinedExceptions) {
error = new apolloPredefinedExceptions[httpStatus](
exceptionRef?.message,
);
error = new GraphQLError(exceptionRef?.message, {
extensions: {
code: apolloPredefinedExceptions[httpStatus],
},
});
} else {
error = new ApolloError(exceptionRef.message, httpStatus?.toString());
error = new GraphQLError(exceptionRef.message, {
extensions: {
code: ApolloServerErrorCode.INTERNAL_SERVER_ERROR,
status: httpStatus,
},
});
}

error.stack = exceptionRef?.stacktrace;
Expand All @@ -227,18 +238,26 @@ export abstract class ApolloBaseDriver<
originalOptions: ApolloDriverConfig = { ...targetOptions },
) {
if (!targetOptions.context) {
targetOptions.context = ({ req, request }) => ({ req: req ?? request });
targetOptions.context = async (contextOrRequest) => {
return {
// New ApolloServer fastify integration has Request as first parameter to the Context function
req: contextOrRequest.req ?? contextOrRequest,
};
};
} else if (isFunction(targetOptions.context)) {
targetOptions.context = async (...args: unknown[]) => {
const ctx = await (originalOptions.context as Function)(...args);
const { req, request } = args[0] as Record<string, unknown>;
return this.assignReqProperty(ctx, req ?? request);
const contextOrRequest = args[0] as Record<string, unknown>;
return this.assignReqProperty(
ctx,
contextOrRequest.req ?? contextOrRequest,
);
};
} else {
targetOptions.context = ({ req, request }: Record<string, unknown>) => {
targetOptions.context = async (contextOrRequest) => {
return this.assignReqProperty(
originalOptions.context as Record<string, any>,
req ?? request,
contextOrRequest.req ?? contextOrRequest,
);
};
}
Expand Down
18 changes: 5 additions & 13 deletions packages/apollo/lib/drivers/apollo-federation.driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common';
import { loadPackage } from '@nestjs/common/utils/load-package.util';
import { ModulesContainer } from '@nestjs/core';
import { extend, GraphQLFederationFactory } from '@nestjs/graphql';
import { GraphQLSchema } from 'graphql';
import { ApolloDriverConfig } from '../interfaces';
import { PluginsExplorerService } from '../services/plugins-explorer.service';
import { ApolloBaseDriver } from './apollo-base.driver';
Expand All @@ -24,24 +25,19 @@ export class ApolloFederationDriver extends ApolloBaseDriver {
this.pluginsExplorerService.explore(options),
);

const adapterOptions = await this.graphqlFederationFactory.mergeWithSchema(
options,
);
await this.runExecutorFactoryIfPresent(adapterOptions);

if (options.definitions && options.definitions.path) {
const { printSubgraphSchema } = loadPackage(
'@apollo/subgraph',
'ApolloFederation',
() => require('@apollo/subgraph'),
);
await this.graphQlFactory.generateDefinitions(
printSubgraphSchema(adapterOptions.schema),
printSubgraphSchema(options.schema),
options,
);
}

await super.start(adapterOptions);
await super.start(options);

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

private async runExecutorFactoryIfPresent(apolloOptions: ApolloDriverConfig) {
if (!apolloOptions.executorFactory) {
return;
}
const executor = await apolloOptions.executorFactory(apolloOptions.schema);
apolloOptions.executor = executor;
public generateSchema(options: ApolloDriverConfig): Promise<GraphQLSchema> {
return this.graphqlFederationFactory.generateSchema(options);
}
}
4 changes: 4 additions & 0 deletions packages/apollo/lib/drivers/apollo-gateway.driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,8 @@ export class ApolloGatewayDriver extends ApolloBaseDriver<ApolloGatewayDriverCon
server: await super.mergeDefaultOptions(options?.server ?? {}),
};
}

public generateSchema(_: ApolloGatewayDriverConfig) {
return null;
}
}
13 changes: 4 additions & 9 deletions packages/apollo/lib/drivers/apollo.driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,12 @@ export class ApolloDriver extends ApolloBaseDriver {
this.pluginsExplorerService = new PluginsExplorerService(modulesContainer);
}

public async start(apolloOptions: ApolloDriverConfig) {
apolloOptions.plugins = extend(
apolloOptions.plugins || [],
this.pluginsExplorerService.explore(apolloOptions),
public async start(options: ApolloDriverConfig) {
options.plugins = extend(
options.plugins || [],
this.pluginsExplorerService.explore(options),
);

const options =
await this.graphQlFactory.mergeWithSchema<ApolloDriverConfig>(
apolloOptions,
);

if (options.definitions && options.definitions.path) {
await this.graphQlFactory.generateDefinitions(
printSchema(options.schema),
Expand Down