diff --git a/docs/APIReference-Errors.md b/docs/APIReference-Errors.md new file mode 100644 index 0000000000..eccd0934ce --- /dev/null +++ b/docs/APIReference-Errors.md @@ -0,0 +1,109 @@ +--- +title: graphql/error +layout: ../_core/GraphQLJSLayout +category: API Reference +permalink: /graphql-js/error/ +sublinks: formatError,GraphQLError,locatedError,syntaxError +next: /graphql-js/execution/ +--- + +The `graphql/error` module is responsible for creating and formatting +GraphQL errors. You can import either from the `graphql/error` module, or from the root `graphql` module. For example: + +```js +import { GraphQLError } from 'graphql'; // ES6 +var { GraphQLError } = require('graphql'); // CommonJS +``` + +## Overview + + + +## Errors + +### GraphQLError + +```js +class GraphQLError extends Error { + constructor( + message: string, + nodes?: Array, + stack?: ?string, + source?: Source, + positions?: Array, + originalError?: ?Error, + extensions?: ?{ [key: string]: mixed } + ) +} +``` + +A representation of an error that occurred within GraphQL. Contains +information about where in the query the error occurred for debugging. Most +commonly constructed with `locatedError` below. + +### syntaxError + +```js +function syntaxError( + source: Source, + position: number, + description: string +): GraphQLError; +``` + +Produces a GraphQLError representing a syntax error, containing useful +descriptive information about the syntax error's position in the source. + +### locatedError + +```js +function locatedError(error: ?Error, nodes: Array): GraphQLError { +``` + +Given an arbitrary Error, presumably thrown while attempting to execute a +GraphQL operation, produce a new GraphQLError aware of the location in the +document responsible for the original Error. + +### formatError + +```js +function formatError(error: GraphQLError): GraphQLFormattedError + +type GraphQLFormattedError = { + message: string, + locations: ?Array +}; + +type GraphQLErrorLocation = { + line: number, + column: number +}; +``` + +Given a GraphQLError, format it according to the rules described by the +Response Format, Errors section of the GraphQL Specification. diff --git a/docs/APIReference-Execution.md b/docs/APIReference-Execution.md new file mode 100644 index 0000000000..750c2889f8 --- /dev/null +++ b/docs/APIReference-Execution.md @@ -0,0 +1,60 @@ +--- +title: graphql/execution +layout: ../_core/GraphQLJSLayout +category: API Reference +permalink: /graphql-js/execution/ +sublinks: execute +next: /graphql-js/language/ +--- + +The `graphql/execution` module is responsible for the execution phase of +fulfilling a GraphQL request. You can import either from the `graphql/execution` module, or from the root `graphql` module. For example: + +```js +import { execute } from 'graphql'; // ES6 +var { execute } = require('graphql'); // CommonJS +``` + +## Overview + + + +## Execution + +### execute + +```js +export function execute( + schema: GraphQLSchema, + documentAST: Document, + rootValue?: mixed, + contextValue?: mixed, + variableValues?: ?{[key: string]: mixed}, + operationName?: ?string +): MaybePromise + +type MaybePromise = Promise | T; + +type ExecutionResult = { + data: ?Object; + errors?: Array; +} +``` + +Implements the "Evaluating requests" section of the GraphQL specification. + +Returns a Promise that will eventually be resolved and never rejected. + +If the arguments to this function do not result in a legal execution context, +a GraphQLError will be thrown immediately explaining the invalid input. + +`ExecutionResult` represents the result of execution. `data` is the result of +executing the query, `errors` is null if no errors occurred, and is a +non-empty array if an error occurred. diff --git a/docs/APIReference-ExpressGraphQL.md b/docs/APIReference-ExpressGraphQL.md new file mode 100644 index 0000000000..65703b1b08 --- /dev/null +++ b/docs/APIReference-ExpressGraphQL.md @@ -0,0 +1,35 @@ +--- +title: express-graphql +layout: ../_core/GraphQLJSLayout +category: API Reference +permalink: /graphql-js/express-graphql/ +sublinks: graphqlHTTP +next: /graphql-js/graphql/ +--- + +The `express-graphql` module provides a simple way to create an [Express](https://expressjs.com/) server that runs a GraphQL API. + +```js +import graphqlHTTP from 'express-graphql'; // ES6 +var graphqlHTTP = require('express-graphql'); // CommonJS +``` + +### graphqlHTTP + +```js +graphqlHTTP({ + schema: GraphQLSchema, + graphiql?: ?boolean, + rootValue?: ?any, + context?: ?any, + pretty?: ?boolean, + formatError?: ?Function, + validationRules?: ?Array, +}): Middleware +``` + +Constructs an Express application based on a GraphQL schema. + +See the [express-graphql tutorial](/graphql-js/running-an-express-graphql-server/) for sample usage. + +See the [GitHub README](https://github.com/graphql/express-graphql) for more extensive documentation of the details of this method. diff --git a/docs/APIReference-GraphQL.md b/docs/APIReference-GraphQL.md new file mode 100644 index 0000000000..3db7cdf841 --- /dev/null +++ b/docs/APIReference-GraphQL.md @@ -0,0 +1,179 @@ +--- +title: graphql +layout: ../_core/GraphQLJSLayout +category: API Reference +permalink: /graphql-js/graphql/ +sublinks: graphql +next: /graphql-js/error/ +--- + +The `graphql` module exports a core subset of GraphQL functionality for creation +of GraphQL type systems and servers. + +```js +import { graphql } from 'graphql'; // ES6 +var { graphql } = require('graphql'); // CommonJS +``` + +## Overview + +*Entry Point* + + + +*Schema* + + + +*Type Definitions* + + + +*Scalars* + + + +*Errors* + + + +## Entry Point + +### graphql + +```js +graphql( + schema: GraphQLSchema, + requestString: string, + rootValue?: ?any, + contextValue?: ?any, + variableValues?: ?{[key: string]: any}, + operationName?: ?string +): Promise +``` + +The `graphql` function lexes, parses, validates and executes a GraphQL request. +It requires a `schema` and a `requestString`. Optional arguments include a +`rootValue`, which will get passed as the root value to the executor, a `contextValue`, +which will get passed to all resolve functions, +`variableValues`, which will get passed to the executor to provide values for +any variables in `requestString`, and `operationName`, which allows the caller +to specify which operation in `requestString` will be run, in cases where +`requestString` contains multiple top-level operations. + +## Schema + +See the [Type System API Reference](../type#schema). + +## Type Definitions + +See the [Type System API Reference](../type#definitions). + +## Scalars + +See the [Type System API Reference](../type#scalars). + +## Errors + +See the [Errors API Reference](../error) diff --git a/docs/APIReference-Language.md b/docs/APIReference-Language.md new file mode 100644 index 0000000000..340a1eab08 --- /dev/null +++ b/docs/APIReference-Language.md @@ -0,0 +1,305 @@ +--- +title: graphql/language +layout: ../_core/GraphQLJSLayout +category: API Reference +permalink: /graphql-js/language/ +sublinks: BREAK,getLocation,Kind,lex,parse,parseValue,printSource,visit +next: /graphql-js/type/ +--- + +The `graphql/language` module is responsible for parsing and operating on the GraphQL language. You can import either from the `graphql/language` module, or from the root `graphql` module. For example: + +```js +import { Source } from 'graphql'; // ES6 +var { Source } = require('graphql'); // CommonJS +``` + +## Overview + +*Source* + + + +*Lexer* + + + +*Parser* + + + +*Visitor* + + + +*Printer* + + + +## Source + +### Source + +```js +export class Source { + constructor(body: string, name?: string) +} +``` + +A representation of source input to GraphQL. The name is optional, +but is mostly useful for clients who store GraphQL documents in +source files; for example, if the GraphQL input is in a file Foo.graphql, +it might be useful for name to be "Foo.graphql". + +### getLocation + +```js +function getLocation(source: Source, position: number): SourceLocation + +type SourceLocation = { + line: number; + column: number; +} +``` + +Takes a Source and a UTF-8 character offset, and returns the corresponding +line and column as a SourceLocation. + +## Lexer + +### lex + +```js +function lex(source: Source): Lexer; + +type Lexer = (resetPosition?: number) => Token; + +export type Token = { + kind: number; + start: number; + end: number; + value: ?string; +}; +``` + +Given a Source object, this returns a Lexer for that source. +A Lexer is a function that acts like a generator in that every time +it is called, it returns the next token in the Source. Assuming the +source lexes, the final Token emitted by the lexer will be of kind +EOF, after which the lexer will repeatedly return EOF tokens whenever +called. + +The argument to the lexer function is optional, and can be used to +rewind or fast forward the lexer to a new position in the source. + +## Parser + +### parse + +```js +export function parse( + source: Source | string, + options?: ParseOptions +): Document +``` + +Given a GraphQL source, parses it into a Document. + +Throws GraphQLError if a syntax error is encountered. + +### parseValue + +```js +export function parseValue( + source: Source | string, + options?: ParseOptions +): Value +``` + +Given a string containing a GraphQL value, parse the AST for that value. + +Throws GraphQLError if a syntax error is encountered. + +This is useful within tools that operate upon GraphQL Values directly and +in isolation of complete GraphQL documents. + +### Kind + +An enum that describes the different kinds of AST nodes. + +## Visitor + +### visit + +```js +function visit(root, visitor, keyMap) +``` + +visit() will walk through an AST using a depth first traversal, calling +the visitor's enter function at each node in the traversal, and calling the +leave function after visiting that node and all of its child nodes. + +By returning different values from the enter and leave functions, the +behavior of the visitor can be altered, including skipping over a sub-tree of +the AST (by returning false), editing the AST by returning a value or null +to remove the value, or to stop the whole traversal by returning BREAK. + +When using visit() to edit an AST, the original AST will not be modified, and +a new version of the AST with the changes applied will be returned from the +visit function. + +```js +var editedAST = visit(ast, { + enter(node, key, parent, path, ancestors) { + // @return + // undefined: no action + // false: skip visiting this node + // visitor.BREAK: stop visiting altogether + // null: delete this node + // any value: replace this node with the returned value + }, + leave(node, key, parent, path, ancestors) { + // @return + // undefined: no action + // false: no action + // visitor.BREAK: stop visiting altogether + // null: delete this node + // any value: replace this node with the returned value + } +}); +``` + +Alternatively to providing enter() and leave() functions, a visitor can +instead provide functions named the same as the kinds of AST nodes, or +enter/leave visitors at a named key, leading to four permutations of +visitor API: + +1) Named visitors triggered when entering a node a specific kind. + +```js +visit(ast, { + Kind(node) { + // enter the "Kind" node + } +}) +``` + +2) Named visitors that trigger upon entering and leaving a node of + a specific kind. + +```js +visit(ast, { + Kind: { + enter(node) { + // enter the "Kind" node + } + leave(node) { + // leave the "Kind" node + } + } +}) +``` + +3) Generic visitors that trigger upon entering and leaving any node. + +```js +visit(ast, { + enter(node) { + // enter any node + }, + leave(node) { + // leave any node + } +}) +``` + +4) Parallel visitors for entering and leaving nodes of a specific kind. + +```js +visit(ast, { + enter: { + Kind(node) { + // enter the "Kind" node + } + }, + leave: { + Kind(node) { + // leave the "Kind" node + } + } +}) +``` + +### BREAK + +The sentinel `BREAK` value described in the documentation of `visitor`. + +## Printer + +### print + +```js +function print(ast): string +``` + +Converts an AST into a string, using one set of reasonable +formatting rules. diff --git a/docs/APIReference-TypeSystem.md b/docs/APIReference-TypeSystem.md new file mode 100644 index 0000000000..0a7ff72520 --- /dev/null +++ b/docs/APIReference-TypeSystem.md @@ -0,0 +1,666 @@ +--- +title: graphql/type +layout: ../_core/GraphQLJSLayout +category: API Reference +permalink: /graphql-js/type/ +sublinks: getNamedType,getNullableType,GraphQLBoolean,GraphQLEnumType,GraphQLFloat,GraphQLID,GraphQLInputObjectType,GraphQLInt,GraphQLInterfaceType,GraphQLList,GraphQLNonNull,GraphQLObjectType,GraphQLScalarType,GraphQLSchema,GraphQLString,GraphQLUnionType,isAbstractType,isCompositeType,isInputType,isLeafType,isOutputType +next: /graphql-js/utilities/ +--- + +The `graphql/type` module is responsible for defining GraphQL types and schema. You can import either from the `graphql/type` module, or from the root `graphql` module. For example: + +```js +import { GraphQLSchema } from 'graphql'; // ES6 +var { GraphQLSchema } = require('graphql'); // CommonJS +``` + +## Overview + +*Schema* + + + +*Definitions* + + + +*Predicates* + + + +*Un-modifiers* + + + +*Scalars* + + + +## Schema + +### GraphQLSchema + +```js +class GraphQLSchema { + constructor(config: GraphQLSchemaConfig) +} + +type GraphQLSchemaConfig = { + query: GraphQLObjectType; + mutation?: ?GraphQLObjectType; +} +``` + +A Schema is created by supplying the root types of each type of operation, +query and mutation (optional). A schema definition is then supplied to the +validator and executor. + +#### Example + +```js +var MyAppSchema = new GraphQLSchema({ + query: MyAppQueryRootType + mutation: MyAppMutationRootType +}); +``` + +## Definitions + +### GraphQLScalarType + +```js +class GraphQLScalarType { + constructor(config: GraphQLScalarTypeConfig) +} + +type GraphQLScalarTypeConfig = { + name: string; + description?: ?string; + serialize: (value: mixed) => ?InternalType; + parseValue?: (value: mixed) => ?InternalType; + parseLiteral?: (valueAST: Value) => ?InternalType; +} +``` + +The leaf values of any request and input values to arguments are +Scalars (or Enums) and are defined with a name and a series of serialization +functions used to ensure validity. + +#### Example + +```js +var OddType = new GraphQLScalarType({ + name: 'Odd', + serialize: oddValue, + parseValue: oddValue, + parseLiteral(ast) { + if (ast.kind === Kind.INT) { + return oddValue(parseInt(ast.value, 10)); + } + return null; + } +}); + +function oddValue(value) { + return value % 2 === 1 ? value : null; +} +``` + +### GraphQLObjectType + +```js +class GraphQLObjectType { + constructor(config: GraphQLObjectTypeConfig) +} + +type GraphQLObjectTypeConfig = { + name: string; + interfaces?: GraphQLInterfacesThunk | Array; + fields: GraphQLFieldConfigMapThunk | GraphQLFieldConfigMap; + isTypeOf?: (value: any, info?: GraphQLResolveInfo) => boolean; + description?: ?string +} + +type GraphQLInterfacesThunk = () => Array; + +type GraphQLFieldConfigMapThunk = () => GraphQLFieldConfigMap; + +// See below about resolver functions. +type GraphQLFieldResolveFn = ( + source?: any, + args?: {[argName: string]: any}, + context?: any, + info?: GraphQLResolveInfo +) => any + +type GraphQLResolveInfo = { + fieldName: string, + fieldNodes: Array, + returnType: GraphQLOutputType, + parentType: GraphQLCompositeType, + schema: GraphQLSchema, + fragments: { [fragmentName: string]: FragmentDefinition }, + rootValue: any, + operation: OperationDefinition, + variableValues: { [variableName: string]: any }, +} + +type GraphQLFieldConfig = { + type: GraphQLOutputType; + args?: GraphQLFieldConfigArgumentMap; + resolve?: GraphQLFieldResolveFn; + deprecationReason?: string; + description?: ?string; +} + +type GraphQLFieldConfigArgumentMap = { + [argName: string]: GraphQLArgumentConfig; +}; + +type GraphQLArgumentConfig = { + type: GraphQLInputType; + defaultValue?: any; + description?: ?string; +} + +type GraphQLFieldConfigMap = { + [fieldName: string]: GraphQLFieldConfig; +}; +``` + +Almost all of the GraphQL types you define will be object types. Object types +have a name, but most importantly describe their fields. + +When two types need to refer to each other, or a type needs to refer to +itself in a field, you can use a function expression (aka a closure or a +thunk) to supply the fields lazily. + +Note that resolver functions are provided the `source` object as the first parameter. +However, if a resolver function is not provided, then the default resolver is +used, which looks for a method on `source` of the same name as the field. If found, +the method is called with `(args, context, info)`. Since it is a method on `source`, +that value can always be referenced with `this`. + +#### Examples + +```js +var AddressType = new GraphQLObjectType({ + name: 'Address', + fields: { + street: { type: GraphQLString }, + number: { type: GraphQLInt }, + formatted: { + type: GraphQLString, + resolve(obj) { + return obj.number + ' ' + obj.street + } + } + } +}); + +var PersonType = new GraphQLObjectType({ + name: 'Person', + fields: () => ({ + name: { type: GraphQLString }, + bestFriend: { type: PersonType }, + }) +}); +``` + +### GraphQLInterfaceType + +```js +class GraphQLInterfaceType { + constructor(config: GraphQLInterfaceTypeConfig) +} + +type GraphQLInterfaceTypeConfig = { + name: string, + fields: GraphQLFieldConfigMapThunk | GraphQLFieldConfigMap, + resolveType?: (value: any, info?: GraphQLResolveInfo) => ?GraphQLObjectType, + description?: ?string +}; +``` + +When a field can return one of a heterogeneous set of types, a Interface type +is used to describe what types are possible, what fields are in common across +all types, as well as a function to determine which type is actually used +when the field is resolved. + +#### Example + +```js +var EntityType = new GraphQLInterfaceType({ + name: 'Entity', + fields: { + name: { type: GraphQLString } + } +}); +``` + +### GraphQLUnionType + +```js +class GraphQLUnionType { + constructor(config: GraphQLUnionTypeConfig) +} + +type GraphQLUnionTypeConfig = { + name: string, + types: GraphQLObjectsThunk | Array, + resolveType?: (value: any, info?: GraphQLResolveInfo) => ?GraphQLObjectType; + description?: ?string; +}; + +type GraphQLObjectsThunk = () => Array; +``` + +When a field can return one of a heterogeneous set of types, a Union type +is used to describe what types are possible as well as providing a function +to determine which type is actually used when the field is resolved. + +### Example + +```js +var PetType = new GraphQLUnionType({ + name: 'Pet', + types: [ DogType, CatType ], + resolveType(value) { + if (value instanceof Dog) { + return DogType; + } + if (value instanceof Cat) { + return CatType; + } + } +}); +``` + +### GraphQLEnumType + +```js +class GraphQLEnumType { + constructor(config: GraphQLEnumTypeConfig) +} + +type GraphQLEnumTypeConfig = { + name: string; + values: GraphQLEnumValueConfigMap; + description?: ?string; +} + +type GraphQLEnumValueConfigMap = { + [valueName: string]: GraphQLEnumValueConfig; +}; + +type GraphQLEnumValueConfig = { + value?: any; + deprecationReason?: string; + description?: ?string; +} + +type GraphQLEnumValueDefinition = { + name: string; + value?: any; + deprecationReason?: string; + description?: ?string; +} +``` + +Some leaf values of requests and input values are Enums. GraphQL serializes +Enum values as strings, however internally Enums can be represented by any +kind of type, often integers. + +Note: If a value is not provided in a definition, the name of the enum value +will be used as its internal value. + +#### Example + +```js +var RGBType = new GraphQLEnumType({ + name: 'RGB', + values: { + RED: { value: 0 }, + GREEN: { value: 1 }, + BLUE: { value: 2 } + } +}); +``` + +### GraphQLInputObjectType + +```js +class GraphQLInputObjectType { + constructor(config: GraphQLInputObjectConfig) +} + +type GraphQLInputObjectConfig = { + name: string; + fields: GraphQLInputObjectConfigFieldMapThunk | GraphQLInputObjectConfigFieldMap; + description?: ?string; +} + +type GraphQLInputObjectConfigFieldMapThunk = () => GraphQLInputObjectConfigFieldMap; + +type GraphQLInputObjectFieldConfig = { + type: GraphQLInputType; + defaultValue?: any; + description?: ?string; +} + +type GraphQLInputObjectConfigFieldMap = { + [fieldName: string]: GraphQLInputObjectFieldConfig; +}; + +type GraphQLInputObjectField = { + name: string; + type: GraphQLInputType; + defaultValue?: any; + description?: ?string; +} + +type GraphQLInputObjectFieldMap = { + [fieldName: string]: GraphQLInputObjectField; +}; +``` + +An input object defines a structured collection of fields which may be +supplied to a field argument. + +Using `NonNull` will ensure that a value must be provided by the query + +#### Example + +```js +var GeoPoint = new GraphQLInputObjectType({ + name: 'GeoPoint', + fields: { + lat: { type: new GraphQLNonNull(GraphQLFloat) }, + lon: { type: new GraphQLNonNull(GraphQLFloat) }, + alt: { type: GraphQLFloat, defaultValue: 0 }, + } +}); +``` + +### GraphQLList + +```js +class GraphQLList { + constructor(type: GraphQLType) +} +``` + +A list is a kind of type marker, a wrapping type which points to another +type. Lists are often created within the context of defining the fields of +an object type. + +#### Example + +```js +var PersonType = new GraphQLObjectType({ + name: 'Person', + fields: () => ({ + parents: { type: new GraphQLList(Person) }, + children: { type: new GraphQLList(Person) }, + }) +}); +``` + +### GraphQLNonNull + +```js +class GraphQLNonNull { + constructor(type: GraphQLType) +} +``` + +A non-null is a kind of type marker, a wrapping type which points to another +type. Non-null types enforce that their values are never null and can ensure +an error is raised if this ever occurs during a request. It is useful for +fields which you can make a strong guarantee on non-nullability, for example +usually the id field of a database row will never be null. + +#### Example + +```js +var RowType = new GraphQLObjectType({ + name: 'Row', + fields: () => ({ + id: { type: new GraphQLNonNull(String) }, + }) +}); +``` + +## Predicates + +### isInputType + +```js +function isInputType(type: ?GraphQLType): boolean +``` + +These types may be used as input types for arguments and directives. + +### isOutputType + +```js +function isOutputType(type: ?GraphQLType): boolean +``` + +These types may be used as output types as the result of fields + +### isLeafType + +```js +function isLeafType(type: ?GraphQLType): boolean +``` + +These types may describe types which may be leaf values + +### isCompositeType + +```js +function isCompositeType(type: ?GraphQLType): boolean +``` + +These types may describe the parent context of a selection set + +### isAbstractType + +```js +function isAbstractType(type: ?GraphQLType): boolean +``` + +These types may describe a combination of object types + +## Un-modifiers + +### getNullableType + +```js +function getNullableType(type: ?GraphQLType): ?GraphQLNullableType +``` + +If a given type is non-nullable, this strips the non-nullability and +returns the underlying type. + +### getNamedType + +```js +function getNamedType(type: ?GraphQLType): ?GraphQLNamedType +``` + +If a given type is non-nullable or a list, this repeated strips the +non-nullability and list wrappers and returns the underlying type. + +## Scalars + +### GraphQLInt + +```js +var GraphQLInt: GraphQLScalarType; +``` + +A `GraphQLScalarType` that represents an int. + +### GraphQLFloat + +```js +var GraphQLFloat: GraphQLScalarType; +``` + +A `GraphQLScalarType` that represents a float. + +### GraphQLString + +```js +var GraphQLString: GraphQLScalarType; +``` + +A `GraphQLScalarType` that represents a string. + +### GraphQLBoolean + +```js +var GraphQLBoolean: GraphQLScalarType; +``` + +A `GraphQLScalarType` that represents a boolean. + +### GraphQLID + +```js +var GraphQLID: GraphQLScalarType; +``` + +A `GraphQLScalarType` that represents an ID. diff --git a/docs/APIReference-Utilities.md b/docs/APIReference-Utilities.md new file mode 100644 index 0000000000..2b0b0625ae --- /dev/null +++ b/docs/APIReference-Utilities.md @@ -0,0 +1,245 @@ +--- +title: graphql/utilities +layout: ../_core/GraphQLJSLayout +category: API Reference +permalink: /graphql-js/utilities/ +sublinks: astFromValue,buildASTSchema,buildClientSchema,buildSchema,introspectionQuery,isValidJSValue,isValidLiteralValue,printIntrospectionSchema,printSchema,typeFromAST,TypeInfo +next: /graphql-js/validation/ +--- + +The `graphql/utilities` module contains common useful computations to use with +the GraphQL language and type objects. You can import either from the `graphql/utilities` module, or from the root `graphql` module. For example: + +```js +import { introspectionQuery } from 'graphql'; // ES6 +var { introspectionQuery } = require('graphql'); // CommonJS +``` + +## Overview + +*Introspection* + + + +*Schema Language* + + + +*Visitors* + + + +*Value Validation* + + + +## Introspection + +### introspectionQuery + +```js +var introspectionQuery: string +``` + +A GraphQL query that queries a server's introspection system for enough +information to reproduce that server's type system. + +### buildClientSchema + +```js +function buildClientSchema( + introspection: IntrospectionQuery +): GraphQLSchema +``` + +Build a GraphQLSchema for use by client tools. + +Given the result of a client running the introspection query, creates and +returns a GraphQLSchema instance which can be then used with all GraphQL.js +tools, but cannot be used to execute a query, as introspection does not +represent the "resolver", "parse" or "serialize" functions or any other +server-internal mechanisms. + +## Schema Representation + +### buildSchema + +```js +function buildSchema(source: string | Source): GraphQLSchema { +``` + +Creates a GraphQLSchema object from GraphQL schema language. The schema will use default resolvers. For more detail on the GraphQL schema language, see the [schema language docs](/learn/schema/) or this [schema language cheat sheet](https://wehavefaces.net/graphql-shorthand-notation-cheatsheet-17cd715861b6#.9oztv0a7n). + +### printSchema + +```js +function printSchema(schema: GraphQLSchema): string { +``` + +Prints the provided schema in the Schema Language format. + +### printIntrospectionSchema + +```js +function printIntrospectionSchema(schema: GraphQLSchema): string { +``` + +Prints the built-in introspection schema in the Schema Language format. + +### buildASTSchema + +```js +function buildASTSchema( + ast: SchemaDocument, + queryTypeName: string, + mutationTypeName: ?string +): GraphQLSchema +``` + +This takes the ast of a schema document produced by `parseSchemaIntoAST` in +`graphql/language/schema` and constructs a GraphQLSchema instance which can be +then used with all GraphQL.js tools, but cannot be used to execute a query, as +introspection does not represent the "resolver", "parse" or "serialize" +functions or any other server-internal mechanisms. + +### typeFromAST + +```js +function typeFromAST( + schema: GraphQLSchema, + inputTypeAST: Type +): ?GraphQLType +``` + +Given the name of a Type as it appears in a GraphQL AST and a Schema, return the +corresponding GraphQLType from that schema. + +### astFromValue + +```js +function astFromValue( + value: any, + type?: ?GraphQLType +): ?Value +``` +Produces a GraphQL Input Value AST given a JavaScript value. + +Optionally, a GraphQL type may be provided, which will be used to +disambiguate between value primitives. + +## Visitors + +### TypeInfo + +```js +class TypeInfo { + constructor(schema: GraphQLSchema) + getType(): ?GraphQLOutputType { + getParentType(): ?GraphQLCompositeType { + getInputType(): ?GraphQLInputType { + getFieldDef(): ?GraphQLFieldDefinition { + getDirective(): ?GraphQLDirective { + getArgument(): ?GraphQLArgument { +} +``` + +TypeInfo is a utility class which, given a GraphQL schema, can keep track +of the current field and type definitions at any point in a GraphQL document +AST during a recursive descent by calling `enter(node)` and `leave(node)`. + +## Value Validation + +### isValidJSValue + +```js +function isValidJSValue(value: any, type: GraphQLInputType): string[] +``` + +Given a JavaScript value and a GraphQL type, determine if the value will be +accepted for that type. This is primarily useful for validating the +runtime values of query variables. + +### isValidLiteralValue + +```js +function isValidLiteralValue( + type: GraphQLInputType, + valueAST: Value +): string[] +``` + +Utility for validators which determines if a value literal AST is valid given +an input type. + +Note that this only validates literal values, variables are assumed to +provide values of the correct type. diff --git a/docs/APIReference-Validation.md b/docs/APIReference-Validation.md new file mode 100644 index 0000000000..e9c28ebbe0 --- /dev/null +++ b/docs/APIReference-Validation.md @@ -0,0 +1,68 @@ +--- +title: graphql/validation +layout: ../_core/GraphQLJSLayout +category: API Reference +permalink: /graphql-js/validation/ +sublinks: specifiedRules,validate +--- + +The `graphql/validation` module fulfills the Validation phase of fulfilling a +GraphQL result. You can import either from the `graphql/validation` module, or from the root `graphql` module. For example: + +```js +import { validate } from 'graphql/validation'; // ES6 +var { validate } = require('graphql/validation'); // CommonJS +``` + +## Overview + + + +## Validation + +### validate + +```js +function validate( + schema: GraphQLSchema, + ast: Document, + rules?: Array +): Array +``` + +Implements the "Validation" section of the spec. + +Validation runs synchronously, returning an array of encountered errors, or +an empty array if no errors were encountered and the document is valid. + +A list of specific validation rules may be provided. If not provided, the +default list of rules defined by the GraphQL specification will be used. + +Each validation rules is a function which returns a visitor +(see the language/visitor API). Visitor methods are expected to return +GraphQLErrors, or Arrays of GraphQLErrors when invalid. + +Visitors can also supply `visitSpreadFragments: true` which will alter the +behavior of the visitor to skip over top level defined fragments, and instead +visit those fragments at every point a spread is encountered. + +### specifiedRules + +```js +var specifiedRules: Array<(context: ValidationContext): any> +``` + +This set includes all validation rules defined by the GraphQL spec diff --git a/docs/Guides-ConstructingTypes.md b/docs/Guides-ConstructingTypes.md new file mode 100644 index 0000000000..9abd6e100d --- /dev/null +++ b/docs/Guides-ConstructingTypes.md @@ -0,0 +1,117 @@ +--- +title: Constructing Types +layout: ../_core/GraphQLJSLayout +category: Advanced Guides +permalink: /graphql-js/constructing-types/ +next: /graphql-js/express-graphql/ +--- + +For many apps, you can define a fixed schema when the application starts, and define it using GraphQL schema language. In some cases, it's useful to construct a schema programmatically. You can do this using the `GraphQLSchema` constructor. + +When you are using the `GraphQLSchema` constructor to create a schema, instead of defining `Query` and `Mutation` types solely using schema language, you create them as separate object types. + +For example, let's say we are building a simple API that lets you fetch user data for a few hardcoded users based on an id. Using `buildSchema` we could write a server with: + +```javascript +var express = require('express'); +var graphqlHTTP = require('express-graphql'); +var { buildSchema } = require('graphql'); + +var schema = buildSchema(` + type User { + id: String + name: String + } + + type Query { + user(id: String): User + } +`); + +// Maps id to User object +var fakeDatabase = { + 'a': { + id: 'a', + name: 'alice', + }, + 'b': { + id: 'b', + name: 'bob', + }, +}; + +var root = { + user: function ({id}) { + return fakeDatabase[id]; + } +}; + +var app = express(); +app.use('/graphql', graphqlHTTP({ + schema: schema, + rootValue: root, + graphiql: true, +})); +app.listen(4000); +console.log('Running a GraphQL API server at localhost:4000/graphql'); +``` + +We can implement this same API without using GraphQL schema language: + +```javascript +var express = require('express'); +var graphqlHTTP = require('express-graphql'); +var graphql = require('graphql'); + +// Maps id to User object +var fakeDatabase = { + 'a': { + id: 'a', + name: 'alice', + }, + 'b': { + id: 'b', + name: 'bob', + }, +}; + +// Define the User type +var userType = new graphql.GraphQLObjectType({ + name: 'User', + fields: { + id: { type: graphql.GraphQLString }, + name: { type: graphql.GraphQLString }, + } +}); + +// Define the Query type +var queryType = new graphql.GraphQLObjectType({ + name: 'Query', + fields: { + user: { + type: userType, + // `args` describes the arguments that the `user` query accepts + args: { + id: { type: graphql.GraphQLString } + }, + resolve: function (_, {id}) { + return fakeDatabase[id]; + } + } + } +}); + +var schema = new graphql.GraphQLSchema({query: queryType}); + +var app = express(); +app.use('/graphql', graphqlHTTP({ + schema: schema, + graphiql: true, +})); +app.listen(4000); +console.log('Running a GraphQL API server at localhost:4000/graphql'); +``` + +When we use this method of creating the API, the root level resolvers are implemented on the `Query` and `Mutation` types rather than on a `root` object. + +This is particularly useful if you want to create a GraphQL schema automatically from something else, like a database schema. You might have a common format for something like creating and updating database records. This is also useful for implementing features like union types which don't map cleanly to ES6 classes and schema language. diff --git a/docs/Tutorial-Authentication.md b/docs/Tutorial-Authentication.md new file mode 100644 index 0000000000..2ad93de475 --- /dev/null +++ b/docs/Tutorial-Authentication.md @@ -0,0 +1,53 @@ +--- +title: Authentication and Express Middleware +sidebarTitle: Authentication & Middleware +layout: ../_core/GraphQLJSLayout +category: GraphQL.js Tutorial +permalink: /graphql-js/authentication-and-express-middleware/ +next: /graphql-js/constructing-types/ +--- + +It's simple to use any Express middleware in conjunction with `express-graphql`. In particular, this is a great pattern for handling authentication. + +To use middleware with a GraphQL resolver, just use the middleware like you would with a normal Express app. The `request` object is then available as the second argument in any resolver. + +For example, let's say we wanted our server to log the IP address of every request, and we also want to write an API that returns the IP address of the caller. We can do the former with middleware, and the latter by accessing the `request` object in a resolver. Here's server code that implements this: + +```javascript +var express = require('express'); +var graphqlHTTP = require('express-graphql'); +var { buildSchema } = require('graphql'); + +var schema = buildSchema(` + type Query { + ip: String + } +`); + +function loggingMiddleware(req, res, next) { + console.log('ip:', req.ip); + next(); +} + +var root = { + ip: function (args, request) { + return request.ip; + } +}; + +var app = express(); +app.use(loggingMiddleware); +app.use('/graphql', graphqlHTTP({ + schema: schema, + rootValue: root, + graphiql: true, +})); +app.listen(4000); +console.log('Running a GraphQL API server at localhost:4000/graphql'); +``` + +In a REST API, authentication is often handled with a header, that contains an auth token which proves what user is making this request. Express middleware processes these headers and puts authentication data on the Express `request` object. Some middleware modules that handle authentication like this are [Passport](http://passportjs.org/), [express-jwt](https://github.com/auth0/express-jwt), and [express-session](https://github.com/expressjs/session). Each of these modules works with `express-graphql`. + +If you aren't familiar with any of these authentication mechanisms, we recommend using `express-jwt` because it's simple without sacrificing any future flexibility. + +If you've read through the docs linearly to get to this point, congratulations! You now know everything you need to build a practical GraphQL API server. diff --git a/docs/Tutorial-BasicTypes.md b/docs/Tutorial-BasicTypes.md new file mode 100644 index 0000000000..4532f03f01 --- /dev/null +++ b/docs/Tutorial-BasicTypes.md @@ -0,0 +1,58 @@ +--- +title: Basic Types +layout: ../_core/GraphQLJSLayout +category: GraphQL.js Tutorial +permalink: /graphql-js/basic-types/ +next: /graphql-js/passing-arguments/ +--- + +In most situations, all you need to do is to specify the types for your API using the GraphQL schema language, taken as an argument to the `buildSchema` function. + +The GraphQL schema language supports the scalar types of `String`, `Int`, `Float`, `Boolean`, and `ID`, so you can use these directly in the schema you pass to `buildSchema`. + +By default, every type is nullable - it's legitimate to return `null` as any of the scalar types. Use an exclamation point to indicate a type cannot be nullable, so `String!` is a non-nullable string. + +To use a list type, surround the type in square brackets, so `[Int]` is a list of integers. + +Each of these types maps straightforwardly to JavaScript, so you can just return plain old JavaScript objects in APIs that return these types. Here's an example that shows how to use some of these basic types: + +```javascript +var express = require('express'); +var graphqlHTTP = require('express-graphql'); +var { buildSchema } = require('graphql'); + +// Construct a schema, using GraphQL schema language +var schema = buildSchema(` + type Query { + quoteOfTheDay: String + random: Float! + rollThreeDice: [Int] + } +`); + +// The root provides a resolver function for each API endpoint +var root = { + quoteOfTheDay: () => { + return Math.random() < 0.5 ? 'Take it easy' : 'Salvation lies within'; + }, + random: () => { + return Math.random(); + }, + rollThreeDice: () => { + return [1, 2, 3].map(_ => 1 + Math.floor(Math.random() * 6)); + }, +}; + +var app = express(); +app.use('/graphql', graphqlHTTP({ + schema: schema, + rootValue: root, + graphiql: true, +})); +app.listen(4000); +console.log('Running a GraphQL API server at localhost:4000/graphql'); +``` + +If you run this code with `node server.js` and browse to http://localhost:4000/graphql you can try out these APIs. + +These examples show you how to call APIs that return different types. To send different types of data into an API, you will also need to learn about [passing arguments to a GraphQL API](/graphql-js/passing-arguments/). diff --git a/docs/Tutorial-ExpressGraphQL.md b/docs/Tutorial-ExpressGraphQL.md new file mode 100644 index 0000000000..6fbfd57c67 --- /dev/null +++ b/docs/Tutorial-ExpressGraphQL.md @@ -0,0 +1,59 @@ +--- +title: Running an Express GraphQL Server +sidebarTitle: Running Express + GraphQL +layout: ../_core/GraphQLJSLayout +category: GraphQL.js Tutorial +permalink: /graphql-js/running-an-express-graphql-server/ +next: /graphql-js/graphql-clients/ +--- + +The simplest way to run an GraphQL API server is to use [Express](https://expressjs.com), a popular web application framework for Node.js. You will need to install two additional dependencies: + +```bash +npm install express express-graphql graphql --save +``` + +Let's modify our “hello world” example so that it's an API server rather than a script that runs a single query. We can use the 'express' module to run a webserver, and instead of executing a query directly with the `graphql` function, we can use the `express-graphql` library to mount a GraphQL API server on the “/graphql” HTTP endpoint: + +```javascript +var express = require('express'); +var graphqlHTTP = require('express-graphql'); +var { buildSchema } = require('graphql'); + +// Construct a schema, using GraphQL schema language +var schema = buildSchema(` + type Query { + hello: String + } +`); + +// The root provides a resolver function for each API endpoint +var root = { + hello: () => { + return 'Hello world!'; + }, +}; + +var app = express(); +app.use('/graphql', graphqlHTTP({ + schema: schema, + rootValue: root, + graphiql: true, +})); +app.listen(4000); +console.log('Running a GraphQL API server at localhost:4000/graphql'); +``` + +You can run this GraphQL server with: + +```bash +node server.js +``` + +Since we configured `graphqlHTTP` with `graphiql: true`, you can use the GraphiQL tool to manually issue GraphQL queries. If you navigate in a web browser to `http://localhost:4000/graphql`, you should see an interface that lets you enter queries. It should look like: + +![hello world graphql example](/img/hello.png) + +This screen shot shows the GraphQL query `{ hello }` being issued and giving a result of `{ data: { hello: 'Hello world!' } }`. GraphiQL is a great tool for debugging and inspecting a server, so we recommend running it whenever your application is in development mode. + +At this point you have learned how to run a GraphQL server and how to use GraphiQL interface to issue queries. The next step is to learn how to [issue GraphQL queries from client code](/graphql-js/graphql-clients/). diff --git a/docs/Tutorial-GettingStarted.md b/docs/Tutorial-GettingStarted.md new file mode 100644 index 0000000000..0e492ae00d --- /dev/null +++ b/docs/Tutorial-GettingStarted.md @@ -0,0 +1,62 @@ +--- +title: Getting Started With GraphQL.js +sidebarTitle: Getting Started +layout: ../_core/GraphQLJSLayout +category: GraphQL.js Tutorial +permalink: /graphql-js/ +next: /graphql-js/running-an-express-graphql-server/ +--- + +## Prerequisites + +Before getting started, you should have Node v6 installed, although the examples should mostly work in previous versions of Node as well. For this guide, we won't use any language features that require transpilation, but we will use some ES6 features like [Promises](http://www.html5rocks.com/en/tutorials/es6/promises/), [classes](http://javascriptplayground.com/blog/2014/07/introduction-to-es6-classes-tutorial/), and [fat arrow functions](https://strongloop.com/strongblog/an-introduction-to-javascript-es6-arrow-functions/), so if you aren't familiar with them you might want to read up on them first. + +To create a new project and install GraphQL.js in your current directory: + +```bash +npm init +npm install graphql --save +``` + +## Writing Code + +To handle GraphQL queries, we need a schema that defines the `Query` type, and we need an API root with a function called a “resolver” for each API endpoint. For an API that just returns “Hello world!”, we can put this code in a file named `server.js`: + +```javascript +var { graphql, buildSchema } = require('graphql'); + +// Construct a schema, using GraphQL schema language +var schema = buildSchema(` + type Query { + hello: String + } +`); + +// The root provides a resolver function for each API endpoint +var root = { + hello: () => { + return 'Hello world!'; + }, +}; + +// Run the GraphQL query '{ hello }' and print out the response +graphql(schema, '{ hello }', root).then((response) => { + console.log(response); +}); +``` + +If you run this with: + +```bash +node server.js +``` + +You should see the GraphQL response printed out: + +```javascript +{ data: { hello: 'Hello world!' } } +``` + +Congratulations - you just executed a GraphQL query! + +For practical applications, you'll probably want to run GraphQL queries from an API server, rather than executing GraphQL with a command line tool. To use GraphQL for an API server over HTTP, check out [Running an Express GraphQL Server](/graphql-js/running-an-express-graphql-server/). diff --git a/docs/Tutorial-GraphQLClients.md b/docs/Tutorial-GraphQLClients.md new file mode 100644 index 0000000000..68485e4367 --- /dev/null +++ b/docs/Tutorial-GraphQLClients.md @@ -0,0 +1,87 @@ +--- +title: GraphQL Clients +layout: ../_core/GraphQLJSLayout +category: GraphQL.js Tutorial +permalink: /graphql-js/graphql-clients/ +next: /graphql-js/basic-types/ +--- + +Since a GraphQL API has more underlying structure than a REST API, there are more powerful clients like [Relay](https://facebook.github.io/relay/) which can automatically handle batching, caching, and other features. But you don't need a complex client to call a GraphQL server. With `express-graphql`, you can just send an HTTP POST request to the endpoint you mounted your GraphQL server on, passing the GraphQL query as the `query` field in a JSON payload. + +For example, let's say we mounted a GraphQL server on http://localhost:4000/graphql as in the example code for [running an Express GraphQL server](/graphql-js/running-an-express-graphql-server/), and we want to send the GraphQL query `{ hello }`. We can do this from the command line with `curl`. If you paste this into a terminal: + +```bash +curl -X POST \ +-H "Content-Type: application/json" \ +-d '{"query": "{ hello }"}' \ +http://localhost:4000/graphql +``` + +You should see the output returned as JSON: + +```bash +{"data":{"hello":"Hello world!"}} +``` + +If you prefer to use a graphical user interface to send a test query, you can use clients such as [GraphiQL](https://github.com/graphql/graphiql) and [Insomnia](https://github.com/getinsomnia/insomnia). + +It's also simple to send GraphQL from the browser. Open up http://localhost:4000, open a developer console, and paste in: + +```javascript +fetch('/graphql', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }, + body: JSON.stringify({query: "{ hello }"}) +}) + .then(r => r.json()) + .then(data => console.log('data returned:', data)); +``` + +You should see the data returned, logged in the console: + +``` +data returned: Object { hello: "Hello world!" } +``` + +In this example, the query was just a hardcoded string. As your application becomes more complex, and you add GraphQL endpoints that take arguments as described in [Passing Arguments](/graphql-js/passing-arguments/), you will want to construct GraphQL queries using variables in client code. You can do this by including a keyword prefixed with a dollar sign in the query, and passing an extra `variables` field on the payload. + +For example, let's say you're running the example server from [Passing Arguments](/graphql-js/passing-arguments/) that has a schema of + +```javascript +type Query { + rollDice(numDice: Int!, numSides: Int): [Int] +} +``` + +You could access this from JavaScript with the code: + +```javascript +var dice = 3; +var sides = 6; +var query = `query RollDice($dice: Int!, $sides: Int) { + rollDice(numDice: $dice, numSides: $sides) +}`; + +fetch('/graphql', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }, + body: JSON.stringify({ + query, + variables: { dice, sides }, + }) +}) + .then(r => r.json()) + .then(data => console.log('data returned:', data)); +``` + +Using this syntax for variables is a good idea because it automatically prevents bugs due to escaping, and it makes it easier to monitor your server. + +In general, it will take a bit more time to set up a GraphQL client like Relay, but it's worth it to get more features as your application grows. You might want to start out just using HTTP requests as the underlying transport layer, and switching to a more complex client as your application gets more complex. + +At this point you can write a client and server in GraphQL for an API that receives a single string. To do more, you will want to [learn how to use the other basic data types](/graphql-js/basic-types/). diff --git a/docs/Tutorial-Mutations.md b/docs/Tutorial-Mutations.md new file mode 100644 index 0000000000..2ccde6ae68 --- /dev/null +++ b/docs/Tutorial-Mutations.md @@ -0,0 +1,194 @@ +--- +title: Mutations and Input Types +layout: ../_core/GraphQLJSLayout +category: GraphQL.js Tutorial +permalink: /graphql-js/mutations-and-input-types/ +next: /graphql-js/authentication-and-express-middleware/ +--- + +If you have an API endpoint that alters data, like inserting data into a database or altering data already in a database, you should make this endpoint a `Mutation` rather than a `Query`. This is as simple as making the API endpoint part of the top-level `Mutation` type instead of the top-level `Query` type. + +Let's say we have a “message of the day” server, where anyone can update the message of the day, and anyone can read the current one. The GraphQL schema for this is simply: + +```javascript +type Mutation { + setMessage(message: String): String +} + +type Query { + getMessage: String +} +``` + +It's often convenient to have a mutation that maps to a database create or update operation, like `setMessage`, return the same thing that the server stored. That way, if you modify the data on the server, the client can learn about those modifications. + +Both mutations and queries can be handled by root resolvers, so the root that implements this schema can simply be: + +```javascript +var fakeDatabase = {}; +var root = { + setMessage: function ({message}) { + fakeDatabase.message = message; + return message; + }, + getMessage: function () { + return fakeDatabase.message; + } +}; +``` + +You don't need anything more than this to implement mutations. But in many cases, you will find a number of different mutations that all accept the same input parameters. A common example is that creating an object in a database and updating an object in a database often take the same parameters. To make your schema simpler, you can use “input types” for this, by using the `input` keyword instead of the `type` keyword. + +For example, instead of a single message of the day, let's say we have many messages, indexed in a database by the `id` field, and each message has both a `content` string and an `author` string. We want a mutation API both for creating a new message and for updating an old message. We could use the schema: + +```javascript +input MessageInput { + content: String + author: String +} + +type Message { + id: ID! + content: String + author: String +} + +type Query { + getMessage(id: ID!): Message +} + +type Mutation { + createMessage(input: MessageInput): Message + updateMessage(id: ID!, input: MessageInput): Message +} +``` + +Here, the mutations return a `Message` type, so that the client can get more information about the newly-modified `Message` in the same request as the request that mutates it. + +Input types can't have fields that are other objects, only basic scalar types, list types, and other input types. + +Naming input types with `Input` on the end is a useful convention, because you will often want both an input type and an output type that are slightly different for a single conceptual object. + +Here's some runnable code that implements this schema, keeping the data in memory: + +```javascript +var express = require('express'); +var graphqlHTTP = require('express-graphql'); +var { buildSchema } = require('graphql'); + +// Construct a schema, using GraphQL schema language +var schema = buildSchema(` + input MessageInput { + content: String + author: String + } + + type Message { + id: ID! + content: String + author: String + } + + type Query { + getMessage(id: ID!): Message + } + + type Mutation { + createMessage(input: MessageInput): Message + updateMessage(id: ID!, input: MessageInput): Message + } +`); + +// If Message had any complex fields, we'd put them on this object. +class Message { + constructor(id, {content, author}) { + this.id = id; + this.content = content; + this.author = author; + } +} + +// Maps username to content +var fakeDatabase = {}; + +var root = { + getMessage: function ({id}) { + if (!fakeDatabase[id]) { + throw new Error('no message exists with id ' + id); + } + return new Message(id, fakeDatabase[id]); + }, + createMessage: function ({input}) { + // Create a random id for our "database". + var id = require('crypto').randomBytes(10).toString('hex'); + + fakeDatabase[id] = input; + return new Message(id, input); + }, + updateMessage: function ({id, input}) { + if (!fakeDatabase[id]) { + throw new Error('no message exists with id ' + id); + } + // This replaces all old data, but some apps might want partial update. + fakeDatabase[id] = input; + return new Message(id, input); + }, +}; + +var app = express(); +app.use('/graphql', graphqlHTTP({ + schema: schema, + rootValue: root, + graphiql: true, +})); +app.listen(4000, () => { + console.log('Running a GraphQL API server at localhost:4000/graphql'); +}); + +``` + +To call a mutation, you must use the keyword `mutation` before your GraphQL query. To pass an input type, provide the data written as if it's a JSON object. For example, with the server defined above, you can create a new message and return the `id` of the new message with this operation: + +```javascript +mutation { + createMessage(input: { + author: "andy", + content: "hope is a good thing", + }) { + id + } +} +``` + +You can use variables to simplify mutation client logic just like you can with queries. For example, some JavaScript code that calls the server to execute this mutation is: + +```javascript +var author = 'andy'; +var content = 'hope is a good thing'; +var query = `mutation CreateMessage($input: MessageInput) { + createMessage(input: $input) { + id + } +}`; + +fetch('/graphql', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }, + body: JSON.stringify({ + query, + variables: { + input: { + author, + content, + } + } + }) +}) + .then(r => r.json()) + .then(data => console.log('data returned:', data)); +``` + +One particular type of mutation is operations that change users, like signing up a new user. While you can implement this using GraphQL mutations, you can reuse many existing libraries if you learn about [GraphQL with authentication and Express middleware](/graphql-js/authentication-and-express-middleware/). diff --git a/docs/Tutorial-ObjectTypes.md b/docs/Tutorial-ObjectTypes.md new file mode 100644 index 0000000000..60a151f3ac --- /dev/null +++ b/docs/Tutorial-ObjectTypes.md @@ -0,0 +1,144 @@ +--- +title: Object Types +layout: ../_core/GraphQLJSLayout +category: GraphQL.js Tutorial +permalink: /graphql-js/object-types/ +next: /graphql-js/mutations-and-input-types/ +--- + +In many cases, you don't want to return a number or a string from an API. You want to return an object that has its own complex behavior. GraphQL is a perfect fit for this. + +In GraphQL schema language, the way you define a new object type is the same way we have been defining the `Query` type in our examples. Each object can have fields that return a particular type, and methods that take arguments. For example, in the [Passing Arguments](/graphql-js/passing-arguments/) documentation, we had a method to roll some random dice: + +```javascript +type Query { + rollDice(numDice: Int!, numSides: Int): [Int] +} +``` + +If we wanted to have more and more methods based on a random die over time, we could implement this with a `RandomDie` object type instead. + +```javascript +type RandomDie { + roll(numRolls: Int!): [Int] +} + +type Query { + getDie(numSides: Int): RandomDie +} +``` + +Instead of a root-level resolver for the `RandomDie` type, we can instead use an ES6 class, where the resolvers are instance methods. This code shows how the `RandomDie` schema above can be implemented: + +```javascript +class RandomDie { + constructor(numSides) { + this.numSides = numSides; + } + + rollOnce() { + return 1 + Math.floor(Math.random() * this.numSides); + } + + roll({numRolls}) { + var output = []; + for (var i = 0; i < numRolls; i++) { + output.push(this.rollOnce()); + } + return output; + } +} + +var root = { + getDie: function ({numSides}) { + return new RandomDie(numSides || 6); + } +} +``` + +For fields that don't use any arguments, you can use either properties on the object or instance methods. So for the example code above, both `numSides` and `rollOnce` can actually be used to implement GraphQL fields, so that code also implements the schema of: + +```javascript +type RandomDie { + numSides: Int! + rollOnce: Int! + roll(numRolls: Int!): [Int] +} + +type Query { + getDie(numSides: Int): RandomDie +} +``` + +Putting this all together, here is some sample code that runs a server with this GraphQL API: + +```javascript +var express = require('express'); +var graphqlHTTP = require('express-graphql'); +var { buildSchema } = require('graphql'); + +// Construct a schema, using GraphQL schema language +var schema = buildSchema(` + type RandomDie { + numSides: Int! + rollOnce: Int! + roll(numRolls: Int!): [Int] + } + + type Query { + getDie(numSides: Int): RandomDie + } +`); + +// This class implements the RandomDie GraphQL type +class RandomDie { + constructor(numSides) { + this.numSides = numSides; + } + + rollOnce() { + return 1 + Math.floor(Math.random() * this.numSides); + } + + roll({numRolls}) { + var output = []; + for (var i = 0; i < numRolls; i++) { + output.push(this.rollOnce()); + } + return output; + } +} + +// The root provides the top-level API endpoints +var root = { + getDie: function ({numSides}) { + return new RandomDie(numSides || 6); + } +} + +var app = express(); +app.use('/graphql', graphqlHTTP({ + schema: schema, + rootValue: root, + graphiql: true, +})); +app.listen(4000); +console.log('Running a GraphQL API server at localhost:4000/graphql'); +``` + +When you issue a GraphQL query against an API that returns object types, you can call multiple methods on the object at once by nesting the GraphQL field names. For example, if you wanted to call both `rollOnce` to roll a die once, and `roll` to roll a die three times, you could do it with this query: + +```javascript +{ + getDie(numSides: 6) { + rollOnce + roll(numRolls: 3) + } +} +``` + +If you run this code with `node server.js` and browse to http://localhost:4000/graphql you can try out these APIs with GraphiQL. + +This way of defining object types often provides advantages over a traditional REST API. Instead of doing one API request to get basic information about an object, and then multiple subsequent API requests to find out more information about that object, you can get all of that information in one API request. That saves bandwidth, makes your app run faster, and simplifies your client-side logic. + +So far, every API we've looked at is designed for returning data. In order to modify stored data or handle complex input, it helps to [learn about mutations and input types](/graphql-js/mutations-and-input-types/). diff --git a/docs/Tutorial-PassingArguments.md b/docs/Tutorial-PassingArguments.md new file mode 100644 index 0000000000..47154b488b --- /dev/null +++ b/docs/Tutorial-PassingArguments.md @@ -0,0 +1,130 @@ +--- +title: Passing Arguments +layout: ../_core/GraphQLJSLayout +category: GraphQL.js Tutorial +permalink: /graphql-js/passing-arguments/ +next: /graphql-js/object-types/ +--- + +Just like a REST API, it's common to pass arguments to an endpoint in a GraphQL API. By defining the arguments in the schema language, typechecking happens automatically. Each argument must be named and have a type. For example, in the [Basic Types documentation](/graphql-js/basic-types/) we had an endpoint called `rollThreeDice`: + +```javascript +type Query { + rollThreeDice: [Int] +} +``` + +Instead of hardcoding “three”, we might want a more general function that rolls `numDice` dice, each of which have `numSides` sides. We can add arguments to the GraphQL schema language like this: + +```javascript +type Query { + rollDice(numDice: Int!, numSides: Int): [Int] +} +``` + +The exclamation point in `Int!` indicates that `numDice` can't be null, which means we can skip a bit of validation logic to make our server code simpler. We can let `numSides` be null and assume that by default a die has 6 sides. + +So far, our resolver functions took no arguments. When a resolver takes arguments, they are passed as one “args” object, as the first argument to the function. So rollDice could be implemented as: + +```javascript +var root = { + rollDice: function (args) { + var output = []; + for (var i = 0; i < args.numDice; i++) { + output.push(1 + Math.floor(Math.random() * (args.numSides || 6))); + } + return output; + } +}; +``` + +It's convenient to use [ES6 destructuring assignment](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) for these parameters, since you know what format they will be. So we can also write `rollDice` as + +```javascript +var root = { + rollDice: function ({numDice, numSides}) { + var output = []; + for (var i = 0; i < numDice; i++) { + output.push(1 + Math.floor(Math.random() * (numSides || 6))); + } + return output; + } +}; +``` + +If you're familiar with destructuring, this is a bit nicer because the line of code where `rollDice` is defined tells you about what the arguments are. + +The entire code for a server that hosts this `rollDice` API is: + +```javascript +var express = require('express'); +var graphqlHTTP = require('express-graphql'); +var { buildSchema } = require('graphql'); + +// Construct a schema, using GraphQL schema language +var schema = buildSchema(` + type Query { + rollDice(numDice: Int!, numSides: Int): [Int] + } +`); + +// The root provides a resolver function for each API endpoint +var root = { + rollDice: function ({numDice, numSides}) { + var output = []; + for (var i = 0; i < numDice; i++) { + output.push(1 + Math.floor(Math.random() * (numSides || 6))); + } + return output; + } +}; + +var app = express(); +app.use('/graphql', graphqlHTTP({ + schema: schema, + rootValue: root, + graphiql: true, +})); +app.listen(4000); +console.log('Running a GraphQL API server at localhost:4000/graphql'); +``` + +When you call this API, you have to pass each argument by name. So for the server above, you could issue this GraphQL query to roll three six-sided dice: + +```javascript +{ + rollDice(numDice: 3, numSides: 6) +} +``` + +If you run this code with `node server.js` and browse to http://localhost:4000/graphql you can try out this API. + +When you're passing arguments in code, it's generally better to avoid constructing the whole query string yourself. Instead, you can use `$` syntax to define variables in your query, and pass the variables as a separate map. + +For example, some JavaScript code that calls our server above is: + +```javascript +var dice = 3; +var sides = 6; +var query = `query RollDice($dice: Int!, $sides: Int) { + rollDice(numDice: $dice, numSides: $sides) +}`; + +fetch('/graphql', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }, + body: JSON.stringify({ + query, + variables: { dice, sides }, + }) +}) + .then(r => r.json()) + .then(data => console.log('data returned:', data)); +``` + +Using `$dice` and `$sides` as variables in GraphQL means we don't have to worry about escaping on the client side. + +With basic types and argument passing, you can implement anything you can implement in a REST API. But GraphQL supports even more powerful queries. You can replace multiple API calls with a single API call if you learn how to [define your own object types](/graphql-js/object-types/).