1 | "use strict";
|
2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
4 | return new (P || (P = Promise))(function (resolve, reject) {
|
5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
8 | step((generator = generator.apply(thisArg, _arguments || [])).next());
|
9 | });
|
10 | };
|
11 | var __importDefault = (this && this.__importDefault) || function (mod) {
|
12 | return (mod && mod.__esModule) ? mod : { "default": mod };
|
13 | };
|
14 | Object.defineProperty(exports, "__esModule", { value: true });
|
15 | exports.processGraphQLRequest = exports.APQ_CACHE_PREFIX = exports.InvalidGraphQLRequestError = void 0;
|
16 | const graphql_1 = require("graphql");
|
17 | const graphql_extensions_1 = require("graphql-extensions");
|
18 | const schemaInstrumentation_1 = require("./utils/schemaInstrumentation");
|
19 | const apollo_server_errors_1 = require("apollo-server-errors");
|
20 | const apollo_server_types_1 = require("apollo-server-types");
|
21 | Object.defineProperty(exports, "InvalidGraphQLRequestError", { enumerable: true, get: function () { return apollo_server_types_1.InvalidGraphQLRequestError; } });
|
22 | const dispatcher_1 = require("./utils/dispatcher");
|
23 | const apollo_server_caching_1 = require("apollo-server-caching");
|
24 | const createSHA_1 = __importDefault(require("./utils/createSHA"));
|
25 | const runHttpQuery_1 = require("./runHttpQuery");
|
26 | exports.APQ_CACHE_PREFIX = 'apq:';
|
27 | function computeQueryHash(query) {
|
28 | return createSHA_1.default('sha256')
|
29 | .update(query)
|
30 | .digest('hex');
|
31 | }
|
32 | const symbolExtensionDeprecationDone = Symbol("apolloServerExtensionDeprecationDone");
|
33 | function processGraphQLRequest(config, requestContext) {
|
34 | var _a;
|
35 | return __awaiter(this, void 0, void 0, function* () {
|
36 | const logger = requestContext.logger || console;
|
37 | const metrics = requestContext.metrics =
|
38 | requestContext.metrics || Object.create(null);
|
39 | const extensionStack = initializeExtensionStack();
|
40 | requestContext.context._extensionStack = extensionStack;
|
41 | const dispatcher = initializeRequestListenerDispatcher();
|
42 | yield initializeDataSources();
|
43 | const request = requestContext.request;
|
44 | let { query, extensions } = request;
|
45 | let queryHash;
|
46 | let persistedQueryCache;
|
47 | metrics.persistedQueryHit = false;
|
48 | metrics.persistedQueryRegister = false;
|
49 | if (extensions && extensions.persistedQuery) {
|
50 | if (!config.persistedQueries || !config.persistedQueries.cache) {
|
51 | return yield emitErrorAndThrow(new apollo_server_errors_1.PersistedQueryNotSupportedError());
|
52 | }
|
53 | else if (extensions.persistedQuery.version !== 1) {
|
54 | return yield emitErrorAndThrow(new apollo_server_types_1.InvalidGraphQLRequestError('Unsupported persisted query version'));
|
55 | }
|
56 | persistedQueryCache = config.persistedQueries.cache;
|
57 | if (!(persistedQueryCache instanceof apollo_server_caching_1.PrefixingKeyValueCache)) {
|
58 | persistedQueryCache = new apollo_server_caching_1.PrefixingKeyValueCache(persistedQueryCache, exports.APQ_CACHE_PREFIX);
|
59 | }
|
60 | queryHash = extensions.persistedQuery.sha256Hash;
|
61 | if (query === undefined) {
|
62 | query = yield persistedQueryCache.get(queryHash);
|
63 | if (query) {
|
64 | metrics.persistedQueryHit = true;
|
65 | }
|
66 | else {
|
67 | return yield emitErrorAndThrow(new apollo_server_errors_1.PersistedQueryNotFoundError());
|
68 | }
|
69 | }
|
70 | else {
|
71 | const computedQueryHash = computeQueryHash(query);
|
72 | if (queryHash !== computedQueryHash) {
|
73 | return yield emitErrorAndThrow(new apollo_server_types_1.InvalidGraphQLRequestError('provided sha does not match query'));
|
74 | }
|
75 | metrics.persistedQueryRegister = true;
|
76 | }
|
77 | }
|
78 | else if (query) {
|
79 | queryHash = computeQueryHash(query);
|
80 | }
|
81 | else {
|
82 | return yield emitErrorAndThrow(new apollo_server_types_1.InvalidGraphQLRequestError('Must provide query string.'));
|
83 | }
|
84 | requestContext.queryHash = queryHash;
|
85 | requestContext.source = query;
|
86 | yield dispatcher.invokeHookAsync('didResolveSource', requestContext);
|
87 | const requestDidEnd = extensionStack.requestDidStart({
|
88 | request: request.http,
|
89 | queryString: request.query,
|
90 | operationName: request.operationName,
|
91 | variables: request.variables,
|
92 | extensions: request.extensions,
|
93 | context: requestContext.context,
|
94 | persistedQueryHit: metrics.persistedQueryHit,
|
95 | persistedQueryRegister: metrics.persistedQueryRegister,
|
96 | requestContext: requestContext,
|
97 | });
|
98 | try {
|
99 | if (config.documentStore) {
|
100 | try {
|
101 | requestContext.document = yield config.documentStore.get(queryHash);
|
102 | }
|
103 | catch (err) {
|
104 | logger.warn('An error occurred while attempting to read from the documentStore. '
|
105 | + (err && err.message) || err);
|
106 | }
|
107 | }
|
108 | if (!requestContext.document) {
|
109 | const parsingDidEnd = yield dispatcher.invokeDidStartHook('parsingDidStart', requestContext);
|
110 | try {
|
111 | requestContext.document = parse(query, config.parseOptions);
|
112 | parsingDidEnd();
|
113 | }
|
114 | catch (syntaxError) {
|
115 | parsingDidEnd(syntaxError);
|
116 | return yield sendErrorResponse(syntaxError, apollo_server_errors_1.SyntaxError);
|
117 | }
|
118 | const validationDidEnd = yield dispatcher.invokeDidStartHook('validationDidStart', requestContext);
|
119 | const validationErrors = validate(requestContext.document);
|
120 | if (validationErrors.length === 0) {
|
121 | validationDidEnd();
|
122 | }
|
123 | else {
|
124 | validationDidEnd(validationErrors);
|
125 | return yield sendErrorResponse(validationErrors, apollo_server_errors_1.ValidationError);
|
126 | }
|
127 | if (config.documentStore) {
|
128 | Promise.resolve(config.documentStore.set(queryHash, requestContext.document)).catch(err => logger.warn('Could not store validated document. ' +
|
129 | (err && err.message) || err));
|
130 | }
|
131 | }
|
132 | const operation = graphql_1.getOperationAST(requestContext.document, request.operationName);
|
133 | requestContext.operation = operation || undefined;
|
134 | requestContext.operationName =
|
135 | (operation && operation.name && operation.name.value) || null;
|
136 | try {
|
137 | yield dispatcher.invokeHookAsync('didResolveOperation', requestContext);
|
138 | }
|
139 | catch (err) {
|
140 | if (err instanceof runHttpQuery_1.HttpQueryError) {
|
141 | const graphqlError = new graphql_1.GraphQLError(err.message);
|
142 | graphqlError.stack = err.stack;
|
143 | yield didEncounterErrors([graphqlError]);
|
144 | throw err;
|
145 | }
|
146 | return yield sendErrorResponse(err);
|
147 | }
|
148 | if (metrics.persistedQueryRegister && persistedQueryCache) {
|
149 | Promise.resolve(persistedQueryCache.set(queryHash, query, config.persistedQueries &&
|
150 | typeof config.persistedQueries.ttl !== 'undefined'
|
151 | ? {
|
152 | ttl: config.persistedQueries.ttl,
|
153 | }
|
154 | : Object.create(null))).catch(logger.warn);
|
155 | }
|
156 | let response = yield dispatcher.invokeHooksUntilNonNull('responseForOperation', requestContext);
|
157 | if (response == null) {
|
158 | const executionListeners = [];
|
159 | dispatcher.invokeHookSync('executionDidStart', requestContext).forEach(executionListener => {
|
160 | if (typeof executionListener === 'function') {
|
161 | executionListeners.push({
|
162 | executionDidEnd: executionListener,
|
163 | });
|
164 | }
|
165 | else if (typeof executionListener === 'object') {
|
166 | executionListeners.push(executionListener);
|
167 | }
|
168 | });
|
169 | const executionDispatcher = new dispatcher_1.Dispatcher(executionListeners);
|
170 | const invokeWillResolveField = (...args) => executionDispatcher.invokeDidStartHook('willResolveField', ...args);
|
171 | Object.defineProperty(requestContext.context, schemaInstrumentation_1.symbolExecutionDispatcherWillResolveField, { value: invokeWillResolveField });
|
172 | if (config.fieldResolver) {
|
173 | Object.defineProperty(requestContext.context, schemaInstrumentation_1.symbolUserFieldResolver, { value: config.fieldResolver });
|
174 | }
|
175 | schemaInstrumentation_1.enablePluginsForSchemaResolvers(config.schema);
|
176 | try {
|
177 | const result = yield execute(requestContext);
|
178 | const resultErrors = (_a = result.errors) === null || _a === void 0 ? void 0 : _a.map((e) => {
|
179 | var _a;
|
180 | if (((_a = e.nodes) === null || _a === void 0 ? void 0 : _a.length) === 1 &&
|
181 | e.nodes[0].kind === graphql_1.Kind.VARIABLE_DEFINITION &&
|
182 | e.message.startsWith(`Variable "$${e.nodes[0].variable.name.value}" got invalid value `)) {
|
183 | return apollo_server_errors_1.fromGraphQLError(e, {
|
184 | errorClass: apollo_server_errors_1.UserInputError,
|
185 | });
|
186 | }
|
187 | return e;
|
188 | });
|
189 | if (resultErrors) {
|
190 | yield didEncounterErrors(resultErrors);
|
191 | }
|
192 | response = Object.assign(Object.assign({}, result), { errors: resultErrors ? formatErrors(resultErrors) : undefined });
|
193 | executionDispatcher.reverseInvokeHookSync('executionDidEnd');
|
194 | }
|
195 | catch (executionError) {
|
196 | executionDispatcher.reverseInvokeHookSync("executionDidEnd", executionError);
|
197 | return yield sendErrorResponse(executionError);
|
198 | }
|
199 | }
|
200 | const formattedExtensions = extensionStack.format();
|
201 | if (Object.keys(formattedExtensions).length > 0) {
|
202 | response.extensions = formattedExtensions;
|
203 | }
|
204 | if (config.formatResponse) {
|
205 | const formattedResponse = config.formatResponse(response, requestContext);
|
206 | if (formattedResponse != null) {
|
207 | response = formattedResponse;
|
208 | }
|
209 | }
|
210 | return sendResponse(response);
|
211 | }
|
212 | finally {
|
213 | requestDidEnd();
|
214 | }
|
215 | function parse(query, parseOptions) {
|
216 | const parsingDidEnd = extensionStack.parsingDidStart({
|
217 | queryString: query,
|
218 | });
|
219 | try {
|
220 | return graphql_1.parse(query, parseOptions);
|
221 | }
|
222 | finally {
|
223 | parsingDidEnd();
|
224 | }
|
225 | }
|
226 | function validate(document) {
|
227 | let rules = graphql_1.specifiedRules;
|
228 | if (config.validationRules) {
|
229 | rules = rules.concat(config.validationRules);
|
230 | }
|
231 | const validationDidEnd = extensionStack.validationDidStart();
|
232 | try {
|
233 | return graphql_1.validate(config.schema, document, rules);
|
234 | }
|
235 | finally {
|
236 | validationDidEnd();
|
237 | }
|
238 | }
|
239 | function execute(requestContext) {
|
240 | return __awaiter(this, void 0, void 0, function* () {
|
241 | const { request, document } = requestContext;
|
242 | const executionArgs = {
|
243 | schema: config.schema,
|
244 | document,
|
245 | rootValue: typeof config.rootValue === 'function'
|
246 | ? config.rootValue(document)
|
247 | : config.rootValue,
|
248 | contextValue: requestContext.context,
|
249 | variableValues: request.variables,
|
250 | operationName: request.operationName,
|
251 | fieldResolver: config.fieldResolver,
|
252 | };
|
253 | const executionDidEnd = extensionStack.executionDidStart({
|
254 | executionArgs,
|
255 | });
|
256 | try {
|
257 | if (config.executor) {
|
258 | return yield config.executor(requestContext);
|
259 | }
|
260 | else {
|
261 | return yield graphql_1.execute(executionArgs);
|
262 | }
|
263 | }
|
264 | finally {
|
265 | executionDidEnd();
|
266 | }
|
267 | });
|
268 | }
|
269 | function sendResponse(response) {
|
270 | return __awaiter(this, void 0, void 0, function* () {
|
271 | requestContext.response = extensionStack.willSendResponse({
|
272 | graphqlResponse: Object.assign(Object.assign({}, requestContext.response), { errors: response.errors, data: response.data, extensions: response.extensions }),
|
273 | context: requestContext.context,
|
274 | }).graphqlResponse;
|
275 | yield dispatcher.invokeHookAsync('willSendResponse', requestContext);
|
276 | return requestContext.response;
|
277 | });
|
278 | }
|
279 | function emitErrorAndThrow(error) {
|
280 | return __awaiter(this, void 0, void 0, function* () {
|
281 | yield didEncounterErrors([error]);
|
282 | throw error;
|
283 | });
|
284 | }
|
285 | function didEncounterErrors(errors) {
|
286 | return __awaiter(this, void 0, void 0, function* () {
|
287 | requestContext.errors = errors;
|
288 | extensionStack.didEncounterErrors(errors);
|
289 | return yield dispatcher.invokeHookAsync('didEncounterErrors', requestContext);
|
290 | });
|
291 | }
|
292 | function sendErrorResponse(errorOrErrors, errorClass) {
|
293 | return __awaiter(this, void 0, void 0, function* () {
|
294 | const errors = Array.isArray(errorOrErrors)
|
295 | ? errorOrErrors
|
296 | : [errorOrErrors];
|
297 | yield didEncounterErrors(errors);
|
298 | return sendResponse({
|
299 | errors: formatErrors(errors.map(err => apollo_server_errors_1.fromGraphQLError(err, errorClass && {
|
300 | errorClass,
|
301 | }))),
|
302 | });
|
303 | });
|
304 | }
|
305 | function formatErrors(errors) {
|
306 | return apollo_server_errors_1.formatApolloErrors(errors, {
|
307 | formatter: config.formatError,
|
308 | debug: requestContext.debug,
|
309 | });
|
310 | }
|
311 | function initializeRequestListenerDispatcher() {
|
312 | const requestListeners = [];
|
313 | if (config.plugins) {
|
314 | for (const plugin of config.plugins) {
|
315 | if (!plugin.requestDidStart)
|
316 | continue;
|
317 | const listener = plugin.requestDidStart(requestContext);
|
318 | if (listener) {
|
319 | requestListeners.push(listener);
|
320 | }
|
321 | }
|
322 | }
|
323 | return new dispatcher_1.Dispatcher(requestListeners);
|
324 | }
|
325 | function initializeExtensionStack() {
|
326 | var _a;
|
327 | if ((_a = config.extensions) === null || _a === void 0 ? void 0 : _a.length) {
|
328 | graphql_extensions_1.enableGraphQLExtensions(config.schema);
|
329 | }
|
330 | const extensions = config.extensions ? config.extensions.map(f => f()) : [];
|
331 | const hasOwn = Object.prototype.hasOwnProperty;
|
332 | extensions.forEach((extension) => {
|
333 | if (!extension.constructor ||
|
334 | hasOwn.call(extension.constructor, symbolExtensionDeprecationDone)) {
|
335 | return;
|
336 | }
|
337 | Object.defineProperty(extension.constructor, symbolExtensionDeprecationDone, { value: true });
|
338 | const extensionName = extension.constructor.name;
|
339 | logger.warn('[deprecated] ' +
|
340 | (extensionName
|
341 | ? 'A "' + extensionName + '" '
|
342 | : 'An anonymous extension ') +
|
343 | 'was defined within the "extensions" configuration for ' +
|
344 | 'Apollo Server. The API on which this extension is built ' +
|
345 | '("graphql-extensions") is being deprecated in the next major ' +
|
346 | 'version of Apollo Server in favor of the new plugin API. See ' +
|
347 | 'https://go.apollo.dev/s/plugins for the documentation on how ' +
|
348 | 'these plugins are to be defined and used.');
|
349 | });
|
350 | return new graphql_extensions_1.GraphQLExtensionStack(extensions);
|
351 | }
|
352 | function initializeDataSources() {
|
353 | return __awaiter(this, void 0, void 0, function* () {
|
354 | if (config.dataSources) {
|
355 | const context = requestContext.context;
|
356 | const dataSources = config.dataSources();
|
357 | const initializers = [];
|
358 | for (const dataSource of Object.values(dataSources)) {
|
359 | if (dataSource.initialize) {
|
360 | initializers.push(dataSource.initialize({
|
361 | context,
|
362 | cache: requestContext.cache,
|
363 | }));
|
364 | }
|
365 | }
|
366 | yield Promise.all(initializers);
|
367 | if ('dataSources' in context) {
|
368 | throw new Error('Please use the dataSources config option instead of putting dataSources on the context yourself.');
|
369 | }
|
370 | context.dataSources = dataSources;
|
371 | }
|
372 | });
|
373 | }
|
374 | });
|
375 | }
|
376 | exports.processGraphQLRequest = processGraphQLRequest;
|
377 |
|
\ | No newline at end of file |