Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add didEncounterErrors to request pipeline API. #2719

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 20 additions & 7 deletions packages/apollo-server-core/src/requestPipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ export async function processGraphQLRequest<TContext>(
parsingDidEnd();
} catch (syntaxError) {
parsingDidEnd(syntaxError);
return sendErrorResponse(syntaxError, SyntaxError);
return await sendErrorResponse(syntaxError, SyntaxError);
}

const validationDidEnd = await dispatcher.invokeDidStartHook(
Expand All @@ -253,7 +253,7 @@ export async function processGraphQLRequest<TContext>(
validationDidEnd();
} else {
validationDidEnd(validationErrors);
return sendErrorResponse(validationErrors, ValidationError);
return await sendErrorResponse(validationErrors, ValidationError);
}

if (config.documentStore) {
Expand Down Expand Up @@ -309,7 +309,7 @@ export async function processGraphQLRequest<TContext>(
if (err instanceof HttpQueryError) {
throw err;
}
return sendErrorResponse(err);
return await sendErrorResponse(err);
}

// Now that we've gone through the pre-execution phases of the request
Expand Down Expand Up @@ -345,7 +345,7 @@ export async function processGraphQLRequest<TContext>(
>);

if (result.errors) {
extensionStack.didEncounterErrors(result.errors);
await didEncounterErrors(result.errors);
}

response = {
Expand All @@ -356,7 +356,7 @@ export async function processGraphQLRequest<TContext>(
executionDidEnd();
} catch (executionError) {
executionDidEnd(executionError);
return sendErrorResponse(executionError);
return await sendErrorResponse(executionError);
}
}

Expand Down Expand Up @@ -486,7 +486,20 @@ export async function processGraphQLRequest<TContext>(
return requestContext.response!;
}

function sendErrorResponse(
async function didEncounterErrors(errors: ReadonlyArray<GraphQLError>) {
requestContext.errors = errors;
extensionStack.didEncounterErrors(errors);

return await dispatcher.invokeHookAsync(
'didEncounterErrors',
requestContext as WithRequired<
typeof requestContext,
'metrics' | 'source' | 'errors'
>,
);
}

async function sendErrorResponse(
errorOrErrors: ReadonlyArray<GraphQLError> | GraphQLError,
errorClass?: typeof ApolloError,
) {
Expand All @@ -495,7 +508,7 @@ export async function processGraphQLRequest<TContext>(
? errorOrErrors
: [errorOrErrors];

extensionStack.didEncounterErrors(errors);
await didEncounterErrors(errors);

return sendResponse({
errors: formatErrors(
Expand Down
8 changes: 8 additions & 0 deletions packages/apollo-server-core/src/requestPipelineAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,14 @@ export interface GraphQLRequestContext<TContext = Record<string, any>> {
readonly operationName?: string | null;
readonly operation?: OperationDefinitionNode;

/**
* Unformatted errors which have occurred during the request. Note that these
* are present earlier in the request pipeline and differ from **formatted**
* errors which are the result of running the user-configurable `formatError`
* transformation function over specific errors.
*/
readonly errors?: ReadonlyArray<GraphQLError>;

readonly metrics?: GraphQLRequestMetrics;

debug?: boolean;
Expand Down
6 changes: 6 additions & 0 deletions packages/apollo-server-plugin-base/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ export interface GraphQLRequestListener<TContext = Record<string, any>> {
'metrics' | 'source' | 'document' | 'operationName' | 'operation'
>,
): ValueOrPromise<void>;
didEncounterErrors?(
requestContext: WithRequired<
GraphQLRequestContext<TContext>,
'metrics' | 'source' | 'errors'
>,
): ValueOrPromise<void>;
// If this hook is defined, it is invoked immediately before GraphQL execution
// would take place. If its return value resolves to a non-null
// GraphQLResponse, that result is used instead of executing the query.
Expand Down