Skip to content

Commit

Permalink
Support more forms of async returned values.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
leebyron committed Jul 4, 2015
1 parent 099eeb7 commit 0fd8be1
Show file tree
Hide file tree
Showing 5 changed files with 450 additions and 429 deletions.
18 changes: 10 additions & 8 deletions src/__tests__/starWarsData.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,16 @@ var droidData = {
* Helper function to get a character by ID.
*/
function getCharacter(id) {
if (humanData[id] !== undefined) {
return humanData[id];
}
if (droidData[id] !== undefined) {
return droidData[id];
}
return null;
// Returning a promise just to illustrate GraphQL.js's support.
return new Promise(resolve => {
if (humanData[id] !== undefined) {
return resolve(humanData[id]);
}
if (droidData[id] !== undefined) {
return resolve(droidData[id]);
}
return resolve(null);
});
}

/**
Expand All @@ -108,4 +111,3 @@ export var starWarsData = {
Humans: humanData,
Droids: droidData,
};

14 changes: 12 additions & 2 deletions src/error/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { getLocation } from '../language';
import type { Node } from '../language/ast';


export class GraphQLError {
export class GraphQLError extends Error {
message: string;
stack: string;
nodes: ?Array<Node>;
Expand All @@ -27,6 +27,7 @@ export class GraphQLError {
nodes?: Array<any/*Node*/>,
stack?: any
) {
super(message);
this.message = message;
this.stack = stack || message;
if (nodes) {
Expand All @@ -45,7 +46,16 @@ export class GraphQLError {
}
}

(GraphQLError: any).prototype = Error.prototype;
export function locatedError(error: any, nodes: Array<any>): GraphQLError {
if (error instanceof GraphQLError) {
return error;
}
return new GraphQLError(
error && error.message,
nodes,
error ? error.stack : null
);
}

export type GraphQLFormattedError = {
message: string,
Expand Down
Loading

0 comments on commit 0fd8be1

Please sign in to comment.