123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314 |
- "use strict";
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.processGraphQLRequest = exports.APQ_CACHE_PREFIX = void 0;
- const utils_createhash_1 = require("@apollo/utils.createhash");
- const graphql_1 = require("graphql");
- const schemaInstrumentation_js_1 = require("./utils/schemaInstrumentation.js");
- const internalErrorClasses_js_1 = require("./internalErrorClasses.js");
- const errorNormalize_js_1 = require("./errorNormalize.js");
- const invokeHooks_js_1 = require("./utils/invokeHooks.js");
- const makeGatewayGraphQLRequestContext_js_1 = require("./utils/makeGatewayGraphQLRequestContext.js");
- const runHttpQuery_js_1 = require("./runHttpQuery.js");
- const isDefined_js_1 = require("./utils/isDefined.js");
- const incrementalDeliveryPolyfill_js_1 = require("./incrementalDeliveryPolyfill.js");
- const HeaderMap_js_1 = require("./utils/HeaderMap.js");
- exports.APQ_CACHE_PREFIX = 'apq:';
- function computeQueryHash(query) {
- return (0, utils_createhash_1.createHash)('sha256').update(query).digest('hex');
- }
- function isBadUserInputGraphQLError(error) {
- return (error.nodes?.length === 1 &&
- error.nodes[0].kind === graphql_1.Kind.VARIABLE_DEFINITION &&
- (error.message.startsWith(`Variable "$${error.nodes[0].variable.name.value}" got invalid value `) ||
- error.message.startsWith(`Variable "$${error.nodes[0].variable.name.value}" of required type `) ||
- error.message.startsWith(`Variable "$${error.nodes[0].variable.name.value}" of non-null type `)));
- }
- async function processGraphQLRequest(schemaDerivedData, server, internals, requestContext) {
- const requestListeners = (await Promise.all(internals.plugins.map((p) => p.requestDidStart?.(requestContext)))).filter(isDefined_js_1.isDefined);
- const request = requestContext.request;
- let { query, extensions } = request;
- let queryHash;
- requestContext.metrics.persistedQueryHit = false;
- requestContext.metrics.persistedQueryRegister = false;
- if (extensions?.persistedQuery) {
- if (!internals.persistedQueries) {
- return await sendErrorResponse([new internalErrorClasses_js_1.PersistedQueryNotSupportedError()]);
- }
- else if (extensions.persistedQuery.version !== 1) {
- return await sendErrorResponse([
- new graphql_1.GraphQLError('Unsupported persisted query version', {
- extensions: { http: (0, runHttpQuery_js_1.newHTTPGraphQLHead)(400) },
- }),
- ]);
- }
- queryHash = extensions.persistedQuery.sha256Hash;
- if (query === undefined) {
- query = await internals.persistedQueries.cache.get(queryHash);
- if (query) {
- requestContext.metrics.persistedQueryHit = true;
- }
- else {
- return await sendErrorResponse([new internalErrorClasses_js_1.PersistedQueryNotFoundError()]);
- }
- }
- else {
- const computedQueryHash = computeQueryHash(query);
- if (queryHash !== computedQueryHash) {
- return await sendErrorResponse([
- new graphql_1.GraphQLError('provided sha does not match query', {
- extensions: { http: (0, runHttpQuery_js_1.newHTTPGraphQLHead)(400) },
- }),
- ]);
- }
- requestContext.metrics.persistedQueryRegister = true;
- }
- }
- else if (query) {
- queryHash = computeQueryHash(query);
- }
- else {
- return await sendErrorResponse([
- new internalErrorClasses_js_1.BadRequestError('GraphQL operations must contain a non-empty `query` or a `persistedQuery` extension.'),
- ]);
- }
- requestContext.queryHash = queryHash;
- requestContext.source = query;
- await Promise.all(requestListeners.map((l) => l.didResolveSource?.(requestContext)));
- if (schemaDerivedData.documentStore) {
- try {
- requestContext.document = await schemaDerivedData.documentStore.get(schemaDerivedData.documentStoreKeyPrefix + queryHash);
- }
- catch (err) {
- server.logger.warn('An error occurred while attempting to read from the documentStore. ' +
- (0, errorNormalize_js_1.ensureError)(err).message);
- }
- }
- if (!requestContext.document) {
- const parsingDidEnd = await (0, invokeHooks_js_1.invokeDidStartHook)(requestListeners, async (l) => l.parsingDidStart?.(requestContext));
- try {
- requestContext.document = (0, graphql_1.parse)(query, internals.parseOptions);
- }
- catch (syntaxMaybeError) {
- const error = (0, errorNormalize_js_1.ensureError)(syntaxMaybeError);
- await parsingDidEnd(error);
- return await sendErrorResponse([
- new internalErrorClasses_js_1.SyntaxError((0, errorNormalize_js_1.ensureGraphQLError)(error)),
- ]);
- }
- await parsingDidEnd();
- if (internals.dangerouslyDisableValidation !== true) {
- const validationDidEnd = await (0, invokeHooks_js_1.invokeDidStartHook)(requestListeners, async (l) => l.validationDidStart?.(requestContext));
- const validationErrors = (0, graphql_1.validate)(schemaDerivedData.schema, requestContext.document, [...graphql_1.specifiedRules, ...internals.validationRules]);
- if (validationErrors.length === 0) {
- await validationDidEnd();
- }
- else {
- await validationDidEnd(validationErrors);
- return await sendErrorResponse(validationErrors.map((error) => new internalErrorClasses_js_1.ValidationError(error)));
- }
- }
- if (schemaDerivedData.documentStore) {
- Promise.resolve(schemaDerivedData.documentStore.set(schemaDerivedData.documentStoreKeyPrefix + queryHash, requestContext.document)).catch((err) => server.logger.warn('Could not store validated document. ' + err?.message || err));
- }
- }
- const operation = (0, graphql_1.getOperationAST)(requestContext.document, request.operationName);
- requestContext.operation = operation || undefined;
- requestContext.operationName = operation?.name?.value || null;
- if (request.http?.method === 'GET' &&
- operation?.operation &&
- operation.operation !== 'query') {
- return await sendErrorResponse([
- new internalErrorClasses_js_1.BadRequestError(`GET requests only support query operations, not ${operation.operation} operations`, {
- extensions: {
- http: { status: 405, headers: new HeaderMap_js_1.HeaderMap([['allow', 'POST']]) },
- },
- }),
- ]);
- }
- try {
- await Promise.all(requestListeners.map((l) => l.didResolveOperation?.(requestContext)));
- }
- catch (err) {
- return await sendErrorResponse([(0, errorNormalize_js_1.ensureGraphQLError)(err)]);
- }
- if (requestContext.metrics.persistedQueryRegister &&
- internals.persistedQueries) {
- const ttl = internals.persistedQueries?.ttl;
- Promise.resolve(internals.persistedQueries.cache.set(queryHash, query, ttl !== undefined
- ? { ttl: internals.persistedQueries?.ttl }
- : undefined)).catch(server.logger.warn);
- }
- const responseFromPlugin = await (0, invokeHooks_js_1.invokeHooksUntilDefinedAndNonNull)(requestListeners, async (l) => await l.responseForOperation?.(requestContext));
- if (responseFromPlugin !== null) {
- requestContext.response.body = responseFromPlugin.body;
- (0, runHttpQuery_js_1.mergeHTTPGraphQLHead)(requestContext.response.http, responseFromPlugin.http);
- }
- else {
- const executionListeners = (await Promise.all(requestListeners.map((l) => l.executionDidStart?.(requestContext)))).filter(isDefined_js_1.isDefined);
- executionListeners.reverse();
- if (executionListeners.some((l) => l.willResolveField)) {
- const invokeWillResolveField = (...args) => (0, invokeHooks_js_1.invokeSyncDidStartHook)(executionListeners, (l) => l.willResolveField?.(...args));
- Object.defineProperty(requestContext.contextValue, schemaInstrumentation_js_1.symbolExecutionDispatcherWillResolveField, { value: invokeWillResolveField });
- if (internals.fieldResolver) {
- Object.defineProperty(requestContext.contextValue, schemaInstrumentation_js_1.symbolUserFieldResolver, {
- value: internals.fieldResolver,
- });
- }
- (0, schemaInstrumentation_js_1.enablePluginsForSchemaResolvers)(schemaDerivedData.schema);
- }
- try {
- const fullResult = await execute(requestContext);
- const result = 'singleResult' in fullResult
- ? fullResult.singleResult
- : fullResult.initialResult;
- if (!requestContext.operation) {
- if (!result.errors?.length) {
- throw new Error('Unexpected error: Apollo Server did not resolve an operation but execute did not return errors');
- }
- throw new internalErrorClasses_js_1.OperationResolutionError(result.errors[0]);
- }
- const resultErrors = result.errors?.map((e) => {
- if (isBadUserInputGraphQLError(e) && e.extensions?.code == null) {
- return new internalErrorClasses_js_1.UserInputError(e);
- }
- return e;
- });
- if (resultErrors) {
- await didEncounterErrors(resultErrors);
- }
- const { formattedErrors, httpFromErrors } = resultErrors
- ? formatErrors(resultErrors)
- : { formattedErrors: undefined, httpFromErrors: (0, runHttpQuery_js_1.newHTTPGraphQLHead)() };
- if (internals.status400ForVariableCoercionErrors &&
- resultErrors?.length &&
- result.data === undefined &&
- !httpFromErrors.status) {
- httpFromErrors.status = 400;
- }
- (0, runHttpQuery_js_1.mergeHTTPGraphQLHead)(requestContext.response.http, httpFromErrors);
- if ('singleResult' in fullResult) {
- requestContext.response.body = {
- kind: 'single',
- singleResult: {
- ...result,
- errors: formattedErrors,
- },
- };
- }
- else {
- requestContext.response.body = {
- kind: 'incremental',
- initialResult: {
- ...fullResult.initialResult,
- errors: formattedErrors,
- },
- subsequentResults: fullResult.subsequentResults,
- };
- }
- }
- catch (executionMaybeError) {
- const executionError = (0, errorNormalize_js_1.ensureError)(executionMaybeError);
- await Promise.all(executionListeners.map((l) => l.executionDidEnd?.(executionError)));
- return await sendErrorResponse([(0, errorNormalize_js_1.ensureGraphQLError)(executionError)]);
- }
- await Promise.all(executionListeners.map((l) => l.executionDidEnd?.()));
- }
- await invokeWillSendResponse();
- if (!requestContext.response.body) {
- throw Error('got to end of processGraphQLRequest without setting body?');
- }
- return requestContext.response;
- async function execute(requestContext) {
- const { request, document } = requestContext;
- if (internals.__testing_incrementalExecutionResults) {
- return internals.__testing_incrementalExecutionResults;
- }
- else if (internals.gatewayExecutor) {
- const result = await internals.gatewayExecutor((0, makeGatewayGraphQLRequestContext_js_1.makeGatewayGraphQLRequestContext)(requestContext, server, internals));
- return { singleResult: result };
- }
- else {
- const resultOrResults = await (0, incrementalDeliveryPolyfill_js_1.executeIncrementally)({
- schema: schemaDerivedData.schema,
- document,
- rootValue: typeof internals.rootValue === 'function'
- ? internals.rootValue(document)
- : internals.rootValue,
- contextValue: requestContext.contextValue,
- variableValues: request.variables,
- operationName: request.operationName,
- fieldResolver: internals.fieldResolver,
- });
- if ('initialResult' in resultOrResults) {
- return {
- initialResult: resultOrResults.initialResult,
- subsequentResults: formatErrorsInSubsequentResults(resultOrResults.subsequentResults),
- };
- }
- else {
- return { singleResult: resultOrResults };
- }
- }
- }
- async function* formatErrorsInSubsequentResults(results) {
- for await (const result of results) {
- const payload = result.incremental
- ? {
- ...result,
- incremental: await seriesAsyncMap(result.incremental, async (incrementalResult) => {
- const { errors } = incrementalResult;
- if (errors) {
- await Promise.all(requestListeners.map((l) => l.didEncounterSubsequentErrors?.(requestContext, errors)));
- return {
- ...incrementalResult,
- errors: formatErrors(errors).formattedErrors,
- };
- }
- return incrementalResult;
- }),
- }
- : result;
- await Promise.all(requestListeners.map((l) => l.willSendSubsequentPayload?.(requestContext, payload)));
- yield payload;
- }
- }
- async function invokeWillSendResponse() {
- await Promise.all(requestListeners.map((l) => l.willSendResponse?.(requestContext)));
- }
- async function didEncounterErrors(errors) {
- requestContext.errors = errors;
- return await Promise.all(requestListeners.map((l) => l.didEncounterErrors?.(requestContext)));
- }
- async function sendErrorResponse(errors) {
- await didEncounterErrors(errors);
- const { formattedErrors, httpFromErrors } = formatErrors(errors);
- requestContext.response.body = {
- kind: 'single',
- singleResult: {
- errors: formattedErrors,
- },
- };
- (0, runHttpQuery_js_1.mergeHTTPGraphQLHead)(requestContext.response.http, httpFromErrors);
- if (!requestContext.response.http.status) {
- requestContext.response.http.status = 500;
- }
- await invokeWillSendResponse();
- return requestContext.response;
- }
- function formatErrors(errors) {
- return (0, errorNormalize_js_1.normalizeAndFormatErrors)(errors, {
- formatError: internals.formatError,
- includeStacktraceInErrorResponses: internals.includeStacktraceInErrorResponses,
- });
- }
- }
- exports.processGraphQLRequest = processGraphQLRequest;
- async function seriesAsyncMap(ts, fn) {
- const us = [];
- for (const t of ts) {
- const u = await fn(t);
- us.push(u);
- }
- return us;
- }
- //# sourceMappingURL=requestPipeline.js.map
|