Skip to content

Instantly share code, notes, and snippets.

@smilingleo
Created December 13, 2018 08:19
Show Gist options
  • Save smilingleo/f90be2b5017a86ec44ab61161dbce650 to your computer and use it in GitHub Desktop.
Save smilingleo/f90be2b5017a86ec44ab61161dbce650 to your computer and use it in GitHub Desktop.
Delegation GraphQL resolver
/**
*
* @flow strict
*/
import {
GraphQLEnumType,
GraphQLInterfaceType,
GraphQLObjectType,
GraphQLList,
GraphQLNonNull,
GraphQLSchema,
GraphQLString,
} from '../type';
import { getFriends, getHero, getHuman, getDroid } from './starWarsData';
import { graphql } from '../graphql';
const episodeEnum = new GraphQLEnumType({
name: 'Episode',
description: 'One of the films in the Star Wars Trilogy',
values: {
NEWHOPE: {
value: 4,
description: 'Released in 1977.',
},
EMPIRE: {
value: 5,
description: 'Released in 1980.',
},
JEDI: {
value: 6,
description: 'Released in 1983.',
},
},
});
const characterInterface = new GraphQLInterfaceType({
name: 'Character',
description: 'A character in the Star Wars Trilogy',
fields: () => ({
id: {
type: GraphQLNonNull(GraphQLString),
description: 'The id of the character.',
},
name: {
type: GraphQLString,
description: 'The name of the character.',
},
friends: {
type: GraphQLList(characterInterface),
description:
'The friends of the character, or an empty list if they have none.',
},
appearsIn: {
type: GraphQLList(episodeEnum),
description: 'Which movies they appear in.',
},
secretBackstory: {
type: GraphQLString,
description: 'All secrets about their past.',
},
}),
resolveType(character) {
if (character.type === 'Human') {
return humanType;
}
if (character.type === 'Droid') {
return droidType;
}
},
});
const humanType = new GraphQLObjectType({
name: 'Human',
description: 'A humanoid creature in the Star Wars universe.',
fields: () => ({
id: {
type: GraphQLNonNull(GraphQLString),
description: 'The id of the human.',
},
name: {
type: GraphQLString,
description: 'The name of the human.',
},
friends: {
type: GraphQLList(characterInterface),
description:
'The friends of the human, or an empty list if they have none.',
resolve: human => getFriends(human),
},
appearsIn: {
type: GraphQLList(episodeEnum),
description: 'Which movies they appear in.',
},
homePlanet: {
type: GraphQLString,
description: 'The home planet of the human, or null if unknown.',
},
secretBackstory: {
type: GraphQLString,
description: 'Where are they from and how they came to be who they are.',
resolve() {
throw new Error('secretBackstory is secret.');
},
},
}),
interfaces: [characterInterface],
});
const droidType = new GraphQLObjectType({
name: 'Droid',
description: 'A mechanical creature in the Star Wars universe.',
fields: () => ({
id: {
type: GraphQLNonNull(GraphQLString),
description: 'The id of the droid.',
},
name: {
type: GraphQLString,
description: 'The name of the droid.',
},
friends: {
type: GraphQLList(characterInterface),
description:
'The friends of the droid, or an empty list if they have none.',
resolve: droid => getFriends(droid),
},
appearsIn: {
type: GraphQLList(episodeEnum),
description: 'Which movies they appear in.',
},
secretBackstory: {
type: GraphQLString,
description: 'Construction date and the name of the designer.',
resolve() {
throw new Error('secretBackstory is secret.');
},
},
primaryFunction: {
type: GraphQLString,
description: 'The primary function of the droid.',
},
}),
interfaces: [characterInterface],
});
const apiType = new GraphQLObjectType({
name: 'ApiQuery',
fields: () => ({
hero: {
type: characterInterface,
args: {
episode: {
description:
'If omitted, returns the hero of the whole saga. ' +
'If provided, returns the hero of that particular episode.',
type: episodeEnum,
},
},
resolve: (root, { episode }) => getHero(episode),
},
human: {
type: humanType,
args: {
id: {
description: 'id of the human',
type: GraphQLNonNull(GraphQLString),
},
},
resolve: (root, { id }) => getHuman(id),
},
droid: {
type: droidType,
args: {
id: {
description: 'id of the droid',
type: GraphQLNonNull(GraphQLString),
},
},
resolve: (root, { id }) => getDroid(id),
},
}),
});
const rawType = new GraphQLObjectType({
name: 'RawQuery',
fields: () => ({
hero: {
type: characterInterface,
args: {
episode: {
description:
'If omitted, returns the hero of the whole saga. ' +
'If provided, returns the hero of that particular episode.',
type: episodeEnum,
},
},
resolve: (root, { episode }) => getHero(episode),
},
human: {
type: humanType,
args: {
id: {
description: 'id of the human',
type: GraphQLNonNull(GraphQLString),
},
},
resolve: (root, { id }) => getHuman(id),
},
droid: {
type: droidType,
args: {
id: {
description: 'id of the droid',
type: GraphQLNonNull(GraphQLString),
},
},
resolve: (root, { id }) => getDroid(id),
},
}),
});
/**
* compose multiple queries in one Query. In case you don't want to mix them together.
*/
const queryType = new GraphQLObjectType({
name: 'Query',
fields: () => ({
api: {
type: apiType,
resolve: delegateResolver(apiType, 'api'),
},
raw: {
type: rawType,
resolve: delegateResolver(rawType, 'raw'),
},
}),
});
/**
* This is the meat of this gist.
*
*/
const delegateResolver = (objType, name) => {
return (root, args, context, info) => {
const subSchema = new GraphQLSchema({
query: objType,
});
const subSelection = info.operation.selectionSet.selections.find(s => s.name.value === name)
const subSource = subSelection.loc.source.body.substring(subSelection.loc.start, subSelection.loc.end)
const newSource = subSource.replace(name, 'query');
return graphql(
subSchema,
newSource,
root,
context,
args,
);
}
}
/**
* Finally, we construct our schema (whose starting query type is the query
* type we defined above) and export it.
*/
export const StarWarsSchema = new GraphQLSchema({
query: queryType,
types: [humanType, droidType],
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment