Skip to content
Permalink
9 contributors

Users who have contributed to this file

@IvanGoncharov @leebyron @enaqx @dschafer @olivierlesnicki @Slava @hzoo @cletusw @albertstill
299 lines (287 sloc) 7.33 KB
// @flow strict
import invariant from '../jsutils/invariant';
import { GraphQLSchema } from '../type/schema';
import { GraphQLString } from '../type/scalars';
import {
GraphQLList,
GraphQLNonNull,
GraphQLEnumType,
GraphQLInterfaceType,
GraphQLObjectType,
} from '../type/definition';
import { getFriends, getHero, getHuman, getDroid } from './starWarsData';
/**
* This is designed to be an end-to-end test, demonstrating
* the full GraphQL stack.
*
* We will create a GraphQL schema that describes the major
* characters in the original Star Wars trilogy.
*
* NOTE: This may contain spoilers for the original Star
* Wars trilogy.
*/
/**
* Using our shorthand to describe type systems, the type system for our
* Star Wars example is:
*
* enum Episode { NEW_HOPE, EMPIRE, JEDI }
*
* interface Character {
* id: String!
* name: String
* friends: [Character]
* appearsIn: [Episode]
* }
*
* type Human implements Character {
* id: String!
* name: String
* friends: [Character]
* appearsIn: [Episode]
* homePlanet: String
* }
*
* type Droid implements Character {
* id: String!
* name: String
* friends: [Character]
* appearsIn: [Episode]
* primaryFunction: String
* }
*
* type Query {
* hero(episode: Episode): Character
* human(id: String!): Human
* droid(id: String!): Droid
* }
*
* We begin by setting up our schema.
*/
/**
* The original trilogy consists of three movies.
*
* This implements the following type system shorthand:
* enum Episode { NEW_HOPE, EMPIRE, JEDI }
*/
const episodeEnum = new GraphQLEnumType({
name: 'Episode',
description: 'One of the films in the Star Wars Trilogy',
values: {
NEW_HOPE: {
value: 4,
description: 'Released in 1977.',
},
EMPIRE: {
value: 5,
description: 'Released in 1980.',
},
JEDI: {
value: 6,
description: 'Released in 1983.',
},
},
});
/**
* Characters in the Star Wars trilogy are either humans or droids.
*
* This implements the following type system shorthand:
* interface Character {
* id: String!
* name: String
* friends: [Character]
* appearsIn: [Episode]
* secretBackstory: String
* }
*/
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;
}
// Not reachable. All possible types have been considered.
invariant(false);
},
});
/**
* We define our human type, which implements the character interface.
*
* This implements the following type system shorthand:
* type Human : Character {
* id: String!
* name: String
* friends: [Character]
* appearsIn: [Episode]
* secretBackstory: String
* }
*/
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],
});
/**
* The other type of character in Star Wars is a droid.
*
* This implements the following type system shorthand:
* type Droid : Character {
* id: String!
* name: String
* friends: [Character]
* appearsIn: [Episode]
* secretBackstory: String
* primaryFunction: String
* }
*/
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],
});
/**
* This is the type that will be the root of our query, and the
* entry point into our schema. It gives us the ability to fetch
* objects by their IDs, as well as to fetch the undisputed hero
* of the Star Wars trilogy, R2-D2, directly.
*
* This implements the following type system shorthand:
* type Query {
* hero(episode: Episode): Character
* human(id: String!): Human
* droid(id: String!): Droid
* }
*
*/
const queryType = new GraphQLObjectType({
name: 'Query',
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: (_source, { episode }) => getHero(episode),
},
human: {
type: humanType,
args: {
id: {
description: 'id of the human',
type: GraphQLNonNull(GraphQLString),
},
},
resolve: (_source, { id }) => getHuman(id),
},
droid: {
type: droidType,
args: {
id: {
description: 'id of the droid',
type: GraphQLNonNull(GraphQLString),
},
},
resolve: (_source, { id }) => getDroid(id),
},
}),
});
/**
* Finally, we construct our schema (whose starting query type is the query
* type we defined above) and export it.
*/
export const StarWarsSchema: GraphQLSchema = new GraphQLSchema({
query: queryType,
types: [humanType, droidType],
});
You can’t perform that action at this time.