Skip to content

Commit f435852

Browse files
Merge pull request #2538 from tugascript/tugascript/add-plugins-to-mercurius
feat(mercurius): add plugins option
2 parents e66c216 + 6828e67 commit f435852

24 files changed

+443
-14
lines changed

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

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,16 @@ import { IncomingMessage, Server, ServerResponse } from 'http';
99
import mercurius from 'mercurius';
1010
import { MercuriusDriverConfig } from '../interfaces/mercurius-driver-config.interface';
1111
import { buildMercuriusFederatedSchema } from '../utils/build-mercurius-federated-schema.util';
12+
import { registerMercuriusPlugin } from '../utils/register-mercurius-plugin.util';
1213

1314
@Injectable()
1415
export class MercuriusFederationDriver extends AbstractGraphQLDriver<MercuriusDriverConfig> {
16+
constructor(
17+
private readonly graphqlFederationFactory: GraphQLFederationFactory,
18+
) {
19+
super();
20+
}
21+
1522
get instance(): FastifyInstance<
1623
Server,
1724
IncomingMessage,
@@ -21,17 +28,12 @@ export class MercuriusFederationDriver extends AbstractGraphQLDriver<MercuriusDr
2128
return this.httpAdapterHost?.httpAdapter?.getInstance?.();
2229
}
2330

24-
constructor(
25-
private readonly graphqlFederationFactory: GraphQLFederationFactory,
26-
) {
27-
super();
28-
}
29-
3031
public async start(options: MercuriusDriverConfig) {
31-
const adapterOptions = await this.graphqlFederationFactory.mergeWithSchema(
32-
options,
33-
buildMercuriusFederatedSchema,
34-
);
32+
const { plugins, ...adapterOptions } =
33+
await this.graphqlFederationFactory.mergeWithSchema(
34+
options,
35+
buildMercuriusFederatedSchema,
36+
);
3537

3638
if (adapterOptions.definitions && adapterOptions.definitions.path) {
3739
await this.graphQlFactory.generateDefinitions(
@@ -50,6 +52,7 @@ export class MercuriusFederationDriver extends AbstractGraphQLDriver<MercuriusDr
5052
await app.register(mercurius, {
5153
...adapterOptions,
5254
});
55+
await registerMercuriusPlugin(app, plugins);
5356
}
5457

5558
/* eslit-disable-next-line @typescript-eslint/no-empty-function */

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { FastifyInstance, FastifyLoggerInstance } from 'fastify';
33
import { IncomingMessage, Server, ServerResponse } from 'http';
44
import mercurius from 'mercurius';
55
import { MercuriusDriverConfig } from '../interfaces/mercurius-driver-config.interface';
6+
import { registerMercuriusPlugin } from '../utils/register-mercurius-plugin.util';
67

78
export class MercuriusGatewayDriver extends AbstractGraphQLDriver<MercuriusDriverConfig> {
89
get instance(): FastifyInstance<
@@ -22,10 +23,12 @@ export class MercuriusGatewayDriver extends AbstractGraphQLDriver<MercuriusDrive
2223
throw new Error(`No support for current HttpAdapter: ${platformName}`);
2324
}
2425

26+
const { plugins, ...mercuriusOptions } = options;
2527
const app = httpAdapter.getInstance<FastifyInstance>();
2628
await app.register(mercurius, {
27-
...options,
29+
...mercuriusOptions,
2830
});
31+
await registerMercuriusPlugin(app, plugins);
2932
}
3033

3134
public async stop(): Promise<void> {}

packages/mercurius/lib/drivers/mercurius.driver.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { printSchema } from 'graphql';
55
import { IncomingMessage, Server, ServerResponse } from 'http';
66
import mercurius from 'mercurius';
77
import { MercuriusDriverConfig } from '../interfaces/mercurius-driver-config.interface';
8+
import { registerMercuriusPlugin } from '../utils/register-mercurius-plugin.util';
89

910
export class MercuriusDriver extends AbstractGraphQLDriver<MercuriusDriverConfig> {
1011
get instance(): FastifyInstance<
@@ -17,7 +18,7 @@ export class MercuriusDriver extends AbstractGraphQLDriver<MercuriusDriverConfig
1718
}
1819

1920
public async start(mercuriusOptions: MercuriusDriverConfig) {
20-
const options =
21+
const { plugins, ...options } =
2122
await this.graphQlFactory.mergeWithSchema<MercuriusDriverConfig>(
2223
mercuriusOptions,
2324
);
@@ -39,6 +40,7 @@ export class MercuriusDriver extends AbstractGraphQLDriver<MercuriusDriverConfig
3940
await app.register(mercurius, {
4041
...options,
4142
});
43+
await registerMercuriusPlugin(app, plugins);
4244
}
4345

4446
public async stop(): Promise<void> {}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export * from './mercurius-driver-config.interface';
22
export * from './mercurius-federation-driver-config.interface';
33
export * from './mercurius-gateway-driver-config.interface';
4+
export * from './mercurius-plugin.interface';

packages/mercurius/lib/interfaces/mercurius-driver-config.interface.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@ import {
44
GqlOptionsFactory,
55
} from '@nestjs/graphql';
66
import { MercuriusOptions } from 'mercurius';
7+
import { MercuriusPlugins } from './mercurius-plugin.interface';
78

8-
export type MercuriusDriverConfig = GqlModuleOptions & MercuriusOptions;
9+
export type MercuriusDriverConfig = GqlModuleOptions &
10+
MercuriusOptions &
11+
MercuriusPlugins;
912

1013
export type MercuriusDriverConfigFactory =
1114
GqlOptionsFactory<MercuriusDriverConfig>;

packages/mercurius/lib/interfaces/mercurius-gateway-driver-config.interface.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ import {
44
GqlOptionsFactory,
55
} from '@nestjs/graphql';
66
import { MercuriusCommonOptions, MercuriusGatewayOptions } from 'mercurius';
7+
import { MercuriusPlugin } from './mercurius-plugin.interface';
78

89
export type MercuriusGatewayDriverConfig = GqlModuleOptions &
910
MercuriusCommonOptions &
10-
MercuriusGatewayOptions;
11+
MercuriusGatewayOptions &
12+
MercuriusPlugin;
1113

1214
export type MercuriusGatewayDriverConfigFactory =
1315
GqlOptionsFactory<MercuriusGatewayDriverConfig>;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import {
2+
FastifyPluginAsync,
3+
FastifyPluginCallback,
4+
FastifyPluginOptions,
5+
FastifyRegisterOptions,
6+
} from 'fastify';
7+
8+
export interface MercuriusPlugin<
9+
Options extends FastifyPluginOptions = unknown,
10+
> {
11+
plugin:
12+
| FastifyPluginCallback<Options>
13+
| FastifyPluginAsync<Options>
14+
| Promise<{
15+
default: FastifyPluginCallback<Options>;
16+
}>;
17+
options?: FastifyRegisterOptions<Options>;
18+
}
19+
20+
export interface MercuriusPlugins<
21+
Options extends FastifyPluginOptions = unknown,
22+
> {
23+
plugins?: MercuriusPlugin<Options>[];
24+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { FastifyInstance } from 'fastify';
2+
import { MercuriusPlugin } from '../interfaces/mercurius-plugin.interface';
3+
import { isArray, isNull, isUndefined } from './validation.util';
4+
5+
export async function registerMercuriusPlugin(
6+
app: FastifyInstance,
7+
plugins?: MercuriusPlugin[],
8+
): Promise<void> {
9+
if (
10+
isUndefined(plugins) ||
11+
isNull(plugins) ||
12+
!isArray(plugins) ||
13+
plugins.length === 0
14+
) {
15+
return;
16+
}
17+
18+
for (const plugin of plugins) {
19+
await app.register(plugin.plugin, plugin.options);
20+
}
21+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export const isUndefined = (value: unknown): value is undefined => {
2+
return typeof value === 'undefined';
3+
};
4+
5+
export const isNull = (value: unknown): value is null => value === null;
6+
7+
export const isArray = <T>(value: unknown): value is T[] => {
8+
return Array.isArray(value);
9+
};
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { INestApplication } from '@nestjs/common';
2+
import { FastifyAdapter } from '@nestjs/platform-fastify';
3+
import { Test } from '@nestjs/testing';
4+
import { FastifyInstance } from 'fastify';
5+
import { ApplicationModule } from '../plugins/code-first-plugin/app.module';
6+
import { NEW_PLUGIN_URL } from '../plugins/mocks/utils/constants';
7+
8+
describe('Code-first with plugins', () => {
9+
let app: INestApplication;
10+
11+
beforeEach(async () => {
12+
const module = await Test.createTestingModule({
13+
imports: [ApplicationModule],
14+
}).compile();
15+
16+
app = module.createNestApplication(new FastifyAdapter());
17+
await app.init();
18+
});
19+
20+
it('should get the plugin', async () => {
21+
const fastifyInstance: FastifyInstance = app.getHttpAdapter().getInstance();
22+
await fastifyInstance.ready();
23+
24+
const response = await fastifyInstance.inject({
25+
method: 'GET',
26+
url: NEW_PLUGIN_URL,
27+
});
28+
const data = JSON.parse(response.body);
29+
expect(fastifyInstance.printPlugins().includes('mockPlugin')).toBe(true);
30+
expect(response.statusCode).toBe(200);
31+
expect(data.from).toBe(NEW_PLUGIN_URL);
32+
});
33+
34+
it('it should query dog', async () => {
35+
const fastifyInstance: FastifyInstance = app.getHttpAdapter().getInstance();
36+
await fastifyInstance.ready();
37+
38+
const response = await fastifyInstance.graphql(`
39+
{
40+
getAnimalName
41+
}
42+
`);
43+
expect(response.data).toEqual({
44+
getAnimalName: 'dog',
45+
});
46+
});
47+
48+
afterEach(async () => {
49+
await app.close();
50+
});
51+
});

0 commit comments

Comments
 (0)