Skip to content

Commit 5a10e0b

Browse files
authored
fix(handler): Response maker handles errors correctly (#45)
1 parent 67778a8 commit 5a10e0b

File tree

4 files changed

+61
-24
lines changed

4 files changed

+61
-24
lines changed

src/__tests__/fixtures/simple.ts

+9
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
GraphQLString,
55
GraphQLNonNull,
66
GraphQLSchemaConfig,
7+
GraphQLInt,
78
} from 'graphql';
89

910
export const schemaConfig: GraphQLSchemaConfig = {
@@ -14,6 +15,14 @@ export const schemaConfig: GraphQLSchemaConfig = {
1415
type: new GraphQLNonNull(GraphQLString),
1516
resolve: () => 'world',
1617
},
18+
num: {
19+
type: GraphQLInt,
20+
args: {
21+
num: {
22+
type: GraphQLInt,
23+
},
24+
},
25+
},
1726
},
1827
}),
1928
mutation: new GraphQLObjectType({

src/__tests__/handler.ts

+23
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,26 @@ it('should respond with error if execution result is iterable', async () => {
9797
],
9898
});
9999
});
100+
101+
it('should correctly serialise execution result errors', async () => {
102+
const server = startTServer();
103+
const url = new URL(server.url);
104+
url.searchParams.set('query', 'query ($num: Int) { num(num: $num) }');
105+
url.searchParams.set('variables', JSON.stringify({ num: 'foo' }));
106+
const result = await fetch(url.toString());
107+
expect(result.json()).resolves.toMatchInlineSnapshot(`
108+
{
109+
"errors": [
110+
{
111+
"locations": [
112+
{
113+
"column": 8,
114+
"line": 1,
115+
},
116+
],
117+
"message": "Variable "$num" got invalid value "foo"; Int cannot represent non-integer value: "foo"",
118+
},
119+
],
120+
}
121+
`);
122+
});

src/handler.ts

+20-20
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
areGraphQLErrors,
2222
isAsyncIterable,
2323
isExecutionResult,
24+
isGraphQLError,
2425
isObject,
2526
} from './utils';
2627

@@ -681,12 +682,24 @@ export function makeResponse(
681682
| Readonly<GraphQLError>,
682683
acceptedMediaType: AcceptableMediaType,
683684
): Response {
684-
if (isExecutionResult(resultOrErrors)) {
685+
const errors = isGraphQLError(resultOrErrors)
686+
? [resultOrErrors]
687+
: areGraphQLErrors(resultOrErrors)
688+
? resultOrErrors
689+
: null;
690+
if (errors) {
685691
return [
686-
JSON.stringify(resultOrErrors),
692+
JSON.stringify({ errors }),
687693
{
688-
status: 200,
689-
statusText: 'OK',
694+
...(acceptedMediaType === 'application/json'
695+
? {
696+
status: 200,
697+
statusText: 'OK',
698+
}
699+
: {
700+
status: 400,
701+
statusText: 'Bad Request',
702+
}),
690703
headers: {
691704
'content-type':
692705
acceptedMediaType === 'application/json'
@@ -698,23 +711,10 @@ export function makeResponse(
698711
}
699712

700713
return [
701-
JSON.stringify({
702-
errors: Array.isArray(resultOrErrors)
703-
? isObject(resultOrErrors)
704-
? resultOrErrors
705-
: new GraphQLError(String(resultOrErrors))
706-
: [resultOrErrors],
707-
}),
714+
JSON.stringify(resultOrErrors),
708715
{
709-
...(acceptedMediaType === 'application/json'
710-
? {
711-
status: 200,
712-
statusText: 'OK',
713-
}
714-
: {
715-
status: 400,
716-
statusText: 'Bad Request',
717-
}),
716+
status: 200,
717+
statusText: 'OK',
718718
headers: {
719719
'content-type':
720720
acceptedMediaType === 'application/json'

src/utils.ts

+9-4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
*
55
*/
66

7-
import type { ExecutionResult, GraphQLError } from 'graphql';
7+
import type { ExecutionResult } from 'graphql';
8+
import { GraphQLError } from 'graphql';
89

910
/** @private */
1011
export function extendedTypeof(
@@ -42,13 +43,17 @@ export function isObject(val: unknown): val is Record<
4243
export function areGraphQLErrors(obj: unknown): obj is readonly GraphQLError[] {
4344
return (
4445
Array.isArray(obj) &&
45-
// must be at least one error
4646
obj.length > 0 &&
47-
// error has at least a message
48-
obj.every((ob) => 'message' in ob)
47+
// if one item in the array is a GraphQLError, we're good
48+
obj.some(isGraphQLError)
4949
);
5050
}
5151

52+
/** @private */
53+
export function isGraphQLError(obj: unknown): obj is GraphQLError {
54+
return obj instanceof GraphQLError;
55+
}
56+
5257
/** @private */
5358
export function isExecutionResult(val: unknown): val is ExecutionResult {
5459
return (

0 commit comments

Comments
 (0)