@tinkerstack/graphql-annotation 0.0.3 → 0.0.6

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/README.md CHANGED
@@ -1,138 +1,138 @@
1
- <center>
2
- <img src="https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fcdn.icon-icons.com%2Ficons2%2F2699%2FPNG%2F512%2Fgraphql_logo_icon_171045.png&f=1&nofb=1&ipt=e40678a4804af7f493102aa8bcc97bacbfdfee9dac86e14c75ab7afb00a237b5" height="150px">
3
- <h1>GraphQL Annotation</h1>
4
- <p>A set of tools for extending GraphQL stitching capabilities through annotations</p>
5
- </center>
6
-
7
- ---
8
-
9
- ## Who is this intended for?
10
-
11
- This library is designed to solve a specific scenario in mind:
12
-
13
- 1. There's a primary `Gateway` and separately developed `SubGateway`s, both of each uses `graphql`.
14
- 2. Front-end or external non-backend consumers interact with `SubGateway` resolvers stitched through `Gateway`
15
- 3. Resolvers at `SubGateway` requires additional resource/guard/processing from `Gateway`.
16
- 4. `SubGateway` team does not have access to `Gateway` nor can they run a local instance.
17
- 5. `SubGateway` team **does not require** `Gateway` features during development, only during deployment.
18
-
19
- Available solutions often utilize `Remote-Produce-Calls (RPCs)` libraries to let `SubGateway` invoke `Gateway` methods through HTTP transport, which unfortunately fails point 4 and 5, of which this library answers through `annotations`.
20
-
21
- **However**, if `SubGateway` needs to make additional calls to `Gateway` for mutation or other purposes, then this library should only be considered as a mean of optimization and you are better off just running an `RPC` library at the small of performance and back-and-forth.
22
-
23
- **TL;DR:** Only use this library if you HAVE TO achieve complete isolation between `Gateway` and `SubGateway` development cycle.
24
-
25
- ## Usage
26
-
27
- You can find examples in `src/examples` for more details. Note that `graphql-annotation` should be replaced with workspace name in internal projects.
28
-
29
- ```ts
30
- // gateway
31
-
32
- import {
33
- GraphQLAnnotationModule,
34
- GraphQLAnnotationSchemaLoader
35
- } from "graphql-annotation";
36
-
37
- @Module({
38
- imports: [
39
- GraphQLAnnotationModule.forRoot(),
40
- GraphQLModule.forRootAsync<ApolloDriverConfig>({
41
- driver: ApolloDriver,
42
- useFactory: (loader: GraphQLAnnotatedSchemaLoader) => ({
43
- async transformSchema(schema) {
44
- return stitchSchemas({
45
- subschemas: [
46
- { schema },
47
- {
48
- // Load external annotated schemas
49
- schema: await loader.load({
50
- example: "http://localhost:3031/graphql",
51
- }),
52
- },
53
- ],
54
- });
55
- },
56
- }),
57
- inject: [GraphQLAnnotatedSchemaLoader],
58
- }),
59
- ],
60
- })
61
- export class GatewayAppModule {}
62
-
63
-
64
- // It is recommended that you wrap the `Annotate` decorator in a function and in the gateway to ensure `gateway` team knows that's implemented. `sub-gateway` team could reference this through github submodule.
65
-
66
- export type RoleGroups = ("user" | "admin" | "super-admin")[];
67
- export const ProtectedResolver = (roles: RoleGroups) =>
68
- Annotate("protected", { data: { roles } });
69
-
70
- export const InjectableArg = (argName: string, resourceType: string) =>
71
- Annotate("resource", { data: { resourceType }, parameter: argName });
72
-
73
- @Injectable()
74
- export class ExampleGuard implements CanActivate {
75
- canActivate(context: ExecutionContext) {
76
- // Do something with your execution context
77
- return true;
78
- }
79
- }
80
-
81
- @Resolver()
82
- export class SubgatewayResolver {
83
- // NOTE: You can use normal nest and graphql decorators.
84
- // Just note that `ResolveAnnotation` must be in a `Resolver`
85
-
86
- @UseGuards(ExampleGuard)
87
- @ResolveAnnotation("protected")
88
- verifyUser(context: ExecutionContext, next: () => void) {}
89
-
90
- // If empty would use function name as annotation tag
91
- @ResolveAnnotation()
92
- resource(
93
- // WARN: this is NOT validated like in graphql though
94
- @Args("resourceType") resourceType: string,
95
- @Context() context: GraphQLExecutionContext,
96
- ) {
97
- return "this-is-gateway-provided-username";
98
- }
99
- }
100
-
101
- // ---------------------------------------------
102
-
103
- // sub-gateway
104
- @Module({
105
- imports: [
106
- GraphQLModule.forRoot<ApolloDriverConfig>({
107
- /* Put your graphql config here*/
108
- }),
109
- GraphQLAnnotationModule.forRoot({
110
- serveAnnotations: true,
111
- // Name is only for identification at the time of writing, which does not support annotation filtering.
112
- serveConfig: { name: "<subgateway-a>" },
113
- }),
114
- ExampleProducerModule,
115
- ],
116
- })
117
- export class SubGatewayAppModule {}
118
-
119
- @Resolver()
120
- export class ExampleProducerResolver {
121
- @Query(() => [String])
122
- @ProtectedResolver(["admin"])
123
- testProtectedQuery() {
124
- return ["This resolver should only be available to if guard check passed"];
125
- }
126
- @Query(() => [String])
127
- testQueryWithParam(
128
- @InjectableArg("username", "session:username")
129
- username: string
130
- ) {
131
- return [`Received params: ${username}`];
132
- }
133
- @Query(() => [String])
134
- testPublicQuery() {
135
- return ["This resolver should be available to everyone"];
136
- }
137
- }
138
- ```
1
+ <center>
2
+ <img src="https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fcdn.icon-icons.com%2Ficons2%2F2699%2FPNG%2F512%2Fgraphql_logo_icon_171045.png&f=1&nofb=1&ipt=e40678a4804af7f493102aa8bcc97bacbfdfee9dac86e14c75ab7afb00a237b5" height="150px">
3
+ <h1>GraphQL Annotation</h1>
4
+ <p>A set of tools for extending GraphQL stitching capabilities through annotations</p>
5
+ </center>
6
+
7
+ ---
8
+
9
+ ## Who is this intended for?
10
+
11
+ This library is designed to solve a specific scenario in mind:
12
+
13
+ 1. There's a primary `Gateway` and separately developed `SubGateway`s, both of each uses `graphql`.
14
+ 2. Front-end or external non-backend consumers interact with `SubGateway` resolvers stitched through `Gateway`
15
+ 3. Resolvers at `SubGateway` requires additional resource/guard/processing from `Gateway`.
16
+ 4. `SubGateway` team does not have access to `Gateway` nor can they run a local instance.
17
+ 5. `SubGateway` team **does not require** `Gateway` features during development, only during deployment.
18
+
19
+ Available solutions often utilize `Remote-Produce-Calls (RPCs)` libraries to let `SubGateway` invoke `Gateway` methods through HTTP transport, which unfortunately fails point 4 and 5, of which this library answers through `annotations`.
20
+
21
+ **However**, if `SubGateway` needs to make additional calls to `Gateway` for mutation or other purposes, then this library should only be considered as a mean of optimization and you are better off just running an `RPC` library at the small of performance and back-and-forth.
22
+
23
+ **TL;DR:** Only use this library if you HAVE TO achieve complete isolation between `Gateway` and `SubGateway` development cycle.
24
+
25
+ ## Usage
26
+
27
+ You can find examples in `src/examples` for more details. Note that `graphql-annotation` should be replaced with workspace name in internal projects.
28
+
29
+ ```ts
30
+ // gateway
31
+
32
+ import {
33
+ GraphQLAnnotationModule,
34
+ GraphQLAnnotationSchemaLoader
35
+ } from "graphql-annotation";
36
+
37
+ @Module({
38
+ imports: [
39
+ GraphQLAnnotationModule.forRoot(),
40
+ GraphQLModule.forRootAsync<ApolloDriverConfig>({
41
+ driver: ApolloDriver,
42
+ useFactory: (loader: GraphQLAnnotatedSchemaLoader) => ({
43
+ async transformSchema(schema) {
44
+ return stitchSchemas({
45
+ subschemas: [
46
+ { schema },
47
+ {
48
+ // Load external annotated schemas
49
+ schema: await loader.load({
50
+ example: "http://localhost:3031/graphql",
51
+ }),
52
+ },
53
+ ],
54
+ });
55
+ },
56
+ }),
57
+ inject: [GraphQLAnnotatedSchemaLoader],
58
+ }),
59
+ ],
60
+ })
61
+ export class GatewayAppModule {}
62
+
63
+
64
+ // It is recommended that you wrap the `Annotate` decorator in a function and in the gateway to ensure `gateway` team knows that's implemented. `sub-gateway` team could reference this through github submodule.
65
+
66
+ export type RoleGroups = ("user" | "admin" | "super-admin")[];
67
+ export const ProtectedResolver = (roles: RoleGroups) =>
68
+ Annotate("protected", { data: { roles } });
69
+
70
+ export const InjectableArg = (argName: string, resourceType: string) =>
71
+ Annotate("resource", { data: { resourceType }, parameter: argName });
72
+
73
+ @Injectable()
74
+ export class ExampleGuard implements CanActivate {
75
+ canActivate(context: ExecutionContext) {
76
+ // Do something with your execution context
77
+ return true;
78
+ }
79
+ }
80
+
81
+ @Resolver()
82
+ export class SubgatewayResolver {
83
+ // NOTE: You can use normal nest and graphql decorators.
84
+ // Just note that `ResolveAnnotation` must be in a `Resolver`
85
+
86
+ @UseGuards(ExampleGuard)
87
+ @ResolveAnnotation("protected")
88
+ verifyUser(context: ExecutionContext, next: () => void) {}
89
+
90
+ // If empty would use function name as annotation tag
91
+ @ResolveAnnotation()
92
+ resource(
93
+ // WARN: this is NOT validated like in graphql though
94
+ @Args("resourceType") resourceType: string,
95
+ @Context() context: GraphQLExecutionContext,
96
+ ) {
97
+ return "this-is-gateway-provided-username";
98
+ }
99
+ }
100
+
101
+ // ---------------------------------------------
102
+
103
+ // sub-gateway
104
+ @Module({
105
+ imports: [
106
+ GraphQLModule.forRoot<ApolloDriverConfig>({
107
+ /* Put your graphql config here*/
108
+ }),
109
+ GraphQLAnnotationModule.forRoot({
110
+ serveAnnotations: true,
111
+ // Name is only for identification at the time of writing, which does not support annotation filtering.
112
+ serveConfig: { name: "<subgateway-a>" },
113
+ }),
114
+ ExampleProducerModule,
115
+ ],
116
+ })
117
+ export class SubGatewayAppModule {}
118
+
119
+ @Resolver()
120
+ export class ExampleProducerResolver {
121
+ @Query(() => [String])
122
+ @ProtectedResolver(["admin"])
123
+ testProtectedQuery() {
124
+ return ["This resolver should only be available to if guard check passed"];
125
+ }
126
+ @Query(() => [String])
127
+ testQueryWithParam(
128
+ @InjectableArg("username", "session:username")
129
+ username: string
130
+ ) {
131
+ return [`Received params: ${username}`];
132
+ }
133
+ @Query(() => [String])
134
+ testPublicQuery() {
135
+ return ["This resolver should be available to everyone"];
136
+ }
137
+ }
138
+ ```
package/dist/index.d.mts CHANGED
@@ -58,7 +58,9 @@ declare class GraphQLAnnotatedSchemaLoader {
58
58
  private readonly externalContextCreator;
59
59
  private _logger;
60
60
  constructor(resolverDiscoveryService: ResolverDiscoveryService, metadataScanner: MetadataScanner, externalContextCreator: ExternalContextCreator);
61
- load(sources: AnnotationSchemaSources): Promise<GraphQLSchema>;
61
+ load(sources: AnnotationSchemaSources, opts?: {
62
+ ignoreMissingSources?: boolean;
63
+ }): Promise<GraphQLSchema>;
62
64
  private discoverAnnotationResolvers;
63
65
  private batchLoadSources;
64
66
  private loadAnnotations;
package/dist/index.d.ts CHANGED
@@ -58,7 +58,9 @@ declare class GraphQLAnnotatedSchemaLoader {
58
58
  private readonly externalContextCreator;
59
59
  private _logger;
60
60
  constructor(resolverDiscoveryService: ResolverDiscoveryService, metadataScanner: MetadataScanner, externalContextCreator: ExternalContextCreator);
61
- load(sources: AnnotationSchemaSources): Promise<GraphQLSchema>;
61
+ load(sources: AnnotationSchemaSources, opts?: {
62
+ ignoreMissingSources?: boolean;
63
+ }): Promise<GraphQLSchema>;
62
64
  private discoverAnnotationResolvers;
63
65
  private batchLoadSources;
64
66
  private loadAnnotations;
package/dist/index.js CHANGED
@@ -328,8 +328,10 @@ var GraphQLAnnotatedSchemaLoader = class {
328
328
  this.metadataScanner = metadataScanner;
329
329
  this.externalContextCreator = externalContextCreator;
330
330
  }
331
- async load(sources) {
332
- const loadedSources = await this.batchLoadSources(sources);
331
+ async load(sources, opts) {
332
+ const loadedSources = await this.batchLoadSources(sources, {
333
+ ignoreMissingSources: opts?.ignoreMissingSources ?? false
334
+ });
333
335
  const schema = (0, import_stitch.stitchSchemas)({
334
336
  subschemas: loadedSources.map((s) => s.subschema)
335
337
  });
@@ -349,7 +351,7 @@ var GraphQLAnnotatedSchemaLoader = class {
349
351
  }
350
352
  return annotationResolvers;
351
353
  }
352
- async batchLoadSources(sources) {
354
+ async batchLoadSources(sources, opts) {
353
355
  const pending = Object.entries(sources).map(async ([name, url]) => {
354
356
  const loadId = `${name}@${url}`;
355
357
  try {
@@ -371,7 +373,11 @@ var GraphQLAnnotatedSchemaLoader = class {
371
373
  }
372
374
  });
373
375
  const [loaded, failed] = split(await Promise.allSettled(pending), (q) => q.status === "fulfilled");
374
- if (failed.length > 0) throw new Error(`Failed to load ${failed.length} schema(s) from sources.`);
376
+ const shouldThrow = !(opts?.ignoreMissingSources ?? false);
377
+ if (failed.length > 0) {
378
+ if (shouldThrow) throw new Error(`Failed to load ${failed.length} schema(s) from sources.`);
379
+ else this._logger.warn(`Failed to load ${failed.length}, ignoring.`);
380
+ }
375
381
  return loaded.map((l) => l.value);
376
382
  }
377
383
  async loadAnnotations(url) {
package/dist/index.mjs CHANGED
@@ -299,8 +299,10 @@ var GraphQLAnnotatedSchemaLoader = class {
299
299
  this.metadataScanner = metadataScanner;
300
300
  this.externalContextCreator = externalContextCreator;
301
301
  }
302
- async load(sources) {
303
- const loadedSources = await this.batchLoadSources(sources);
302
+ async load(sources, opts) {
303
+ const loadedSources = await this.batchLoadSources(sources, {
304
+ ignoreMissingSources: opts?.ignoreMissingSources ?? false
305
+ });
304
306
  const schema = stitchSchemas({
305
307
  subschemas: loadedSources.map((s) => s.subschema)
306
308
  });
@@ -320,7 +322,7 @@ var GraphQLAnnotatedSchemaLoader = class {
320
322
  }
321
323
  return annotationResolvers;
322
324
  }
323
- async batchLoadSources(sources) {
325
+ async batchLoadSources(sources, opts) {
324
326
  const pending = Object.entries(sources).map(async ([name, url]) => {
325
327
  const loadId = `${name}@${url}`;
326
328
  try {
@@ -342,7 +344,11 @@ var GraphQLAnnotatedSchemaLoader = class {
342
344
  }
343
345
  });
344
346
  const [loaded, failed] = split(await Promise.allSettled(pending), (q) => q.status === "fulfilled");
345
- if (failed.length > 0) throw new Error(`Failed to load ${failed.length} schema(s) from sources.`);
347
+ const shouldThrow = !(opts?.ignoreMissingSources ?? false);
348
+ if (failed.length > 0) {
349
+ if (shouldThrow) throw new Error(`Failed to load ${failed.length} schema(s) from sources.`);
350
+ else this._logger.warn(`Failed to load ${failed.length}, ignoring.`);
351
+ }
346
352
  return loaded.map((l) => l.value);
347
353
  }
348
354
  async loadAnnotations(url) {
package/nest-cli.json CHANGED
@@ -1,9 +1,9 @@
1
- {
2
- "$schema": "https://json.schemastore.org/nest-cli",
3
- "collection": "@nestjs/schematics",
4
- "sourceRoot": "src",
5
- "entryFile": "example/main",
6
- "compilerOptions": {
7
- "tsConfigPath": "tsconfig.json"
8
- }
1
+ {
2
+ "$schema": "https://json.schemastore.org/nest-cli",
3
+ "collection": "@nestjs/schematics",
4
+ "sourceRoot": "src",
5
+ "entryFile": "example/main",
6
+ "compilerOptions": {
7
+ "tsConfigPath": "tsconfig.json"
8
+ }
9
9
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tinkerstack/graphql-annotation",
3
- "version": "0.0.3",
3
+ "version": "0.0.6",
4
4
  "description": "Better type-safe-able graphql directives",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -14,11 +14,15 @@
14
14
  "@graphql-tools/stitch": "^10.1.8",
15
15
  "@graphql-tools/utils": "^11.0.0",
16
16
  "@graphql-tools/wrap": "^11.1.4",
17
- "class-transformer": "^0.5.1",
18
17
  "graphql-request": "^7.2.0"
19
18
  },
20
19
  "publishConfig": {
21
- "access": "public"
20
+ "access": "public",
21
+ "provenance": true
22
+ },
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/plasteek/tinkerstack.git"
22
26
  },
23
27
  "peerDependencies": {
24
28
  "@nestjs/common": "^10 || ^11",
@@ -40,6 +44,7 @@
40
44
  "@nestjs/mapped-types": "^2.1.0",
41
45
  "@nestjs/platform-fastify": "^11.1.11",
42
46
  "@swc/core": "^1.15.11",
47
+ "class-transformer": "^0.5.1",
43
48
  "class-validator": "^0.14.2",
44
49
  "concurrently": "^9.2.1",
45
50
  "eslint": "^9.37.0",
@@ -1,38 +1,38 @@
1
- import { Module } from "@nestjs/common";
2
- import { GraphQLModule } from "@nestjs/graphql";
3
-
4
- import { ApolloDriver, ApolloDriverConfig } from "@nestjs/apollo";
5
- import { ExampleConsumerModule } from "./consumer.example";
6
- import { GraphQLAnnotatedSchemaLoader } from "@/modules/core/annotation.loader";
7
- import { GraphQLAnnotationModule } from "@/modules/core/annotation.module";
8
- import { stitchSchemas } from "@graphql-tools/stitch";
9
-
10
- @Module({
11
- imports: [
12
- ExampleConsumerModule,
13
- GraphQLAnnotationModule.forRoot(),
14
- GraphQLModule.forRootAsync<ApolloDriverConfig>({
15
- driver: ApolloDriver,
16
- useFactory: (loader: GraphQLAnnotatedSchemaLoader) => ({
17
- graphiql: true,
18
- playground: true,
19
- autoSchemaFile: "./src/example/consumer/consumer.schema.gql",
20
- async transformSchema(schema) {
21
- return stitchSchemas({
22
- subschemas: [
23
- { schema },
24
- {
25
- // Load external annotated schemas
26
- schema: await loader.load({
27
- example: "http://localhost:3031/graphql",
28
- }),
29
- },
30
- ],
31
- });
32
- },
33
- }),
34
- inject: [GraphQLAnnotatedSchemaLoader],
35
- }),
36
- ],
37
- })
38
- export class ExampleConsumerApp {}
1
+ import { Module } from "@nestjs/common";
2
+ import { GraphQLModule } from "@nestjs/graphql";
3
+
4
+ import { ApolloDriver, ApolloDriverConfig } from "@nestjs/apollo";
5
+ import { ExampleConsumerModule } from "./consumer.example";
6
+ import { GraphQLAnnotatedSchemaLoader } from "@/modules/core/annotation.loader";
7
+ import { GraphQLAnnotationModule } from "@/modules/core/annotation.module";
8
+ import { stitchSchemas } from "@graphql-tools/stitch";
9
+
10
+ @Module({
11
+ imports: [
12
+ ExampleConsumerModule,
13
+ GraphQLAnnotationModule.forRoot(),
14
+ GraphQLModule.forRootAsync<ApolloDriverConfig>({
15
+ driver: ApolloDriver,
16
+ useFactory: (loader: GraphQLAnnotatedSchemaLoader) => ({
17
+ graphiql: true,
18
+ playground: true,
19
+ autoSchemaFile: "./src/example/consumer/consumer.schema.gql",
20
+ async transformSchema(schema) {
21
+ return stitchSchemas({
22
+ subschemas: [
23
+ { schema },
24
+ {
25
+ // Load external annotated schemas
26
+ schema: await loader.load({
27
+ example: "http://localhost:3031/graphql",
28
+ }),
29
+ },
30
+ ],
31
+ });
32
+ },
33
+ }),
34
+ inject: [GraphQLAnnotatedSchemaLoader],
35
+ }),
36
+ ],
37
+ })
38
+ export class ExampleConsumerApp {}
@@ -1,57 +1,57 @@
1
- import { Annotate, ResolveAnnotation } from "@/modules/core";
2
- import {
3
- CanActivate,
4
- ExecutionContext,
5
- Injectable,
6
- Module,
7
- UseGuards,
8
- } from "@nestjs/common";
9
- import {
10
- Args,
11
- Context,
12
- GraphQLExecutionContext,
13
- Query,
14
- Resolver,
15
- } from "@nestjs/graphql";
16
-
17
- // Export for external
18
- export type RoleGroups = ("user" | "admin" | "super-admin")[];
19
- export const ProtectedResolver = (roles: RoleGroups) =>
20
- Annotate("protected", { data: { roles } });
21
- export const InjectableArg = (argName: string, resourceType: string) =>
22
- Annotate("resource", { data: { resourceType }, parameter: argName });
23
-
24
- @Injectable()
25
- export class ExampleGuard implements CanActivate {
26
- canActivate(context: ExecutionContext) {
27
- // Do something with your execution context
28
- return true;
29
- }
30
- }
31
-
32
- @Resolver()
33
- export class ExampleConsumerResolver {
34
- @Query(() => [String])
35
- exampleOut() {
36
- return ["this is from consumer"];
37
- }
38
-
39
- @UseGuards(ExampleGuard)
40
- @ResolveAnnotation("protected")
41
- verifyUser(context: ExecutionContext, next: () => void) {
42
- console.log("I AM HERE");
43
- }
44
-
45
- // Should use the name
46
- @ResolveAnnotation("resource")
47
- resolveResource(
48
- @Args("resourceType") resourceType: string,
49
- @Context() context: GraphQLExecutionContext,
50
- ) {
51
- console.log(resourceType);
52
- return "this-is-gateway-provided-username";
53
- }
54
- }
55
-
56
- @Module({ providers: [ExampleConsumerResolver] })
57
- export class ExampleConsumerModule {}
1
+ import { Annotate, ResolveAnnotation } from "@/modules/core";
2
+ import {
3
+ CanActivate,
4
+ ExecutionContext,
5
+ Injectable,
6
+ Module,
7
+ UseGuards,
8
+ } from "@nestjs/common";
9
+ import {
10
+ Args,
11
+ Context,
12
+ GraphQLExecutionContext,
13
+ Query,
14
+ Resolver,
15
+ } from "@nestjs/graphql";
16
+
17
+ // Export for external
18
+ export type RoleGroups = ("user" | "admin" | "super-admin")[];
19
+ export const ProtectedResolver = (roles: RoleGroups) =>
20
+ Annotate("protected", { data: { roles } });
21
+ export const InjectableArg = (argName: string, resourceType: string) =>
22
+ Annotate("resource", { data: { resourceType }, parameter: argName });
23
+
24
+ @Injectable()
25
+ export class ExampleGuard implements CanActivate {
26
+ canActivate(context: ExecutionContext) {
27
+ // Do something with your execution context
28
+ return true;
29
+ }
30
+ }
31
+
32
+ @Resolver()
33
+ export class ExampleConsumerResolver {
34
+ @Query(() => [String])
35
+ exampleOut() {
36
+ return ["this is from consumer"];
37
+ }
38
+
39
+ @UseGuards(ExampleGuard)
40
+ @ResolveAnnotation("protected")
41
+ verifyUser(context: ExecutionContext, next: () => void) {
42
+ console.log("I AM HERE");
43
+ }
44
+
45
+ // Should use the name
46
+ @ResolveAnnotation("resource")
47
+ resolveResource(
48
+ @Args("resourceType") resourceType: string,
49
+ @Context() context: GraphQLExecutionContext,
50
+ ) {
51
+ console.log(resourceType);
52
+ return "this-is-gateway-provided-username";
53
+ }
54
+ }
55
+
56
+ @Module({ providers: [ExampleConsumerResolver] })
57
+ export class ExampleConsumerModule {}
@@ -1,23 +1,23 @@
1
- import { NestFactory } from "@nestjs/core";
2
-
3
- import { FastifyAdapter } from "@nestjs/platform-fastify";
4
- import { ExampleProducerApp } from "./producer/producer.app";
5
- import { ConsoleLogger, Type } from "@nestjs/common";
6
- import { ExampleConsumerApp } from "./consumer/consumer.app";
7
-
8
- export async function bootstrap(name: string, module: Type, port: number) {
9
- const app = await NestFactory.create(module, new FastifyAdapter(), {
10
- logger: new ConsoleLogger({ prefix: name }),
11
- });
12
- await app.listen(port);
13
-
14
- console.log(
15
- `Listening on localhost:${port}. Playground: http://localhost:${port}/graphql`
16
- );
17
- }
18
-
19
- async function main() {
20
- await bootstrap("example-producer", ExampleProducerApp, 3031);
21
- await bootstrap("example-consumer", ExampleConsumerApp, 3030);
22
- }
23
- void main();
1
+ import { NestFactory } from "@nestjs/core";
2
+
3
+ import { FastifyAdapter } from "@nestjs/platform-fastify";
4
+ import { ExampleProducerApp } from "./producer/producer.app";
5
+ import { ConsoleLogger, Type } from "@nestjs/common";
6
+ import { ExampleConsumerApp } from "./consumer/consumer.app";
7
+
8
+ export async function bootstrap(name: string, module: Type, port: number) {
9
+ const app = await NestFactory.create(module, new FastifyAdapter(), {
10
+ logger: new ConsoleLogger({ prefix: name }),
11
+ });
12
+ await app.listen(port);
13
+
14
+ console.log(
15
+ `Listening on localhost:${port}. Playground: http://localhost:${port}/graphql`
16
+ );
17
+ }
18
+
19
+ async function main() {
20
+ await bootstrap("example-producer", ExampleProducerApp, 3031);
21
+ await bootstrap("example-consumer", ExampleConsumerApp, 3030);
22
+ }
23
+ void main();