Skip to content

Commit 3161e7c

Browse files
committed
Convert remaining plugins from apollo to yoga
1 parent 23a4f40 commit 3161e7c

File tree

4 files changed

+73
-82
lines changed

4 files changed

+73
-82
lines changed

src/components/authentication/current-user.provider.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { Plugin } from '@nestjs/apollo';
21
import {
32
CallHandler,
43
ExecutionContext,
@@ -13,7 +12,6 @@ import { EdgeDB, OptionsFn } from '~/core/edgedb';
1312
import { HttpMiddleware } from '~/core/http';
1413

1514
@Injectable()
16-
@Plugin()
1715
export class EdgeDBCurrentUserProvider
1816
implements HttpMiddleware, NestInterceptor
1917
{
Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,38 @@
11
import {
2-
ApolloServerPlugin as ApolloPlugin,
3-
GraphQLRequestContext as RequestContext,
4-
GraphQLRequestListener as RequestListener,
5-
} from '@apollo/server';
6-
import { Plugin } from '@nestjs/apollo';
2+
OnExecuteEventPayload as OnExecute,
3+
OnSubscribeEventPayload as OnSubscribe,
4+
} from '@envelop/types';
5+
import { Injectable } from '@nestjs/common';
76
import { GqlContextType as ContextType } from '~/common';
87
import { maskSecrets } from '~/common/mask-secrets';
98
import { ILogger, Logger } from '../logger';
9+
import { Plugin } from './plugin.decorator';
1010

1111
/**
1212
* Logging for GraphQL errors that are not handled anywhere else
1313
* Note: Lots of assumptions here.
1414
*/
1515
@Plugin()
16-
export class GraphqlLoggingPlugin implements ApolloPlugin<ContextType> {
16+
@Injectable()
17+
export class GraphqlLoggingPlugin {
1718
constructor(@Logger('graphql') private readonly logger: ILogger) {}
1819

19-
async requestDidStart(
20-
_context: RequestContext<ContextType>,
21-
): Promise<RequestListener<ContextType>> {
22-
return {
23-
executionDidStart: async ({ operationName, operation, request }) => {
24-
if (operationName === 'IntrospectionQuery') {
25-
return;
26-
}
27-
this.logger.info(`Received ${operation.operation}`, {
28-
operation: operationName,
29-
...maskSecrets(request.variables ?? {}),
30-
});
31-
},
32-
};
20+
onExecute: Plugin['onExecute'] = ({ args }) => {
21+
this.logReq(args);
22+
};
23+
24+
onSubscribe: Plugin['onSubscribe'] = ({ args }) => {
25+
this.logReq(args);
26+
};
27+
28+
logReq(args: (OnExecute<ContextType> | OnSubscribe<ContextType>)['args']) {
29+
const { operationName, variableValues, contextValue } = args;
30+
if (operationName === 'IntrospectionQuery') {
31+
return;
32+
}
33+
this.logger.info(`Received ${contextValue.operation.operation}`, {
34+
operation: operationName,
35+
...maskSecrets(variableValues ?? {}),
36+
});
3337
}
3438
}
Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,12 @@
1-
import {
2-
ApolloServerPlugin as ApolloPlugin,
3-
GraphQLRequestContext as RequestContext,
4-
GraphQLRequestListener as RequestListener,
5-
GraphQLRequestContextWillSendResponse as WillSendResponse,
6-
} from '@apollo/server';
7-
import { Plugin } from '@nestjs/apollo';
8-
import { GqlContextType as ContextType } from '~/common';
1+
import { Plugin } from './plugin.decorator';
92

103
@Plugin()
11-
export class GraphqlSessionPlugin implements ApolloPlugin<ContextType> {
12-
async requestDidStart(
13-
_context: RequestContext<ContextType>,
14-
): Promise<RequestListener<ContextType>> {
15-
return {
16-
async willSendResponse(context: WillSendResponse<ContextType>) {
17-
// I suspect this is important to ensure that subscriptions
18-
// will close without burdening the subscribers to do so.
19-
context.contextValue.session$.complete();
20-
},
21-
};
22-
}
4+
export class GraphqlSessionPlugin {
5+
onExecute: Plugin['onExecute'] = ({ args }) => ({
6+
onExecuteDone: () => {
7+
// I suspect this is important to ensure that subscriptions
8+
// will close without burdening the subscribers to do so.
9+
args.contextValue.session$.complete();
10+
},
11+
});
2312
}

src/core/graphql/graphql-tracing.plugin.ts

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,60 @@
1-
import {
2-
ApolloServerPlugin as ApolloPlugin,
3-
GraphQLRequestExecutionListener as ExecutionListener,
4-
GraphQLRequestListener as Listener,
5-
} from '@apollo/server';
6-
import { Plugin } from '@nestjs/apollo';
71
import { FieldMiddleware } from '@nestjs/graphql';
2+
import { createHash } from 'crypto';
83
import { GraphQLResolveInfo as ResolveInfo, ResponsePath } from 'graphql';
9-
import { GqlContextType as ContextType } from '~/common';
104
import { Segment, TracingService } from '../tracing';
5+
import { Plugin } from './plugin.decorator';
116

127
@Plugin()
13-
export class GraphqlTracingPlugin implements ApolloPlugin<ContextType> {
8+
export class GraphqlTracingPlugin {
149
constructor(private readonly tracing: TracingService) {}
1510

16-
async requestDidStart(): Promise<Listener<ContextType>> {
17-
return {
18-
executionDidStart: async (
19-
reqContext,
20-
): Promise<ExecutionListener<ContextType>> => {
21-
let segment: Segment;
22-
try {
23-
segment = this.tracing.rootSegment;
24-
} catch (e) {
25-
return {};
26-
}
11+
onExecute: Plugin['onExecute'] = ({ args }) => {
12+
const { operationName, contextValue } = args;
13+
const { operation, session$, params } = contextValue;
14+
15+
let segment: Segment;
16+
try {
17+
segment = this.tracing.rootSegment;
18+
} catch (e) {
19+
return {};
20+
}
21+
22+
segment.name =
23+
operationName ??
24+
(params.query
25+
? createHash('sha256').update(params.query).digest('hex')
26+
: undefined);
27+
segment.addAnnotation(operation.operation, true);
2728

28-
segment.name = reqContext.operationName ?? reqContext.queryHash;
29-
segment.addAnnotation(reqContext.operation.operation, true);
29+
// Append operation name to url since all gql requests hit a single http endpoint
30+
if (
31+
// Check if http middleware is present, confirming this is a root subsegment
32+
(segment as any).http?.request &&
33+
// Confirm operation caller didn't do it themselves.
34+
// They should, but it's not currently required.
35+
!(segment as any).http.request.url.endsWith(segment.name)
36+
) {
37+
// @ts-expect-error xray library types suck
38+
(segment.http.request.url as string) += '/' + segment.name;
39+
}
3040

31-
// Append operation name to url since all gql requests hit a single http endpoint
32-
if (
33-
// Check if http middleware is present, confirming this is a root subsegment
34-
(segment as any).http?.request &&
35-
// Confirm operation caller didn't do it themselves.
36-
// They should, but it's not currently required.
37-
!(segment as any).http.request.url.endsWith(segment.name)
38-
) {
39-
// @ts-expect-error xray library types suck
40-
(segment.http.request.url as string) += '/' + segment.name;
41+
return {
42+
onExecuteDone: () => {
43+
const userId = session$.value?.userId;
44+
if (userId) {
45+
segment.setUser?.(userId);
4146
}
4247

4348
return {
44-
executionDidEnd: async (err) => {
45-
const userId = reqContext.contextValue.session$.value?.userId;
46-
if (userId) {
47-
segment.setUser?.(userId);
48-
}
49-
50-
if (err) {
51-
segment.addError(err);
49+
onNext: ({ result }) => {
50+
for (const error of result.errors ?? []) {
51+
segment.addError(error);
5252
}
5353
},
5454
};
5555
},
5656
};
57-
}
57+
};
5858

5959
fieldMiddleware(): FieldMiddleware {
6060
return ({ info, args }, next) => {

0 commit comments

Comments
 (0)