diff --git a/spec/Appendix B -- Grammar Summary.md b/spec/Appendix B -- Grammar Summary.md index 918282358..56b7d1676 100644 --- a/spec/Appendix B -- Grammar Summary.md +++ b/spec/Appendix B -- Grammar Summary.md @@ -89,11 +89,15 @@ Note: Block string values are interpreted to exclude blank initial and trailing lines and uniform indentation with {BlockStringValue()}. -## Query Document +## Document Document : Definition+ Definition : + - ExecutableDefinition + - TypeSystemDefinition + +ExecutableDefinition : - OperationDefinition - FragmentDefinition @@ -114,9 +118,9 @@ Field : Alias? Name Arguments? Directives? SelectionSet? Alias : Name : -Arguments : ( Argument+ ) +Arguments[Const] : ( Argument[?Const]+ ) -Argument : Name : Value +Argument[Const] : Name : Value[?Const] FragmentSpread : ... FragmentName Directives? @@ -176,6 +180,124 @@ NonNullType : - NamedType ! - ListType ! -Directives : Directive+ +Directives[Const] : Directive[?Const]+ + +Directive[Const] : @ Name Arguments[?Const]? + +TypeSystemDefinition : + - SchemaDefinition + - TypeDefinition + - TypeExtension + - DirectiveDefinition + +SchemaDefinition : schema Directives[Const]? { OperationTypeDefinition+ } + +OperationTypeDefinition : OperationType : NamedType + +Description : StringValue + +TypeDefinition : + - ScalarTypeDefinition + - ObjectTypeDefinition + - InterfaceTypeDefinition + - UnionTypeDefinition + - EnumTypeDefinition + - InputObjectTypeDefinition + +TypeExtension : + - ScalarTypeExtension + - ObjectTypeExtension + - InterfaceTypeExtension + - UnionTypeExtension + - EnumTypeExtension + - InputObjectTypeExtension + +ScalarTypeDefinition : Description? scalar Name Directives[Const]? + +ScalarTypeExtension : + - extend scalar Name Directives[Const] + +ObjectTypeDefinition : Description? type Name ImplementsInterfaces? Directives[Const]? FieldsDefinition? + +ObjectTypeExtension : + - extend type Name ImplementsInterfaces? Directives[Const]? FieldsDefinition + - extend type Name ImplementsInterfaces? Directives[Const] + - extend type Name ImplementsInterfaces + +ImplementsInterfaces : + - implements `&`? NamedType + - ImplementsInterfaces & NamedType + +FieldsDefinition : { FieldDefinition+ } + +FieldDefinition : Description? Name ArgumentsDefinition? : Type Directives[Const]? + +ArgumentsDefinition : ( InputValueDefinition+ ) + +InputValueDefinition : Description? Name : Type DefaultValue? Directives[Const]? + +InterfaceTypeDefinition : Description? interface Name Directives[Const]? FieldsDefinition? + +InterfaceTypeExtension : + - extend interface Name Directives[Const]? FieldsDefinition + - extend interface Name Directives[Const] + +UnionTypeDefinition : Description? union Name Directives[Const]? UnionMemberTypes? + +UnionMemberTypes : + - = `|`? NamedType + - UnionMemberTypes | NamedType + +UnionTypeExtension : + - extend union Name Directives[Const]? UnionMemberTypes + - extend union Name Directives[Const] + +EnumTypeDefinition : Description? enum Name Directives[Const]? EnumValuesDefinition? + +EnumValuesDefinition : { EnumValueDefinition+ } + +EnumValueDefinition : Description? EnumValue Directives[Const]? + +EnumTypeExtension : + - extend enum Name Directives[Const]? EnumValuesDefinition + - extend enum Name Directives[Const] + +InputObjectTypeDefinition : Description? input Name Directives[Const]? InputFieldsDefinition? + +InputFieldsDefinition : { InputValueDefinition+ } + +InputObjectTypeExtension : + - extend input Name Directives[Const]? InputFieldsDefinition + - extend input Name Directives[Const] + +DirectiveDefinition : Description? directive @ Name ArgumentsDefinition? on DirectiveLocations + +DirectiveLocations : + - `|`? DirectiveLocation + - DirectiveLocations | DirectiveLocation + +DirectiveLocation : + - ExecutableDirectiveLocation + - TypeSystemDirectiveLocation + +ExecutableDirectiveLocation : one of + `QUERY` + `MUTATION` + `SUBSCRIPTION` + `FIELD` + `FRAGMENT_DEFINITION` + `FRAGMENT_SPREAD` + `INLINE_FRAGMENT` -Directive : @ Name Arguments? +TypeSystemDirectiveLocation : one of + `SCHEMA` + `SCALAR` + `OBJECT` + `FIELD_DEFINITION` + `ARGUMENT_DEFINITION` + `INTERFACE` + `UNION` + `ENUM` + `ENUM_VALUE` + `INPUT_OBJECT` + `INPUT_FIELD_DEFINITION` diff --git a/spec/Section 2 -- Language.md b/spec/Section 2 -- Language.md index 36a1bd153..c523b780d 100644 --- a/spec/Section 2 -- Language.md +++ b/spec/Section 2 -- Language.md @@ -45,7 +45,7 @@ WhiteSpace :: White space is used to improve legibility of source text and act as separation between tokens, and any amount of white space may appear before or after any token. White space between tokens is not significant to the semantic meaning of -a GraphQL query document, however white space characters may appear within a +a GraphQL Document, however white space characters may appear within a {String} or {Comment} token. Note: GraphQL intentionally does not consider Unicode "Zs" category characters @@ -62,7 +62,7 @@ LineTerminator :: Like white space, line terminators are used to improve the legibility of source text, any amount may appear before or after any other token and have no -significance to the semantic meaning of a GraphQL query document. Line +significance to the semantic meaning of a GraphQL Document. Line terminators are not found within any other token. Note: Any error reporting which provide the line number in the source of the @@ -84,8 +84,8 @@ comment always consists of all code points starting with the {`#`} character up to but not including the line terminator. Comments behave like white space and may appear after any token, or before a -line terminator, and have no significance to the semantic meaning of a GraphQL -query document. +line terminator, and have no significance to the semantic meaning of a +GraphQL Document. ### Insignificant Commas @@ -94,7 +94,7 @@ Comma :: , Similar to white space and line terminators, commas ({`,`}) are used to improve the legibility of source text and separate lexical tokens but are otherwise -syntactically and semantically insignificant within GraphQL query documents. +syntactically and semantically insignificant within GraphQL Documents. Non-significant comma characters ensure that the absence or presence of a comma does not meaningfully alter the interpreted syntax of the document, as this can @@ -115,8 +115,8 @@ Token :: A GraphQL document is comprised of several kinds of indivisible lexical tokens defined here in a lexical grammar by patterns of source Unicode characters. -Tokens are later used as terminal symbols in a GraphQL query document syntactic -grammars. +Tokens are later used as terminal symbols in a GraphQL Document +syntactic grammars. ### Ignored Tokens @@ -152,8 +152,8 @@ lacks the punctuation often used to describe mathematical expressions. Name :: /[_A-Za-z][_0-9A-Za-z]*/ -GraphQL query documents are full of named things: operations, fields, arguments, -directives, fragments, and variables. All names must follow the same +GraphQL Documents are full of named things: operations, fields, arguments, +types, directives, fragments, and variables. All names must follow the same grammatical form. Names in GraphQL are case-sensitive. That is to say `name`, `Name`, and `NAME` @@ -164,28 +164,40 @@ Names in GraphQL are limited to this ASCII subset of possible characters to support interoperation with as many other systems as possible. -## Query Document +## Document Document : Definition+ Definition : + - ExecutableDefinition + - TypeSystemDefinition + +ExecutableDefinition : - OperationDefinition - FragmentDefinition -A GraphQL query document describes a complete file or request string received by -a GraphQL service. A document contains multiple definitions of Operations and -Fragments. GraphQL query documents are only executable by a server if they -contain an operation. However documents which do not contain operations may -still be parsed and validated to allow client to represent a single request -across many documents. +A GraphQL Document describes a complete file or request string operated on +by a GraphQL service or client. A document contains multiple definitions, either +executable or representative of a GraphQL type system. + +Documents are only executable by a GraphQL service if they contain an +{OperationDefinition}, only contain {ExecutableDefinition} and do not contain +{TypeSystemDefinition}. However documents which do not contain +{OperationDefinition} or do contain {TypeSystemDefinition} may still be parsed +and validated to allow client tools to represent many GraphQL uses which may +appear across many individual files. -If a document contains only one operation, that operation may be unnamed or +If a Document contains only one operation, that operation may be unnamed or represented in the shorthand form, which omits both the query keyword and -operation name. Otherwise, if a GraphQL query document contains multiple -operations, each operation must be named. When submitting a query document with +operation name. Otherwise, if a GraphQL Document contains multiple +operations, each operation must be named. When submitting a Document with multiple operations to a GraphQL service, the name of the desired operation to be executed must also be provided. +GraphQL services which only seek to provide GraphQL query execution may choose +to only include {ExecutableDefinition} and omit the {TypeSystemDefinition} rule +from {Definition}. + ## Operations @@ -318,9 +330,9 @@ unique identifier. ## Arguments -Arguments : ( Argument+ ) +Arguments[Const] : ( Argument[?Const]+ ) -Argument : Name : Value +Argument[Const] : Name : Value[?Const] Fields are conceptually functions which return values, and occasionally accept arguments which alter their behavior. These arguments often map directly to @@ -1016,7 +1028,7 @@ a variable is referenced in a fragment and is included by an operation that does not define that variable, the operation cannot be executed. -## Input Types +## Type References Type : - NamedType @@ -1059,9 +1071,9 @@ Type : Type ! ## Directives -Directives : Directive+ +Directives[Const] : Directive[?Const]+ -Directive : @ Name Arguments? +Directive[Const] : @ Name Arguments[?Const]? Directives provide a way to describe alternate runtime execution and type validation behavior in a GraphQL document. diff --git a/spec/Section 3 -- Type System.md b/spec/Section 3 -- Type System.md index 06cb7e80d..e52cfbbe0 100644 --- a/spec/Section 3 -- Type System.md +++ b/spec/Section 3 -- Type System.md @@ -5,32 +5,210 @@ used to determine if a query is valid. The type system also describes the input types of query variables to determine if values provided at runtime are valid. -A GraphQL server's capabilities are referred to as that server's "schema". -A schema is defined in terms of the types and directives it supports. +TypeSystemDefinition : + - SchemaDefinition + - TypeDefinition + - TypeExtension + - DirectiveDefinition + +The GraphQL language includes an +[IDL](https://en.wikipedia.org/wiki/Interface_description_language) used to +describe a GraphQL service's type system. Tools may use this definition language +to provide utilities such as client code generation or service boot-strapping. + +GraphQL tools which only seek to provide GraphQL query execution may choose not +to parse {TypeSystemDefinition}. + +A GraphQL Document which contains {TypeSystemDefinition} must not be executed; +GraphQL execution services which receive a GraphQL Document containing type +system definitions should return a descriptive error. + +Note: The type system definition language is used throughout the remainder of +this specification document when illustrating example type systems. -A given GraphQL schema must itself be internally valid. This section describes -the rules for this validation process where relevant. -A GraphQL schema is represented by a root type for each kind of operation: +## Schema + +SchemaDefinition : schema Directives[Const]? { RootOperationTypeDefinition+ } + +RootOperationTypeDefinition : OperationType : NamedType + +A GraphQL service's collective type system capabilities are referred to as that +service's "schema". A schema is defined in terms of the types and directives it +supports as well as the root operation types for each kind of operation: query, mutation, and subscription; this determines the place in the type system where those operations begin. +A GraphQL schema must itself be internally valid. This section describes +the rules for this validation process where relevant. + All types within a GraphQL schema must have unique names. No two provided types may have the same name. No provided type may have a name which conflicts with any built in types (including Scalar and Introspection types). -All directives within a GraphQL schema must have unique names. A directive -and a type may share the same name, since there is no ambiguity between them. +All directives within a GraphQL schema must have unique names. All types and directives defined within a schema must not have a name which begins with {"__"} (two underscores), as this is used exclusively by GraphQL's introspection system. +### Root Operation Types + +A schema defines the initial root operation type for each kind of operation it +supports: query, mutation, and subscription; this determines the place in the +type system where those operations begin. + +The `query` root operation type must be provided and must be an Object type. + +The `mutation` root operation type is optional; if it is not provided, the +service does not support mutations. If it is provided, it must be an +Object type. + +Similarly, the `subscription` root operation type is also optional; if it is not +provided, the service does not support subscriptions. If it is provided, it must +be an Object type. + +The fields on the `query` root operation type indicate what fields are available +at the top level of a GraphQL query. For example, a basic GraphQL query like: + +```graphql example +query { + myName +} +``` + +Is valid when the `query` root operation type has a field named "myName". + +```graphql example +type Query { + myName: String +} +``` + +Similarly, the following mutation is valid if a `mutation` root operation type +has a field named "setName". Note that the `query` and `mutation` root types +must be different types. + +```graphql example +mutation { + setName(name: "Zuck") { + newName + } +} +``` + +When using the type system definition language, a document must include at most +one `schema` definition. + +In this example, a GraphQL schema is defined with both query and mutation +root types: + +```graphql example +schema { + query: MyQueryRootType + mutation: MyMutationRootType +} + +type MyQueryRootType { + someField: String +} + +type MyMutationRootType { + setSomeField(to: String): String +} +``` + +**Default Root Operation Type Names** + +While any type can be the root operation type for a GraphQL operation, the type +system definition language can omit the schema definition when the `query`, +`mutation`, and `subscription` root types are named `Query`, `Mutation`, and +`Subscription` respectively. + +Likewise, when representing a GraphQL schema using the type system language, a +schema definition should be omitted if it only uses the default root operation +type names. + +This example describes a valid complete GraphQL schema, despite not explicitly +including a `schema` definition. The `Query` type is presumed to be the `query` +root operation type of the schema. + +```graphql example +type Query { + someField: String +} +``` + + +## Descriptions + +Description : StringValue + +Documentation is first-class feature of GraphQL type systems. To ensure +the documentation of a GraphQL service remains consistent with its capabilities, +descriptions of GraphQL definitions are provided alongside their definitions and +made available via introspection. + +To allow GraphQL service designers to easily publish documentation alongside the +capabilities of a GraphQL service, GraphQL descriptions are defined using the +Markdown syntax (as specified by [CommonMark](http://commonmark.org/)). In the +type system definition language, these description strings (often {BlockString}) +occur immediately before the definition they describe. + +All GraphQL types, fields, arguments and other definitions which can be +described should provide a {Description} unless they are considered self +descriptive. + +As an example, this simple GraphQL schema is well described: + +```graphql example +""" +A simple GraphQL schema which is well described. +""" +type Query { + """ + Translates a string from a given language into a different language. + """ + translate( + "The original language that `text` is provided in." + fromLanguage: Language + + "The translated language to be returned." + toLanguage: Language + + "The text to be translated." + text: String + ): String +} + +""" +The set of languages supported by `translate`. +""" +enum Language { + "English" + EN + + "French" + FR + + "Chinese" + CH +} +``` + ## Types -The fundamental unit of any GraphQL Schema is the type. There are eight kinds -of types in GraphQL. +TypeDefinition : + - ScalarTypeDefinition + - ObjectTypeDefinition + - InterfaceTypeDefinition + - UnionTypeDefinition + - EnumTypeDefinition + - InputObjectTypeDefinition + +The fundamental unit of any GraphQL Schema is the type. There are six kinds +of named type definitions in GraphQL, and two wrapping types. The most basic type is a `Scalar`. A scalar represents a primitive value, like a string or an integer. Oftentimes, the possible responses for a scalar field @@ -51,25 +229,51 @@ A `Union` defines a list of possible types; similar to interfaces, whenever the type system claims a union will be returned, one of the possible types will be returned. -All of the types so far are assumed to be both nullable and singular: e.g. a scalar -string returns either null or a singular string. The type system might want to -define that it returns a list of other types; the `List` type is provided for -this reason, and wraps another type. Similarly, the `Non-Null` type wraps -another type, and denotes that the result will never be null. These two types -are referred to as "wrapping types"; non-wrapping types are referred to as -"base types". A wrapping type has an underlying "base type", found by -continually unwrapping the type until a base type is found. - Finally, oftentimes it is useful to provide complex structs as inputs to -GraphQL queries; the `Input Object` type allows the schema to define exactly -what data is expected from the client in these queries. +GraphQL field arguments or variables; the `Input Object` type allows the schema +to define exactly what data is expected. + + +### Wrapping Types + +All of the types so far are assumed to be both nullable and singular: e.g. a +scalar string returns either null or a singular string. + +A GraphQL schema may describe that a field represents list of another types; +the `List` type is provided for this reason, and wraps another type. + +Similarly, the `Non-Null` type wraps another type, and denotes that the +resulting value will never be {null} (and that an error cannot result in a +{null} value). +These two types are referred to as "wrapping types"; non-wrapping types are +referred to as "named types". A wrapping type has an underlying named type, +found by continually unwrapping the type until a named type is found. -### Scalars -As expected by the name, a scalar represents a primitive value in GraphQL. -GraphQL responses take the form of a hierarchical tree; the leaves on these trees -are GraphQL scalars. +### Type Extensions + +TypeExtension : + - ScalarTypeExtension + - ObjectTypeExtension + - InterfaceTypeExtension + - UnionTypeExtension + - EnumTypeExtension + - InputObjectTypeExtension + +Type extensions are used to represent a GraphQL type system which has been +extended from some original type system. For example, this might be used by a +local service to represent data a GraphQL client only accesses locally, or by a +GraphQL service which is itself an extension of another GraphQL service. + + +## Scalars + +ScalarTypeDefinition : Description? scalar Name Directives[Const]? + +Scalar types represent primitive leaf values in a GraphQL type system. GraphQL +responses take the form of a hierarchical tree; the leaves on these trees are +GraphQL scalars. All GraphQL scalars are representable as strings, though depending on the response format being used, there may be a more appropriate primitive for the @@ -84,12 +288,21 @@ client-specific primitive for time. Another example of a potentially useful custom scalar is `Url`, which serializes as a string, but is guaranteed by the server to be a valid URL. +```graphql example +scalar Time +scalar Url +``` + A server may omit any of the built-in scalars from its schema, for example if a -schema does not refer to a floating-point number, then it will not include the +schema does not refer to a floating-point number, then it must not include the `Float` type. However, if a schema includes a type with the name of one of the types described here, it must adhere to the behavior described. As an example, a server must not include a type called `Int` and use it to represent -128-bit numbers, or internationalization information. +128-bit numbers, internationalization information, or anything other than what +is defined in this document. + +When representing a GraphQL schema using the type system definition language, +the built-in scalar types should be omitted for brevity. **Result Coercion** @@ -136,7 +349,7 @@ should support all of these types, and a GraphQL server which provide a type by these names must adhere to the behavior described below. -#### Int +### Int The Int scalar type represents a signed 32-bit numeric non-fractional value. Response formats that support a 32-bit integer or a number type should use @@ -161,7 +374,7 @@ custom-defined Scalar type, as not all platforms and transports support encoding integer numbers larger than 32-bit. -#### Float +### Float The Float scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point). @@ -184,7 +397,7 @@ error indicating an incorrect type. If the integer input value represents a value not representable by IEEE 754, a query error should be raised. -#### String +### String The String scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form @@ -205,7 +418,7 @@ accepted. All other input values must raise a query error indicating an incorrect type. -#### Boolean +### Boolean The Boolean scalar type represents `true` or `false`. Response formats should use a built-in boolean type if supported; otherwise, they should use their @@ -223,7 +436,7 @@ When expected as an input type, only boolean input values are accepted. All other input values must raise a query error indicating an incorrect type. -#### ID +### ID The ID scalar type represents a unique identifier, often used to refetch an object or as the key for a cache. The ID type is serialized in the same way as @@ -248,7 +461,34 @@ a given GraphQL server expects. Any other input value, including float input values (such as `4.0`), must raise a query error indicating an incorrect type. -### Objects +### Scalar Extensions + +ScalarTypeExtension : + - extend scalar Name Directives[Const] + +Scalar type extensions are used to represent a scalar type which has been +extended from some original scalar type. For example, this might be used by a +GraphQL tool or service which adds directives to an existing scalar. + +**Type Validation** + +Scalar type extensions have the potential to be invalid if incorrectly defined. + +1. The named type must already be defined and must be a Scalar type. +2. Any directives provided must not already apply to the original Scalar type. + + +## Objects + +ObjectTypeDefinition : Description? type Name ImplementsInterfaces? Directives[Const]? FieldsDefinition? + +ImplementsInterfaces : + - implements `&`? NamedType + - ImplementsInterfaces & NamedType + +FieldsDefinition : { FieldDefinition+ } + +FieldDefinition : Description? Name ArgumentsDefinition? : Type Directives[Const]? GraphQL queries are hierarchical and composed, describing a tree of information. While Scalar types describe the leaf values of these hierarchical queries, Objects @@ -477,8 +717,48 @@ executor, so this is covered in that section of the spec. Objects are never valid inputs. +**Type Validation** -#### Object Field Arguments +Object types have the potential to be invalid if incorrectly defined. This set +of rules must be adhered to by every Object type in a GraphQL schema. + +1. An Object type must define one or more fields. +2. The fields of an Object type must have unique names within that Object type; + no two fields may share the same name. +3. Each field of an Object type must not have a name which begins with the + characters {"__"} (two underscores). +4. An object type may declare that it implements one or more unique interfaces. +5. An object type must be a super-set of all interfaces it implements: + 1. The object type must include a field of the same name for every field + defined in an interface. + 1. The object field must be of a type which is equal to or a sub-type of + the interface field (covariant). + 1. An object field type is a valid sub-type if it is equal to (the same + type as) the interface field type. + 2. An object field type is a valid sub-type if it is an Object type and + the interface field type is either an Interface type or a Union type + and the object field type is a possible type of the interface field + type. + 3. An object field type is a valid sub-type if it is a List type and + the interface field type is also a List type and the list-item type + of the object field type is a valid sub-type of the list-item type + of the interface field type. + 4. An object field type is a valid sub-type if it is a Non-Null variant + of a valid sub-type of the interface field type. + 2. The object field must include an argument of the same name for every + argument defined in the interface field. + 1. The object field argument must accept the same type (invariant) as + the interface field argument. + 3. The object field may include additional arguments not defined in the + interface field, but any additional argument must not be required, e.g. + must not be of a non-nullable type. + + +### Field Arguments + +ArgumentsDefinition : ( InputValueDefinition+ ) + +InputValueDefinition : Description? Name : Type DefaultValue? Directives[Const]? Object fields are conceptually functions which yield values. Occasionally object fields can accept arguments to further specify the return value. Object field @@ -523,76 +803,103 @@ May yield the result: The type of an object field argument can be any Input type. -#### Object Field deprecation +### Field Deprecation Fields in an object may be marked as deprecated as deemed necessary by the application. It is still legal to query for these fields (to ensure existing clients are not broken by the change), but the fields should be appropriately treated in documentation and tooling. +When using the type system definition language, `@deprecated` directives are +used to indicate that a field is deprecated: -#### Object type validation +```graphql example +type ExampleType { + oldField: String @deprecated +} +``` -Object types have the potential to be invalid if incorrectly defined. This set -of rules must be adhered to by every Object type in a GraphQL schema. -1. An Object type must define one or more fields. -2. The fields of an Object type must have unique names within that Object type; - no two fields may share the same name. -3. Each field of an Object type must not have a name which begins with the - characters {"__"} (two underscores). -4. An object type may declare that it implements one or more unique interfaces. -5. An object type must be a super-set of all interfaces it implements: - 1. The object type must include a field of the same name for every field - defined in an interface. - 1. The object field must be of a type which is equal to or a sub-type of - the interface field (covariant). - 1. An object field type is a valid sub-type if it is equal to (the same - type as) the interface field type. - 2. An object field type is a valid sub-type if it is an Object type and - the interface field type is either an Interface type or a Union type - and the object field type is a possible type of the interface field - type. - 3. An object field type is a valid sub-type if it is a List type and - the interface field type is also a List type and the list-item type - of the object field type is a valid sub-type of the list-item type - of the interface field type. - 4. An object field type is a valid sub-type if it is a Non-Null variant - of a valid sub-type of the interface field type. - 2. The object field must include an argument of the same name for every - argument defined in the interface field. - 1. The object field argument must accept the same type (invariant) as - the interface field argument. - 3. The object field may include additional arguments not defined in the - interface field, but any additional argument must not be required, e.g. - must not be of a non-nullable type. +### Object Extensions +ObjectTypeExtension : + - extend type Name ImplementsInterfaces? Directives[Const]? FieldsDefinition + - extend type Name ImplementsInterfaces? Directives[Const] + - extend type Name ImplementsInterfaces -### Interfaces +Object type extensions are used to represent a type which has been extended from +some original type. For example, this might be used to represent local data, or +by a GraphQL service which is itself an extension of another GraphQL service. -GraphQL Interfaces represent a list of named fields and their arguments. GraphQL -objects can then implement an interface, which guarantees that they will -contain the specified fields. +In this example, a local data field is added to a `Story` type: + +```graphql example +extend type Story { + isHiddenLocally: Boolean +} +``` + +Object type extensions may choose not to add additional fields, instead only +adding interfaces or directives. + +In this example, a directive is added to a `User` type without adding fields: + +```graphql example +extend type User @addedDirective +``` + +**Type Validation** + +Object type extensions have the potential to be invalid if incorrectly defined. + +1. The named type must already be defined and must be an Object type. +2. The fields of an Object type extension must have unique names; no two fields + may share the same name. +3. Any fields of an Object type extension must not be already defined on the + original Object type. +4. Any directives provided must not already apply to the original Object type. +5. Any interfaces provided must not be already implemented by the original + Object type. +6. The resulting extended object type must be a super-set of all interfaces it + implements. + + +## Interfaces + +InterfaceTypeDefinition : Description? interface Name Directives[Const]? FieldsDefinition? + +GraphQL interfaces represent a list of named fields and their arguments. GraphQL +objects can then implement these interfaces which requires that the object type +will define all fields defined by those interfaces. Fields on a GraphQL interface have the same rules as fields on a GraphQL object; their type can be Scalar, Object, Enum, Interface, or Union, or any wrapping type whose base type is one of those five. -For example, an interface may describe a required field and types such as -`Person` or `Business` may then implement this interface. +For example, an interface `NamedEntity` may describe a required field and types +such as `Person` or `Business` may then implement this interface to guarantee +this field will always exist. + +Types may also implement multiple interfaces. For example, `Business` implements +both the `NamedEntity` and `ValuedEntity` interfaces in the example below. ```graphql example interface NamedEntity { name: String } +interface ValuedEntity { + value: Int +} + type Person implements NamedEntity { name: String age: Int } -type Business implements NamedEntity { +type Business implements NamedEntity & ValuedEntity { name: String + value: Int employeeCount: Int } ``` @@ -663,8 +970,7 @@ is the same as the result coercion of the object. Interfaces are never valid inputs. - -#### Interface type validation +**Type Validation** Interface types have the potential to be invalid if incorrectly defined. @@ -675,7 +981,66 @@ Interface types have the potential to be invalid if incorrectly defined. characters {"__"} (two underscores). -### Unions +### Interface Extensions + +InterfaceTypeExtension : + - extend interface Name Directives[Const]? FieldsDefinition + - extend interface Name Directives[Const] + +Interface type extensions are used to represent an interface which has been +extended from some original interface. For example, this might be used to +represent common local data on many types, or by a GraphQL service which is +itself an extension of another GraphQL service. + +In this example, an extended data field is added to a `NamedEntity` type along +with the types which implement it: + +```graphql example +extend interface NamedEntity { + nickname: String +} + +extend type Person { + nickname: String +} + +extend type Business { + nickname: String +} +``` + +Interface type extensions may choose not to add additional fields, instead only +adding directives. + +In this example, a directive is added to a `NamedEntity` type without +adding fields: + +```graphql example +extend interface NamedEntity @addedDirective +``` + +**Type Validation** + +Interface type extensions have the potential to be invalid if incorrectly defined. + +1. The named type must already be defined and must be an Interface type. +2. The fields of an Interface type extension must have unique names; no two + fields may share the same name. +3. Any fields of an Interface type extension must not be already defined on the + original Interface type. +4. Any Object type which implemented the original Interface type must also be a + super-set of the fields of the Interface type extension (which may be due to + Object type extension). +5. Any directives provided must not already apply to the original Interface type. + + +## Unions + +UnionTypeDefinition : Description? union Name Directives[Const]? UnionMemberTypes? + +UnionMemberTypes : + - = `|`? NamedType + - UnionMemberTypes | NamedType GraphQL Unions represent an object that could be one of a list of GraphQL Object types, but provides for no guaranteed fields between those types. @@ -686,9 +1051,9 @@ With interfaces and objects, only those fields defined on the type can be queried directly; to query other fields on an interface, typed fragments must be used. This is the same as for unions, but unions do not define any fields, so **no** fields may be queried on this type without the use of -typed fragments. +type refining fragments or inline fragments. -For example, we might have the following type system: +For example, we might define the following types: ```graphql example union SearchResult = Photo | Person @@ -738,6 +1103,15 @@ Instead, the query would be: } ``` +Union members may be defined with an optional leading `|` character to aid +formatting when representing a longer list of possible types: + +```graphql example +union SearchResult = + | Photo + | Person +``` + **Result Coercion** The union type should have some way of determining which object a given result @@ -748,23 +1122,64 @@ same as the result coercion of the object. Unions are never valid inputs. - -#### Union type validation +**Type Validation** Union types have the potential to be invalid if incorrectly defined. 1. The member types of a Union type must all be Object base types; - Scalar, Interface and Union types may not be member types of a Union. - Similarly, wrapping types may not be member types of a Union. + Scalar, Interface and Union types must not be member types of a Union. + Similarly, wrapping types must not be member types of a Union. 2. A Union type must define one or more unique member types. -### Enums -GraphQL Enums are a variant on the Scalar type, which represents one of a -finite set of possible values. +### Union Extensions + +UnionTypeExtension : + - extend union Name Directives[Const]? UnionMemberTypes + - extend union Name Directives[Const] + +Union type extensions are used to represent a union type which has been +extended from some original union type. For example, this might be used to +represent additional local data, or by a GraphQL service which is itself an +extension of another GraphQL service. + +**Type Validation** + +Union type extensions have the potential to be invalid if incorrectly defined. + +1. The named type must already be defined and must be a Union type. +2. The member types of a Union type extension must all be Object base types; + Scalar, Interface and Union types must not be member types of a Union. + Similarly, wrapping types must not be member types of a Union. +3. All member types of a Union type extension must be unique. +4. All member types of a Union type extension must not already be a member of + the original Union type. +5. Any directives provided must not already apply to the original Union type. + +## Enums + +EnumTypeDefinition : Description? enum Name Directives[Const]? EnumValuesDefinition? -GraphQL Enums are not references for a numeric value, but are unique values in -their own right. They serialize as a string: the name of the represented value. +EnumValuesDefinition : { EnumValueDefinition+ } + +EnumValueDefinition : Description? EnumValue Directives[Const]? + +GraphQL Enum types, like scalar types, also represent leaf values in a GraphQL +type system. However Enum types describe the set of possible values. + +Enums are not references for a numeric value, but are unique values in their own +right. They may serialize as a string: the name of the represented value. + +In this example, an Enum type called `Direction` is defined: + +```graphql example +enum Direction { + NORTH + EAST + SOUTH + WEST +} +``` **Result Coercion** @@ -782,26 +1197,67 @@ should only allow such values as enum input values. Otherwise, for most transport serializations that do not, strings may be interpreted as the enum input value with the same name. +**Type Validation** + +Enum types have the potential to be invalid if incorrectly defined. + +1. An Enum type must define one or more unique enum values. + + +### Enum Extensions + +EnumTypeExtension : + - extend enum Name Directives[Const]? EnumValuesDefinition + - extend enum Name Directives[Const] + +Enum type extensions are used to represent an enum type which has been +extended from some original enum type. For example, this might be used to +represent additional local data, or by a GraphQL service which is itself an +extension of another GraphQL service. + +**Type Validation** + +Enum type extensions have the potential to be invalid if incorrectly defined. + +1. The named type must already be defined and must be an Enum type. +2. All values of an Enum type extension must be unique. +3. All values of an Enum type extension must not already be a value of + the original Enum. +4. Any directives provided must not already apply to the original Enum type. + + +## Input Objects -### Input Objects +InputObjectTypeDefinition : Description? input Name Directives[Const]? InputFieldsDefinition? -Fields can define arguments that the client passes up with the query, -to configure their behavior. These inputs can be Strings or Enums, but -they sometimes need to be more complex than this. +InputFieldsDefinition : { InputValueDefinition+ } -The `Object` type defined above is inappropriate for re-use here, because -`Object`s can contain fields that express circular references or references -to interfaces and unions, neither of which is appropriate for use as an -input argument. For this reason, input objects have a separate type in the -system. +Fields may accept arguments to configure their behavior. These inputs are often +scalars or enums, but they sometimes need to represent more complex values. -An `Input Object` defines a set of input fields; the input fields are either +A GraphQL Input Object defines a set of input fields; the input fields are either scalars, enums, or other input objects. This allows arguments to accept arbitrarily complex structs. +In this example, an Input Object called `Point2D` describes `x` and `y` inputs: + +```graphql example +input Point2D { + x: Float + y: Float +} +``` + +Note: The GraphQL Object type ({ObjectTypeDefinition}) defined above is +inappropriate for re-use here, because Object types can contain fields that +define arguments or contain references to interfaces and unions, neither of +which is appropriate for use as an input argument. For this reason, input +objects have a separate type in the system. + **Result Coercion** -An input object is never a valid result. +An input object is never a valid result. Input Object types cannot be the return +type of an Object or Interface field. **Input Coercion** @@ -855,7 +1311,7 @@ Literal Value | Variables | Coerced Value `{ b: $var }` | `{ var: null }` | Error: {b} must be non-null. `{ b: 123, c: "xyz" }` | `{}` | Error: Unexpected field {c} -#### Input Object type validation +**Type Validation** 1. An Input Object type must define one or more fields. 2. The fields of an Input Object type must have unique names within that @@ -863,7 +1319,28 @@ Literal Value | Variables | Coerced Value 3. The return types of each defined field must be an Input type. -### Lists +### Input Object Extensions + +InputObjectTypeExtension : + - extend input Name Directives[Const]? InputFieldsDefinition + - extend input Name Directives[Const] + +Input object type extensions are used to represent an input object type which +has been extended from some original input object type. For example, this might +be used by a GraphQL service which is itself an extension of another GraphQL service. + +**Type Validation** + +Input object type extensions have the potential to be invalid if incorrectly defined. + +1. The named type must already be defined and must be a Input Object type. +3. All fields of an Input Object type extension must have unique names. +4. All fields of an Input Object type extension must not already be a field of + the original Input Object. +5. Any directives provided must not already apply to the original Input Object type. + + +## List A GraphQL list is a special collection type which declares the type of each item in the List (referred to as the *item type* of the list). List values are @@ -897,7 +1374,7 @@ list type, the value is interpreted as no list being provided, and not a list of size one with the value {null}. -### Non-Null +## Non-Null By default, all types in GraphQL are nullable; the {null} value is a valid response for all of the above types. To declare a type that disallows null, @@ -926,6 +1403,10 @@ should be performed. If that result was not {null}, then the result of coercing the Non-Null type is that result. If that result was {null}, then a field error must be raised. +Note: When a field error is raised on a non-null value, the error propogates to +the parent field. For more information on this process, see +"Errors and Non-Nullability" within the Execution section. + **Input Coercion** If an argument or input-object field of a Non-Null type is not provided, is @@ -934,7 +1415,8 @@ either not provided a value at runtime, or was provided the value {null}, then a query error must be raised. If the value provided to the Non-Null type is provided with a literal value -other than {null}, or a Non-Null variable value, it is coerced using the input coercion for the wrapped type. +other than {null}, or a Non-Null variable value, it is coerced using the input +coercion for the wrapped type. Example: A non-null argument cannot be omitted. @@ -963,21 +1445,113 @@ query withNullableVariable($var: String) { Note: The Validation section defines providing a nullable variable type to a non-null input type as invalid. -**Non-Null type validation** +**Type Validation** 1. A Non-Null type must not wrap another Non-Null type. ## Directives -A GraphQL schema includes a list of the directives the execution -engine supports. +DirectiveDefinition : Description? directive @ Name ArgumentsDefinition? on DirectiveLocations + +DirectiveLocations : + - `|`? DirectiveLocation + - DirectiveLocations | DirectiveLocation + +DirectiveLocation : + - ExecutableDirectiveLocation + - TypeSystemDirectiveLocation + +ExecutableDirectiveLocation : one of + `QUERY` + `MUTATION` + `SUBSCRIPTION` + `FIELD` + `FRAGMENT_DEFINITION` + `FRAGMENT_SPREAD` + `INLINE_FRAGMENT` + +TypeSystemDirectiveLocation : one of + `SCHEMA` + `SCALAR` + `OBJECT` + `FIELD_DEFINITION` + `ARGUMENT_DEFINITION` + `INTERFACE` + `UNION` + `ENUM` + `ENUM_VALUE` + `INPUT_OBJECT` + `INPUT_FIELD_DEFINITION` + +A GraphQL schema describes directives which are used to annotate various parts +of a GraphQL document as an indicator that they should be evaluated differently +by a validator, executor, or client tool such as a code generator. GraphQL implementations should provide the `@skip` and `@include` directives. +GraphQL implementations that support the type system definition language must +provide the `@deprecated` directive if representing deprecated portions of +the schema. + +Directives must only be used in the locations they are declared to belong in. +In this example, a directive is defined which can be used to annotate a +fragment definition: + +```graphql example +directive @example on FIELD + +fragment SomeFragment on SomeType { + field @example +} +``` + +Directive locations may be defined with an optional leading `|` character to aid +formatting when representing a longer list of possible locations: + +```graphql example +directive @example on + | FIELD + | FRAGMENT_SPREAD + | INLINE_FRAGMENT +``` + +Directives can also be used to annotate the type system definition language +as well, which can be a useful tool for supplying additional metadata in order +to generate GraphQL execution services, produce client generated runtime code, +or many other useful extensions of the GraphQL semantics. + +In this example, the directive `@example` annotates field and argument definitions: + +```graphql example +directive @example on FIELD_DEFINITION | ARGUMENT_DEFINITION + +type SomeType { + field(arg: Int @example): String @example +} +``` + +While defining a directive, it must not reference itself directly or indirectly: + +```graphql counter-example +directive @invalidExample(arg: String @invalidExample) on ARGUMENT_DEFINITION +``` + +**Validation** + +1. A directive definition must not contain the use of a directive which + references itself directly. +2. A directive definition must not contain the use of a directive which + references itself indirectly by referencing a Type or Directive which + transitively includes a reference to this directive. + ### @skip +```graphql +directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT +``` + The `@skip` directive may be provided for fields, fragment spreads, and inline fragments, and allows for conditional exclusion during execution as described by the if argument. @@ -994,6 +1568,10 @@ query myQuery($someTest: Boolean) { ### @include +```graphql +directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT +``` + The `@include` directive may be provided for fields, fragment spreads, and inline fragments, and allows for conditional inclusion during execution as described by the if argument. @@ -1015,48 +1593,27 @@ must *not* be queried if either the `@skip` condition is true *or* the `@include` condition is false. -## Initial types - -A GraphQL schema includes types, indicating where query, mutation, and -subscription operations start. This provides the initial entry points into the -type system. The query type must always be provided, and is an Object -base type. The mutation type is optional; if it is not provided, that means -the system does not support mutations. If it is provided, it must -be an object base type. Similarly, the subscription type is optional; if it is -not provided, the system does not support subscriptions. If it is provided, it -must be an object base type. +### @deprecated -The fields on the query type indicate what fields are available at -the top level of a GraphQL query. For example, a basic GraphQL query -like this one: - -```graphql example -query getMe { - me -} +```graphql +directive @deprecated( + reason: String = "No longer supported" +) on FIELD_DEFINITION | ENUM_VALUE ``` -Is valid when the type provided for the query starting type has a field -named "me". Similarly +The `@deprecated` directive is used within the type system definition language +to indicate deprecated portions of a GraphQL service's schema, such as +deprecated fields on a type or deprecated enum values. -```graphql example -mutation setName { - setName(name: "Zuck") { - newName - } -} -``` +Deprecations include a reason for why it is deprecated, which is formatted using +Markdown syntax (as specified by [CommonMark](http://commonmark.org/)). -Is valid when the type provided for the mutation starting type is not null, -and has a field named "setName" with a string argument named "name". +In this example type definition, `oldField` is deprecated in favor of +using `newField`. ```graphql example -subscription { - newMessage { - text - } +type ExampleType { + newField: String + oldField: String @deprecated(reason: "Use `newField`.") } ``` - -Is valid when the type provided for the subscription starting type is not null, -and has a field named "newMessage" and only contains a single root field. diff --git a/spec/Section 4 -- Introspection.md b/spec/Section 4 -- Introspection.md index 837ed3c8b..4d60626b7 100644 --- a/spec/Section 4 -- Introspection.md +++ b/spec/Section 4 -- Introspection.md @@ -201,6 +201,17 @@ enum __DirectiveLocation { FRAGMENT_DEFINITION FRAGMENT_SPREAD INLINE_FRAGMENT + SCHEMA + SCALAR + OBJECT + FIELD_DEFINITION + ARGUMENT_DEFINITION + INTERFACE + UNION + ENUM + ENUM_VALUE + INPUT_OBJECT + INPUT_FIELD_DEFINITION } ``` diff --git a/spec/Section 5 -- Validation.md b/spec/Section 5 -- Validation.md index 429a06352..e77e650dc 100644 --- a/spec/Section 5 -- Validation.md +++ b/spec/Section 5 -- Validation.md @@ -5,9 +5,9 @@ ensures that it is unambiguous and mistake-free in the context of a given GraphQL schema. An invalid request is still technically executable, and will always produce a -stable result as defined by the procedures in the Execution section, however -that result may be ambiguous, surprising, or unexpected relative to the request -containing validation errors, so execution should not occur for invalid requests. +stable result as defined by the algorithms in the Execution section, however +that result may be ambiguous, surprising, or unexpected relative to a request +containing validation errors, so execution should only occur for valid requests. Typically validation is performed in the context of a request immediately before execution, however a GraphQL service may execute a request without @@ -36,6 +36,10 @@ For this section of this schema, we will assume the following type system in order to demonstrate examples: ```graphql example +type Query { + dog: Dog +} + enum DogCommand { SIT, DOWN, HEEL } type Dog implements Pet { @@ -76,12 +80,46 @@ type Cat implements Pet { union CatOrDog = Cat | Dog union DogOrHuman = Dog | Human union HumanOrAlien = Human | Alien +``` -type QueryRoot { - dog: Dog + +## Documents + +### Executable Definitions + +**Formal Specification** + + * For each definition {definition} in the document. + * {definition} must be {OperationDefinition} or {FragmentDefinition} (it must + not be {TypeSystemDefinition}). + +**Explanatory Text** + +GraphQL execution will only consider the executable definitions Operation and +Fragment. Type system definitions and extensions are not executable, and are not +considered during execution. + +To avoid ambiguity, a document containing {TypeSystemDefinition} is invalid +for execution. + +GraphQL documents not intended to be directly executed may include +{TypeSystemDefinition}. + +For example, the following document is invalid for execution since the original +executing schema may not know about the provided type extension: + +```graphql counter-example +query getDogName { + dog { + name + color + } } -``` +extend type Dog { + color: String +} +``` ## Operations @@ -91,7 +129,7 @@ type QueryRoot { **Formal Specification** - * For each operation definition {operation} in the document + * For each operation definition {operation} in the document. * Let {operationName} be the name of {operation}. * If {operationName} exists * Let {operations} be all operation definitions in the document named {operationName}. @@ -555,7 +593,7 @@ and unions without subfields are disallowed. Let's assume the following additions to the query root type of the schema: ```graphql example -extend type QueryRoot { +extend type Query { human: Human pet: Pet catOrDog: CatOrDog @@ -640,7 +678,7 @@ type Arguments { booleanListArgField(booleanListArg: [Boolean]!): [Boolean] } -extend type QueryRoot { +extend type Query { arguments: Arguments } ``` @@ -898,9 +936,9 @@ fragment inlineFragOnScalar on Dog { **Explanatory Text** -Defined fragments must be used within a query document. +Defined fragments must be used within a document. -For example the following is an invalid query document: +For example the following is an invalid document: ```graphql counter-example fragment nameFragment on Dog { # unused @@ -1516,7 +1554,7 @@ For these examples, consider the following typesystem additions: ```graphql example input ComplexInput { name: String, owner: String } -extend type QueryRoot { +extend type Query { findDog(complex: ComplexInput): Dog booleanList(booleanListArg: [Boolean!]): Boolean } diff --git a/spec/Section 6 -- Execution.md b/spec/Section 6 -- Execution.md index bdfcf4193..7ae8706a3 100644 --- a/spec/Section 6 -- Execution.md +++ b/spec/Section 6 -- Execution.md @@ -5,7 +5,7 @@ GraphQL generates a response from a request via execution. A request for execution consists of a few pieces of information: * The schema to use, typically solely provided by the GraphQL service. -* A Document containing GraphQL Operations and Fragments to execute. +* A {Document} which must contain GraphQL {OperationDefinition} and may contain {FragmentDefinition}. * Optionally: The name of the Operation in the Document to execute. * Optionally: Values for any Variables defined by the Operation. * An initial value corresponding to the root type being executed. @@ -19,12 +19,11 @@ to be formatted according to the Response section below. ## Executing Requests -To execute a request, the executor must have a parsed `Document` (as defined -in the “Query Language” part of this spec) and a selected operation name to -run if the document defines multiple operations, otherwise the document is -expected to only contain a single operation. The result of the request is -determined by the result of executing this operation according to the "Executing -Operations” section below. +To execute a request, the executor must have a parsed {Document} and a selected +operation name to run if the document defines multiple operations, otherwise the +document is expected to only contain a single operation. The result of the +request is determined by the result of executing this operation according to the +"Executing Operations” section below. ExecuteRequest(schema, document, operationName, variableValues, initialValue):