-
Notifications
You must be signed in to change notification settings - Fork 399
/
merge-defaults.util.ts
116 lines (106 loc) · 3.25 KB
/
merge-defaults.util.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import { HttpStatus } from '@nestjs/common';
import { isFunction } from '@nestjs/common/utils/shared.utils';
import {
ApolloError,
AuthenticationError,
ForbiddenError,
UserInputError,
} from 'apollo-server-core';
import { GraphQLError, GraphQLFormattedError } from 'graphql';
import { GqlModuleOptions } from '../interfaces/gql-module-options.interface';
const defaultOptions: GqlModuleOptions = {
path: '/graphql',
fieldResolverEnhancers: [],
stopOnTerminationSignals: false,
};
export function mergeDefaults(
options: GqlModuleOptions,
defaults: GqlModuleOptions = defaultOptions,
): GqlModuleOptions {
const moduleOptions = {
...defaults,
...options,
};
wrapContextResolver(moduleOptions, options);
wrapFormatErrorFn(moduleOptions);
return moduleOptions;
}
function wrapContextResolver(
targetOptions: GqlModuleOptions,
originalOptions: GqlModuleOptions,
) {
if (!targetOptions.context) {
targetOptions.context = ({ req, request }) => ({ req: req ?? request });
} 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 assignReqProperty(ctx, req ?? request);
};
} else {
targetOptions.context = ({ req, request }: Record<string, unknown>) => {
return assignReqProperty(
originalOptions.context as Record<string, any>,
req ?? request,
);
};
}
}
function assignReqProperty(
ctx: Record<string, unknown> | undefined,
req: unknown,
) {
if (!ctx) {
return { req };
}
if (
typeof ctx !== 'object' ||
(ctx && ctx.req && typeof ctx.req === 'object')
) {
return ctx;
}
ctx.req = req;
return ctx;
}
const apolloPredefinedExceptions: Partial<
Record<HttpStatus, typeof ApolloError | typeof UserInputError>
> = {
[HttpStatus.BAD_REQUEST]: UserInputError,
[HttpStatus.UNAUTHORIZED]: AuthenticationError,
[HttpStatus.FORBIDDEN]: ForbiddenError,
};
function wrapFormatErrorFn(options: GqlModuleOptions) {
if (options.autoTransformHttpErrors === false) {
return;
}
if (options.formatError) {
const origFormatError = options.formatError;
const transformHttpErrorFn = createTransformHttpErrorFn();
options.formatError = (err) => {
err = transformHttpErrorFn(err) as GraphQLError;
return origFormatError(err);
};
} else {
options.formatError = createTransformHttpErrorFn();
}
}
function createTransformHttpErrorFn() {
return (originalError: any): GraphQLFormattedError => {
const exceptionRef = originalError?.extensions?.exception;
const isHttpException =
exceptionRef?.response?.statusCode && exceptionRef?.status;
if (!isHttpException) {
return originalError as GraphQLFormattedError;
}
let error: ApolloError;
const httpStatus = exceptionRef?.status;
if (httpStatus in apolloPredefinedExceptions) {
error = new apolloPredefinedExceptions[httpStatus](exceptionRef?.message);
} else {
error = new ApolloError(exceptionRef.message, httpStatus?.toString());
}
error.stack = exceptionRef?.stacktrace;
error.extensions['response'] = exceptionRef?.response;
return error;
};
}