Skip to content
This repository has been archived by the owner on Mar 20, 2023. It is now read-only.

Commit

Permalink
Wrap HttpError into GraphQLError (#716)
Browse files Browse the repository at this point in the history
Fixes #699
  • Loading branch information
IvanGoncharov committed Nov 9, 2020
1 parent b462653 commit bb23f60
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 13 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,7 @@ overrides:
'@typescript-eslint/no-extraneous-class': off # TODO consider
'@typescript-eslint/no-floating-promises': error
'@typescript-eslint/no-for-in-array': error
'@typescript-eslint/no-implicit-any-catch': off # TODO: Enable
'@typescript-eslint/no-implicit-any-catch': error
'@typescript-eslint/no-implied-eval': error
'@typescript-eslint/no-inferrable-types':
[error, { ignoreParameters: true, ignoreProperties: true }]
Expand Down
37 changes: 34 additions & 3 deletions src/__tests__/http-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1199,15 +1199,18 @@ function runTests(server: Server) {
});
});

it('allows for custom error formatting to sanitize', async () => {
it('allows for custom error formatting to sanitize GraphQL errors', async () => {
const app = server();

app.get(
urlString(),
graphqlHTTP({
schema: TestSchema,
customFormatErrorFn(error) {
return { message: 'Custom error format: ' + error.message };
return {
message:
`Custom ${error.constructor.name} format: ` + error.message,
};
},
}),
);
Expand All @@ -1223,7 +1226,35 @@ function runTests(server: Server) {
data: { thrower: null },
errors: [
{
message: 'Custom error format: Throws!',
message: 'Custom GraphQLError format: Throws!',
},
],
});
});

it('allows for custom error formatting to sanitize HTTP errors', async () => {
const app = server();

app.get(
urlString(),
graphqlHTTP({
schema: TestSchema,
customFormatErrorFn(error) {
return {
message:
`Custom ${error.constructor.name} format: ` + error.message,
};
},
}),
);

const response = await app.request().get(urlString());

expect(response.status).to.equal(400);
expect(JSON.parse(response.text)).to.deep.equal({
errors: [
{
message: 'Custom GraphQLError format: Must provide query string.',
},
],
});
Expand Down
35 changes: 27 additions & 8 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,17 @@ import type {
ExecutionArgs,
ExecutionResult,
FormattedExecutionResult,
GraphQLError,
GraphQLSchema,
GraphQLFieldResolver,
GraphQLTypeResolver,
GraphQLFormattedError,
} from 'graphql';
import accepts from 'accepts';
import httpError from 'http-errors';
import type { HttpError } from 'http-errors';
import {
Source,
GraphQLError,
parse,
validate,
execute,
Expand Down Expand Up @@ -206,7 +207,7 @@ export function graphqlHTTP(options: Options): Middleware {
// Parse the Request to get GraphQL request parameters.
try {
params = await getGraphQLParams(request);
} catch (error) {
} catch (error: unknown) {
// When we failed to parse the GraphQL parameters, we still need to get
// the options object, so make an options call to resolve just that.
const optionsData = await resolveOptions();
Expand Down Expand Up @@ -284,7 +285,7 @@ export function graphqlHTTP(options: Options): Middleware {
let documentAST;
try {
documentAST = parseFn(new Source(query, 'GraphQL request'));
} catch (syntaxError) {
} catch (syntaxError: unknown) {
// Return 400: Bad Request if any syntax errors errors exist.
throw httpError(400, 'GraphQL syntax error.', {
graphqlErrors: [syntaxError],
Expand Down Expand Up @@ -337,7 +338,7 @@ export function graphqlHTTP(options: Options): Middleware {
fieldResolver,
typeResolver,
});
} catch (contextError) {
} catch (contextError: unknown) {
// Return 400: Bad Request if any execution context errors exist.
throw httpError(400, 'GraphQL execution context error.', {
graphqlErrors: [contextError],
Expand All @@ -359,9 +360,15 @@ export function graphqlHTTP(options: Options): Middleware {
result = { ...result, extensions };
}
}
} catch (error) {
} catch (rawError: unknown) {
// If an error was caught, report the httpError status, or 500.
response.statusCode = error.status ?? 500;
const error: HttpError = httpError(
500,
/* istanbul ignore next: Thrown by underlying library. */
rawError instanceof Error ? rawError : String(rawError),
);

response.statusCode = error.status;

const { headers } = error;
if (headers != null) {
Expand All @@ -370,7 +377,19 @@ export function graphqlHTTP(options: Options): Middleware {
}
}

result = { data: undefined, errors: error.graphqlErrors ?? [error] };
if (error.graphqlErrors == null) {
const graphqlError = new GraphQLError(
error.message,
undefined,
undefined,
undefined,
undefined,
error,
);
result = { data: undefined, errors: [graphqlError] };
} else {
result = { data: undefined, errors: error.graphqlErrors };
}
}

// If no data was included in the result, that indicates a runtime query
Expand Down Expand Up @@ -482,7 +501,7 @@ export async function getGraphQLParams(
if (typeof variables === 'string') {
try {
variables = JSON.parse(variables);
} catch (error) {
} catch {
throw httpError(400, 'Variables are invalid JSON.');
}
} else if (typeof variables !== 'object') {
Expand Down
2 changes: 1 addition & 1 deletion src/parseBody.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export async function parseBody(
if (jsonObjRegex.test(rawBody)) {
try {
return JSON.parse(rawBody);
} catch (error) {
} catch {
// Do nothing
}
}
Expand Down

0 comments on commit bb23f60

Please sign in to comment.