@graphql-yoga/nestjs 3.0.2 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # @graphql-yoga/nestjs
2
2
 
3
+ ## 3.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#2992](https://github.com/dotansimha/graphql-yoga/pull/2992)
8
+ [`b1f0e3a2`](https://github.com/dotansimha/graphql-yoga/commit/b1f0e3a2986956c6791a251df908e3f8b50ec966)
9
+ Thanks [@magrinj](https://github.com/magrinj)! - Adding support of conditionalSchema option.
10
+ (Currently without support for WebSocket subscriptions)
11
+
12
+ ### Patch Changes
13
+
14
+ - Updated dependencies
15
+ [[`b1f0e3a2`](https://github.com/dotansimha/graphql-yoga/commit/b1f0e3a2986956c6791a251df908e3f8b50ec966)]:
16
+ - graphql-yoga@5.1.0
17
+
3
18
  ## 3.0.2
4
19
 
5
20
  ### Patch Changes
@@ -1,3 +1,11 @@
1
+ import {
2
+ GraphQLID,
3
+ GraphQLList,
4
+ GraphQLNonNull,
5
+ GraphQLObjectType,
6
+ GraphQLSchema,
7
+ GraphQLString,
8
+ } from 'graphql';
1
9
  import { INestApplication } from '@nestjs/common';
2
10
  import { Test } from '@nestjs/testing';
3
11
  import { fetch } from '@whatwg-node/fetch';
@@ -7,7 +15,44 @@ let app: INestApplication, url: string;
7
15
 
8
16
  beforeAll(async () => {
9
17
  const module = await Test.createTestingModule({
10
- imports: [AppModule.forRoot()],
18
+ imports: [
19
+ AppModule.forRoot({
20
+ conditionalSchema: async () => {
21
+ const DogObjectType = new GraphQLObjectType({
22
+ name: 'Dog',
23
+ fields: {
24
+ id: {
25
+ type: new GraphQLNonNull(GraphQLID),
26
+ },
27
+ name: {
28
+ type: new GraphQLNonNull(GraphQLString),
29
+ },
30
+ breed: {
31
+ type: new GraphQLNonNull(GraphQLString),
32
+ },
33
+ },
34
+ });
35
+
36
+ return new GraphQLSchema({
37
+ query: new GraphQLObjectType({
38
+ name: 'Query',
39
+ fields: {
40
+ getDogs: {
41
+ type: new GraphQLList(new GraphQLNonNull(DogObjectType)),
42
+ resolve: () => [
43
+ {
44
+ id: '1',
45
+ name: 'Bingo',
46
+ breed: 'Dalmatian',
47
+ },
48
+ ],
49
+ },
50
+ },
51
+ }),
52
+ });
53
+ },
54
+ }),
55
+ ],
11
56
  }).compile();
12
57
  app = module.createNestApplication();
13
58
  await app.listen(0);
@@ -48,3 +93,36 @@ it('should return query result', async () => {
48
93
  }
49
94
  `);
50
95
  });
96
+
97
+ it('should return query result for conditional schema', async () => {
98
+ const res = await fetch(url, {
99
+ method: 'POST',
100
+ headers: {
101
+ 'content-type': 'application/json',
102
+ },
103
+ body: JSON.stringify({
104
+ query: /* GraphQL */ `
105
+ {
106
+ getDogs {
107
+ id
108
+ name
109
+ breed
110
+ }
111
+ }
112
+ `,
113
+ }),
114
+ });
115
+ await expect(res.json()).resolves.toMatchInlineSnapshot(`
116
+ {
117
+ "data": {
118
+ "getDogs": [
119
+ {
120
+ "breed": "Dalmatian",
121
+ "id": "1",
122
+ "name": "Bingo",
123
+ },
124
+ ],
125
+ },
126
+ }
127
+ `);
128
+ });
package/dist/cjs/index.js CHANGED
@@ -28,7 +28,7 @@ class AbstractYogaDriver extends graphql_2.AbstractGraphQLDriver {
28
28
  async stop() {
29
29
  // noop
30
30
  }
31
- registerExpress(options, { preStartHook } = {}) {
31
+ registerExpress({ conditionalSchema, ...options }, { preStartHook } = {}) {
32
32
  const app = this.httpAdapterHost.httpAdapter.getInstance();
33
33
  preStartHook?.(app);
34
34
  // nest's logger doesnt have the info method
@@ -41,8 +41,10 @@ class AbstractYogaDriver extends graphql_2.AbstractGraphQLDriver {
41
41
  this.log(message, ...args);
42
42
  }
43
43
  }
44
+ const schema = this.mergeConditionalSchema(conditionalSchema, options.schema);
44
45
  const yoga = (0, graphql_yoga_1.createYoga)({
45
46
  ...options,
47
+ schema,
46
48
  graphqlEndpoint: options.path,
47
49
  // disable logging by default
48
50
  // however, if `true` use nest logger
@@ -55,11 +57,13 @@ class AbstractYogaDriver extends graphql_2.AbstractGraphQLDriver {
55
57
  this.yoga = yoga;
56
58
  app.use(yoga.graphqlEndpoint, (req, res) => yoga(req, res, { req, res }));
57
59
  }
58
- registerFastify(options, { preStartHook } = {}) {
60
+ registerFastify({ conditionalSchema, ...options }, { preStartHook } = {}) {
59
61
  const app = this.httpAdapterHost.httpAdapter.getInstance();
60
62
  preStartHook?.(app);
63
+ const schema = this.mergeConditionalSchema(conditionalSchema, options.schema);
61
64
  const yoga = (0, graphql_yoga_1.createYoga)({
62
65
  ...options,
66
+ schema,
63
67
  graphqlEndpoint: options.path,
64
68
  // disable logging by default
65
69
  // however, if `true` use fastify logger
@@ -78,6 +82,27 @@ class AbstractYogaDriver extends graphql_2.AbstractGraphQLDriver {
78
82
  return reply;
79
83
  });
80
84
  }
85
+ mergeConditionalSchema(conditionalSchema, schema) {
86
+ let mergedSchema = schema;
87
+ if (conditionalSchema) {
88
+ mergedSchema = async (request) => {
89
+ const schemas = [];
90
+ if (schema) {
91
+ schemas.push(schema);
92
+ }
93
+ const conditionalSchemaResult = typeof conditionalSchema === 'function'
94
+ ? await conditionalSchema(request)
95
+ : await conditionalSchema;
96
+ if (conditionalSchemaResult) {
97
+ schemas.push(conditionalSchemaResult);
98
+ }
99
+ return (0, graphql_yoga_1.mergeSchemas)({
100
+ schemas,
101
+ });
102
+ };
103
+ }
104
+ return mergedSchema;
105
+ }
81
106
  subscriptionWithFilter(instanceRef, filterFn,
82
107
  // disable next error, the original function in @nestjs/graphql is also untyped
83
108
  // eslint-disable-next-line @typescript-eslint/ban-types
@@ -111,6 +136,11 @@ let YogaDriver = exports.YogaDriver = class YogaDriver extends AbstractYogaDrive
111
136
  : options.subscriptions;
112
137
  if (config['graphql-ws']) {
113
138
  config['graphql-ws'] = typeof config['graphql-ws'] === 'object' ? config['graphql-ws'] : {};
139
+ if (options.conditionalSchema) {
140
+ throw new Error(`
141
+ Conditional schema is not supported with graphql-ws.
142
+ `);
143
+ }
114
144
  config['graphql-ws'].onSubscribe = async (ctx, msg) => {
115
145
  const { schema, execute, subscribe, contextFactory, parse, validate } = this.yoga.getEnveloped({
116
146
  ...ctx,
@@ -138,6 +168,11 @@ let YogaDriver = exports.YogaDriver = class YogaDriver extends AbstractYogaDrive
138
168
  typeof config['subscriptions-transport-ws'] === 'object'
139
169
  ? config['subscriptions-transport-ws']
140
170
  : {};
171
+ if (options.conditionalSchema) {
172
+ throw new Error(`
173
+ Conditional schema is not supported with subscriptions-transport-ws.
174
+ `);
175
+ }
141
176
  config['subscriptions-transport-ws'].onOperation = async (_msg, params, ws) => {
142
177
  const { schema, execute, subscribe, contextFactory, parse, validate } = this.yoga.getEnveloped({
143
178
  ...params.context,
package/dist/esm/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { __decorate } from "tslib";
2
2
  import { printSchema } from 'graphql';
3
- import { createYoga, filter, pipe } from 'graphql-yoga';
3
+ import { createYoga, filter, mergeSchemas, pipe, } from 'graphql-yoga';
4
4
  import { Injectable, Logger } from '@nestjs/common';
5
5
  import { AbstractGraphQLDriver, GqlSubscriptionService, } from '@nestjs/graphql';
6
6
  export class AbstractYogaDriver extends AbstractGraphQLDriver {
@@ -25,7 +25,7 @@ export class AbstractYogaDriver extends AbstractGraphQLDriver {
25
25
  async stop() {
26
26
  // noop
27
27
  }
28
- registerExpress(options, { preStartHook } = {}) {
28
+ registerExpress({ conditionalSchema, ...options }, { preStartHook } = {}) {
29
29
  const app = this.httpAdapterHost.httpAdapter.getInstance();
30
30
  preStartHook?.(app);
31
31
  // nest's logger doesnt have the info method
@@ -38,8 +38,10 @@ export class AbstractYogaDriver extends AbstractGraphQLDriver {
38
38
  this.log(message, ...args);
39
39
  }
40
40
  }
41
+ const schema = this.mergeConditionalSchema(conditionalSchema, options.schema);
41
42
  const yoga = createYoga({
42
43
  ...options,
44
+ schema,
43
45
  graphqlEndpoint: options.path,
44
46
  // disable logging by default
45
47
  // however, if `true` use nest logger
@@ -52,11 +54,13 @@ export class AbstractYogaDriver extends AbstractGraphQLDriver {
52
54
  this.yoga = yoga;
53
55
  app.use(yoga.graphqlEndpoint, (req, res) => yoga(req, res, { req, res }));
54
56
  }
55
- registerFastify(options, { preStartHook } = {}) {
57
+ registerFastify({ conditionalSchema, ...options }, { preStartHook } = {}) {
56
58
  const app = this.httpAdapterHost.httpAdapter.getInstance();
57
59
  preStartHook?.(app);
60
+ const schema = this.mergeConditionalSchema(conditionalSchema, options.schema);
58
61
  const yoga = createYoga({
59
62
  ...options,
63
+ schema,
60
64
  graphqlEndpoint: options.path,
61
65
  // disable logging by default
62
66
  // however, if `true` use fastify logger
@@ -75,6 +79,27 @@ export class AbstractYogaDriver extends AbstractGraphQLDriver {
75
79
  return reply;
76
80
  });
77
81
  }
82
+ mergeConditionalSchema(conditionalSchema, schema) {
83
+ let mergedSchema = schema;
84
+ if (conditionalSchema) {
85
+ mergedSchema = async (request) => {
86
+ const schemas = [];
87
+ if (schema) {
88
+ schemas.push(schema);
89
+ }
90
+ const conditionalSchemaResult = typeof conditionalSchema === 'function'
91
+ ? await conditionalSchema(request)
92
+ : await conditionalSchema;
93
+ if (conditionalSchemaResult) {
94
+ schemas.push(conditionalSchemaResult);
95
+ }
96
+ return mergeSchemas({
97
+ schemas,
98
+ });
99
+ };
100
+ }
101
+ return mergedSchema;
102
+ }
78
103
  subscriptionWithFilter(instanceRef, filterFn,
79
104
  // disable next error, the original function in @nestjs/graphql is also untyped
80
105
  // eslint-disable-next-line @typescript-eslint/ban-types
@@ -107,6 +132,11 @@ export let YogaDriver = class YogaDriver extends AbstractYogaDriver {
107
132
  : options.subscriptions;
108
133
  if (config['graphql-ws']) {
109
134
  config['graphql-ws'] = typeof config['graphql-ws'] === 'object' ? config['graphql-ws'] : {};
135
+ if (options.conditionalSchema) {
136
+ throw new Error(`
137
+ Conditional schema is not supported with graphql-ws.
138
+ `);
139
+ }
110
140
  config['graphql-ws'].onSubscribe = async (ctx, msg) => {
111
141
  const { schema, execute, subscribe, contextFactory, parse, validate } = this.yoga.getEnveloped({
112
142
  ...ctx,
@@ -134,6 +164,11 @@ export let YogaDriver = class YogaDriver extends AbstractYogaDriver {
134
164
  typeof config['subscriptions-transport-ws'] === 'object'
135
165
  ? config['subscriptions-transport-ws']
136
166
  : {};
167
+ if (options.conditionalSchema) {
168
+ throw new Error(`
169
+ Conditional schema is not supported with subscriptions-transport-ws.
170
+ `);
171
+ }
137
172
  config['subscriptions-transport-ws'].onOperation = async (_msg, params, ws) => {
138
173
  const { schema, execute, subscribe, contextFactory, parse, validate } = this.yoga.getEnveloped({
139
174
  ...params.context,
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graphql-yoga/nestjs",
3
- "version": "3.0.2",
3
+ "version": "3.1.0",
4
4
  "description": "GraphQL Yoga driver for NestJS GraphQL.",
5
5
  "sideEffects": false,
6
6
  "peerDependencies": {
@@ -8,7 +8,7 @@
8
8
  "@nestjs/core": "^10.0.0",
9
9
  "@nestjs/graphql": "^12.0.0",
10
10
  "graphql": "^15.0.0 || ^16.0.0",
11
- "graphql-yoga": "^5.0.2"
11
+ "graphql-yoga": "^5.1.0"
12
12
  },
13
13
  "repository": {
14
14
  "type": "git",
@@ -1,6 +1,6 @@
1
1
  import type { Express, Request as ExpressRequest, Response as ExpressResponse } from 'express';
2
2
  import type { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify';
3
- import { YogaServerInstance, YogaServerOptions } from 'graphql-yoga';
3
+ import { YogaSchemaDefinition, YogaServerInstance, YogaServerOptions } from 'graphql-yoga';
4
4
  import { AbstractGraphQLDriver, GqlModuleOptions, SubscriptionConfig } from '@nestjs/graphql';
5
5
  export type YogaDriverPlatform = 'express' | 'fastify';
6
6
  export type YogaDriverServerContext<Platform extends YogaDriverPlatform> = Platform extends 'fastify' ? {
@@ -10,14 +10,23 @@ export type YogaDriverServerContext<Platform extends YogaDriverPlatform> = Platf
10
10
  req: ExpressRequest;
11
11
  res: ExpressResponse;
12
12
  };
13
- export type YogaDriverServerOptions<Platform extends YogaDriverPlatform> = Omit<YogaServerOptions<YogaDriverServerContext<Platform>, never>, 'context' | 'schema'>;
13
+ export type YogaDriverServerOptions<Platform extends YogaDriverPlatform> = Omit<YogaServerOptions<YogaDriverServerContext<Platform>, never>, 'context' | 'schema'> & {
14
+ conditionalSchema?: YogaSchemaDefinition<YogaDriverServerContext<Platform>, never> | undefined;
15
+ };
14
16
  export type YogaDriverServerInstance<Platform extends YogaDriverPlatform> = YogaServerInstance<YogaDriverServerContext<Platform>, never>;
15
- export type YogaDriverConfig<Platform extends YogaDriverPlatform = 'express'> = GqlModuleOptions & YogaDriverServerOptions<Platform> & {
17
+ export type YogaDriverConfig<Platform extends YogaDriverPlatform = 'express'> = GqlModuleOptions & YogaDriverServerOptions<Platform> & ({
16
18
  /**
17
19
  * Subscriptions configuration. Passing `true` will install only `graphql-ws`.
18
20
  */
19
21
  subscriptions?: boolean | YogaDriverSubscriptionConfig;
20
- };
22
+ conditionalSchema?: never;
23
+ } | {
24
+ /**
25
+ * TODO: Support conditional schema with subscriptions
26
+ */
27
+ subscriptions?: never;
28
+ conditionalSchema?: YogaSchemaDefinition<YogaDriverServerContext<Platform>, never> | undefined;
29
+ });
21
30
  export type YogaDriverSubscriptionConfig = {
22
31
  'graphql-ws'?: Omit<SubscriptionConfig['graphql-ws'], 'onSubscribe'>;
23
32
  'subscriptions-transport-ws'?: Omit<SubscriptionConfig['subscriptions-transport-ws'], 'onOperation'>;
@@ -26,12 +35,13 @@ export declare abstract class AbstractYogaDriver<Platform extends YogaDriverPlat
26
35
  protected yoga: YogaDriverServerInstance<Platform>;
27
36
  start(options: YogaDriverConfig<Platform>): Promise<void>;
28
37
  stop(): Promise<void>;
29
- protected registerExpress(options: YogaDriverConfig<'express'>, { preStartHook }?: {
38
+ protected registerExpress({ conditionalSchema, ...options }: YogaDriverConfig<'express'>, { preStartHook }?: {
30
39
  preStartHook?: (app: Express) => void;
31
40
  }): void;
32
- protected registerFastify(options: YogaDriverConfig<'fastify'>, { preStartHook }?: {
41
+ protected registerFastify({ conditionalSchema, ...options }: YogaDriverConfig<'fastify'>, { preStartHook }?: {
33
42
  preStartHook?: (app: FastifyInstance) => void;
34
43
  }): void;
44
+ private mergeConditionalSchema;
35
45
  subscriptionWithFilter<TPayload, TVariables, TContext>(instanceRef: unknown, filterFn: (payload: TPayload, variables: TVariables, context: TContext) => boolean | Promise<boolean>, createSubscribeContext: Function): (args_0: TPayload, args_1: TVariables, args_2: TContext) => Promise<import("graphql-yoga").Repeater<TPayload, void, unknown>>;
36
46
  }
37
47
  export declare class YogaDriver<Platform extends YogaDriverPlatform = 'express'> extends AbstractYogaDriver<Platform> {
@@ -1,6 +1,6 @@
1
1
  import type { Express, Request as ExpressRequest, Response as ExpressResponse } from 'express';
2
2
  import type { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify';
3
- import { YogaServerInstance, YogaServerOptions } from 'graphql-yoga';
3
+ import { YogaSchemaDefinition, YogaServerInstance, YogaServerOptions } from 'graphql-yoga';
4
4
  import { AbstractGraphQLDriver, GqlModuleOptions, SubscriptionConfig } from '@nestjs/graphql';
5
5
  export type YogaDriverPlatform = 'express' | 'fastify';
6
6
  export type YogaDriverServerContext<Platform extends YogaDriverPlatform> = Platform extends 'fastify' ? {
@@ -10,14 +10,23 @@ export type YogaDriverServerContext<Platform extends YogaDriverPlatform> = Platf
10
10
  req: ExpressRequest;
11
11
  res: ExpressResponse;
12
12
  };
13
- export type YogaDriverServerOptions<Platform extends YogaDriverPlatform> = Omit<YogaServerOptions<YogaDriverServerContext<Platform>, never>, 'context' | 'schema'>;
13
+ export type YogaDriverServerOptions<Platform extends YogaDriverPlatform> = Omit<YogaServerOptions<YogaDriverServerContext<Platform>, never>, 'context' | 'schema'> & {
14
+ conditionalSchema?: YogaSchemaDefinition<YogaDriverServerContext<Platform>, never> | undefined;
15
+ };
14
16
  export type YogaDriverServerInstance<Platform extends YogaDriverPlatform> = YogaServerInstance<YogaDriverServerContext<Platform>, never>;
15
- export type YogaDriverConfig<Platform extends YogaDriverPlatform = 'express'> = GqlModuleOptions & YogaDriverServerOptions<Platform> & {
17
+ export type YogaDriverConfig<Platform extends YogaDriverPlatform = 'express'> = GqlModuleOptions & YogaDriverServerOptions<Platform> & ({
16
18
  /**
17
19
  * Subscriptions configuration. Passing `true` will install only `graphql-ws`.
18
20
  */
19
21
  subscriptions?: boolean | YogaDriverSubscriptionConfig;
20
- };
22
+ conditionalSchema?: never;
23
+ } | {
24
+ /**
25
+ * TODO: Support conditional schema with subscriptions
26
+ */
27
+ subscriptions?: never;
28
+ conditionalSchema?: YogaSchemaDefinition<YogaDriverServerContext<Platform>, never> | undefined;
29
+ });
21
30
  export type YogaDriverSubscriptionConfig = {
22
31
  'graphql-ws'?: Omit<SubscriptionConfig['graphql-ws'], 'onSubscribe'>;
23
32
  'subscriptions-transport-ws'?: Omit<SubscriptionConfig['subscriptions-transport-ws'], 'onOperation'>;
@@ -26,12 +35,13 @@ export declare abstract class AbstractYogaDriver<Platform extends YogaDriverPlat
26
35
  protected yoga: YogaDriverServerInstance<Platform>;
27
36
  start(options: YogaDriverConfig<Platform>): Promise<void>;
28
37
  stop(): Promise<void>;
29
- protected registerExpress(options: YogaDriverConfig<'express'>, { preStartHook }?: {
38
+ protected registerExpress({ conditionalSchema, ...options }: YogaDriverConfig<'express'>, { preStartHook }?: {
30
39
  preStartHook?: (app: Express) => void;
31
40
  }): void;
32
- protected registerFastify(options: YogaDriverConfig<'fastify'>, { preStartHook }?: {
41
+ protected registerFastify({ conditionalSchema, ...options }: YogaDriverConfig<'fastify'>, { preStartHook }?: {
33
42
  preStartHook?: (app: FastifyInstance) => void;
34
43
  }): void;
44
+ private mergeConditionalSchema;
35
45
  subscriptionWithFilter<TPayload, TVariables, TContext>(instanceRef: unknown, filterFn: (payload: TPayload, variables: TVariables, context: TContext) => boolean | Promise<boolean>, createSubscribeContext: Function): (args_0: TPayload, args_1: TVariables, args_2: TContext) => Promise<import("graphql-yoga").Repeater<TPayload, void, unknown>>;
36
46
  }
37
47
  export declare class YogaDriver<Platform extends YogaDriverPlatform = 'express'> extends AbstractYogaDriver<Platform> {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graphql-yoga/nestjs",
3
- "version": "3.0.2",
3
+ "version": "3.1.0",
4
4
  "type": "module",
5
5
  "description": "GraphQL Yoga driver for NestJS GraphQL.",
6
6
  "repository": {
@@ -46,7 +46,7 @@
46
46
  "@nestjs/core": "^10.0.0",
47
47
  "@nestjs/graphql": "^12.0.0",
48
48
  "graphql": "^15.0.0 || ^16.0.0",
49
- "graphql-yoga": "^5.0.2"
49
+ "graphql-yoga": "^5.1.0"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@nestjs/common": "^10.0.0",
@@ -66,7 +66,7 @@
66
66
  "graphql": "^16.6.0",
67
67
  "graphql-http": "^1.18.0",
68
68
  "graphql-ws": "^5.11.3",
69
- "graphql-yoga": "^5.0.2",
69
+ "graphql-yoga": "^5.1.0",
70
70
  "prettier": "^3.0.0",
71
71
  "reflect-metadata": "^0.1.13",
72
72
  "rxjs": "^7.8.0",
package/src/index.ts CHANGED
@@ -1,7 +1,15 @@
1
1
  import type { Express, Request as ExpressRequest, Response as ExpressResponse } from 'express';
2
2
  import type { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify';
3
- import { printSchema } from 'graphql';
4
- import { createYoga, filter, pipe, YogaServerInstance, YogaServerOptions } from 'graphql-yoga';
3
+ import { GraphQLSchema, printSchema } from 'graphql';
4
+ import {
5
+ createYoga,
6
+ filter,
7
+ mergeSchemas,
8
+ pipe,
9
+ YogaSchemaDefinition,
10
+ YogaServerInstance,
11
+ YogaServerOptions,
12
+ } from 'graphql-yoga';
5
13
  import type { ExecutionParams } from 'subscriptions-transport-ws';
6
14
  import { Injectable, Logger } from '@nestjs/common';
7
15
  import {
@@ -27,7 +35,9 @@ export type YogaDriverServerContext<Platform extends YogaDriverPlatform> =
27
35
  export type YogaDriverServerOptions<Platform extends YogaDriverPlatform> = Omit<
28
36
  YogaServerOptions<YogaDriverServerContext<Platform>, never>,
29
37
  'context' | 'schema'
30
- >;
38
+ > & {
39
+ conditionalSchema?: YogaSchemaDefinition<YogaDriverServerContext<Platform>, never> | undefined;
40
+ };
31
41
 
32
42
  export type YogaDriverServerInstance<Platform extends YogaDriverPlatform> = YogaServerInstance<
33
43
  YogaDriverServerContext<Platform>,
@@ -35,12 +45,25 @@ export type YogaDriverServerInstance<Platform extends YogaDriverPlatform> = Yoga
35
45
  >;
36
46
 
37
47
  export type YogaDriverConfig<Platform extends YogaDriverPlatform = 'express'> = GqlModuleOptions &
38
- YogaDriverServerOptions<Platform> & {
39
- /**
40
- * Subscriptions configuration. Passing `true` will install only `graphql-ws`.
41
- */
42
- subscriptions?: boolean | YogaDriverSubscriptionConfig;
43
- };
48
+ YogaDriverServerOptions<Platform> &
49
+ (
50
+ | {
51
+ /**
52
+ * Subscriptions configuration. Passing `true` will install only `graphql-ws`.
53
+ */
54
+ subscriptions?: boolean | YogaDriverSubscriptionConfig;
55
+ conditionalSchema?: never;
56
+ }
57
+ | {
58
+ /**
59
+ * TODO: Support conditional schema with subscriptions
60
+ */
61
+ subscriptions?: never;
62
+ conditionalSchema?:
63
+ | YogaSchemaDefinition<YogaDriverServerContext<Platform>, never>
64
+ | undefined;
65
+ }
66
+ );
44
67
 
45
68
  export type YogaDriverSubscriptionConfig = {
46
69
  'graphql-ws'?: Omit<SubscriptionConfig['graphql-ws'], 'onSubscribe'>;
@@ -78,7 +101,7 @@ export abstract class AbstractYogaDriver<
78
101
  }
79
102
 
80
103
  protected registerExpress(
81
- options: YogaDriverConfig<'express'>,
104
+ { conditionalSchema, ...options }: YogaDriverConfig<'express'>,
82
105
  { preStartHook }: { preStartHook?: (app: Express) => void } = {},
83
106
  ) {
84
107
  const app: Express = this.httpAdapterHost.httpAdapter.getInstance();
@@ -96,8 +119,11 @@ export abstract class AbstractYogaDriver<
96
119
  }
97
120
  }
98
121
 
122
+ const schema = this.mergeConditionalSchema<'express'>(conditionalSchema, options.schema);
123
+
99
124
  const yoga = createYoga<YogaDriverServerContext<'express'>>({
100
125
  ...options,
126
+ schema,
101
127
  graphqlEndpoint: options.path,
102
128
  // disable logging by default
103
129
  // however, if `true` use nest logger
@@ -115,15 +141,18 @@ export abstract class AbstractYogaDriver<
115
141
  }
116
142
 
117
143
  protected registerFastify(
118
- options: YogaDriverConfig<'fastify'>,
144
+ { conditionalSchema, ...options }: YogaDriverConfig<'fastify'>,
119
145
  { preStartHook }: { preStartHook?: (app: FastifyInstance) => void } = {},
120
146
  ) {
121
147
  const app: FastifyInstance = this.httpAdapterHost.httpAdapter.getInstance();
122
148
 
123
149
  preStartHook?.(app);
124
150
 
151
+ const schema = this.mergeConditionalSchema<'fastify'>(conditionalSchema, options.schema);
152
+
125
153
  const yoga = createYoga<YogaDriverServerContext<'fastify'>>({
126
154
  ...options,
155
+ schema,
127
156
  graphqlEndpoint: options.path,
128
157
  // disable logging by default
129
158
  // however, if `true` use fastify logger
@@ -144,6 +173,38 @@ export abstract class AbstractYogaDriver<
144
173
  });
145
174
  }
146
175
 
176
+ private mergeConditionalSchema<T extends YogaDriverPlatform>(
177
+ conditionalSchema: YogaSchemaDefinition<YogaDriverServerContext<T>, never> | undefined,
178
+ schema?: GraphQLSchema,
179
+ ) {
180
+ let mergedSchema: YogaSchemaDefinition<YogaDriverServerContext<T>, never> | undefined = schema;
181
+
182
+ if (conditionalSchema) {
183
+ mergedSchema = async request => {
184
+ const schemas: GraphQLSchema[] = [];
185
+
186
+ if (schema) {
187
+ schemas.push(schema);
188
+ }
189
+
190
+ const conditionalSchemaResult =
191
+ typeof conditionalSchema === 'function'
192
+ ? await conditionalSchema(request)
193
+ : await conditionalSchema;
194
+
195
+ if (conditionalSchemaResult) {
196
+ schemas.push(conditionalSchemaResult);
197
+ }
198
+
199
+ return mergeSchemas({
200
+ schemas,
201
+ });
202
+ };
203
+ }
204
+
205
+ return mergedSchema;
206
+ }
207
+
147
208
  public subscriptionWithFilter<TPayload, TVariables, TContext>(
148
209
  instanceRef: unknown,
149
210
  filterFn: (
@@ -198,6 +259,12 @@ export class YogaDriver<
198
259
  if (config['graphql-ws']) {
199
260
  config['graphql-ws'] = typeof config['graphql-ws'] === 'object' ? config['graphql-ws'] : {};
200
261
 
262
+ if (options.conditionalSchema) {
263
+ throw new Error(`
264
+ Conditional schema is not supported with graphql-ws.
265
+ `);
266
+ }
267
+
201
268
  config['graphql-ws'].onSubscribe = async (ctx, msg) => {
202
269
  const { schema, execute, subscribe, contextFactory, parse, validate } =
203
270
  this.yoga.getEnveloped({
@@ -229,6 +296,12 @@ export class YogaDriver<
229
296
  ? config['subscriptions-transport-ws']
230
297
  : {};
231
298
 
299
+ if (options.conditionalSchema) {
300
+ throw new Error(`
301
+ Conditional schema is not supported with subscriptions-transport-ws.
302
+ `);
303
+ }
304
+
232
305
  config['subscriptions-transport-ws'].onOperation = async (
233
306
  _msg: unknown,
234
307
  params: ExecutionParams,