Skip to content

Commit 0fd8be1

Browse files
committed
Support more forms of async returned values.
GraphQL.js already had support for `Promise<T>` and `Promise<Array<T>>`, but not `Array<Promise<T>>`. We had assumed that resolve functions would call Promise.all when necessary based on how GraphQL had been used in the context of PHP/Hack at Facebook where `Array<Promise<T>>` is actually pretty hard to construct. In JavaScript, however, it's easy to forget a call to Promise.all and provide this kind of value. This change makes GraphQL.js aware of `Array<Promise<T>>` and importantly enables a new expression of error handling for nullable list item types (`[T]` vs `[T!]`): If the second of an array of three values fails, we can log an error accordingly and place a null value for that index. The primary structural change here is moving the error detection logic to after calling a field's `resolve` rather than before it. This means direct field `resolve` errors have to be dealt with directly, which is a little less elegant, but it means this error detection logic can be easily reused when completing the values of items in a list. Finally, this adds a more comprehensive test suite for list types in permuation with nullability and Array and Promise return types. Fixes #17
1 parent 099eeb7 commit 0fd8be1

File tree

5 files changed

+450
-429
lines changed

5 files changed

+450
-429
lines changed

src/__tests__/starWarsData.js

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,16 @@ var droidData = {
8888
* Helper function to get a character by ID.
8989
*/
9090
function getCharacter(id) {
91-
if (humanData[id] !== undefined) {
92-
return humanData[id];
93-
}
94-
if (droidData[id] !== undefined) {
95-
return droidData[id];
96-
}
97-
return null;
91+
// Returning a promise just to illustrate GraphQL.js's support.
92+
return new Promise(resolve => {
93+
if (humanData[id] !== undefined) {
94+
return resolve(humanData[id]);
95+
}
96+
if (droidData[id] !== undefined) {
97+
return resolve(droidData[id]);
98+
}
99+
return resolve(null);
100+
});
98101
}
99102

100103
/**
@@ -108,4 +111,3 @@ export var starWarsData = {
108111
Humans: humanData,
109112
Droids: droidData,
110113
};
111-

src/error/index.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { getLocation } from '../language';
1313
import type { Node } from '../language/ast';
1414

1515

16-
export class GraphQLError {
16+
export class GraphQLError extends Error {
1717
message: string;
1818
stack: string;
1919
nodes: ?Array<Node>;
@@ -27,6 +27,7 @@ export class GraphQLError {
2727
nodes?: Array<any/*Node*/>,
2828
stack?: any
2929
) {
30+
super(message);
3031
this.message = message;
3132
this.stack = stack || message;
3233
if (nodes) {
@@ -45,7 +46,16 @@ export class GraphQLError {
4546
}
4647
}
4748

48-
(GraphQLError: any).prototype = Error.prototype;
49+
export function locatedError(error: any, nodes: Array<any>): GraphQLError {
50+
if (error instanceof GraphQLError) {
51+
return error;
52+
}
53+
return new GraphQLError(
54+
error && error.message,
55+
nodes,
56+
error ? error.stack : null
57+
);
58+
}
4959

5060
export type GraphQLFormattedError = {
5161
message: string,

0 commit comments

Comments
 (0)