From 1d8a1dd5360a38ce02079d3d4b1771002f0f3b5d Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Tue, 1 Sep 2015 19:10:18 -0700 Subject: [PATCH 01/28] [RFC] GraphQL IDL additions This adds the type definition syntax to the GraphQL specification. --- spec/Appendix B -- Grammar Summary.md | 57 +++++- spec/Section 2 -- Language.md | 277 ++++++++++++++++++++++++-- spec/Section 5 -- Validation.md | 4 +- 3 files changed, 317 insertions(+), 21 deletions(-) diff --git a/spec/Appendix B -- Grammar Summary.md b/spec/Appendix B -- Grammar Summary.md index 918282358..ee4124718 100644 --- a/spec/Appendix B -- Grammar Summary.md +++ b/spec/Appendix B -- Grammar Summary.md @@ -89,13 +89,14 @@ Note: Block string values are interpreted to exclude blank initial and trailing lines and uniform indentation with {BlockStringValue()}. -## Query Document +## Document Document : Definition+ Definition : - OperationDefinition - FragmentDefinition + - TypeSystemDefinition OperationDefinition : - SelectionSet @@ -179,3 +180,57 @@ NonNullType : Directives : Directive+ Directive : @ Name Arguments? + +TypeSystemDefinition : + - SchemaDefinition + - TypeDefinition + - TypeExtensionDefinition + - DirectiveDefinition + +SchemaDefinition : schema { OperationTypeDefinition+ } + +OperationTypeDefinition : OperationType : NamedType + +TypeDefinition : + - ScalarTypeDefinition + - ObjectTypeDefinition + - InterfaceTypeDefinition + - UnionTypeDefinition + - EnumTypeDefinition + - InputObjectTypeDefinition + +ScalarTypeDefinition : scalar Name + +ObjectTypeDefinition : type Name ImplementsInterfaces? { FieldDefinition+ } + +ImplementsInterfaces : implements NamedType+ + +FieldDefinition : Name ArgumentsDefinition? : Type + +ArgumentsDefinition : ( InputValueDefinition+ ) + +InputValueDefinition : Name : Type DefaultValue? + +InterfaceTypeDefinition : interface Name { FieldDefinition+ } + +UnionTypeDefinition : union Name = UnionMembers + +UnionMembers : + - NamedType + - UnionMembers | NamedType + +EnumTypeDefinition : enum Name { EnumValueDefinition+ } + +EnumValueDefinition : EnumValue + +EnumValue : Name + +InputObjectTypeDefinition : input Name { InputValueDefinition+ } + +TypeExtensionDefinition : extend ObjectTypeDefinition + +DirectiveDefinition : directive @ Name ArgumentsDefinition? on DirectiveLocations + +DirectiveLocations : + - Name + - DirectiveLocations | Name diff --git a/spec/Section 2 -- Language.md b/spec/Section 2 -- Language.md index 36a1bd153..8c9039000 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,7 +152,7 @@ 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, +GraphQL Documents are full of named things: operations, fields, arguments, directives, fragments, and variables. All names must follow the same grammatical form. @@ -164,28 +164,33 @@ 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 : - OperationDefinition - FragmentDefinition + - TypeSystemDefinition -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 tool. A document contains multiple definitions of +Operations and Fragments, and if consumed by a client tool may also include Type +Definitions. GraphQL Documents are only executable by a server if they +contain an Operation but do not contain a Type Definition. However documents +which do not contain Operations may still be parsed and validated to allow +client tools to represent a single request across many documents. -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 implementations which only seek to provide GraphQL query execution may +omit the {TypeSystemDefinition} rule from {Definition}. + ## Operations @@ -1078,3 +1083,239 @@ and operations. As future versions of GraphQL adopt new configurable execution capabilities, they may be exposed via directives. + + +## Type System Definition + +TypeSystemDefinition : + - SchemaDefinition + - TypeDefinition + - TypeExtensionDefinition + - DirectiveDefinition + +The GraphQL language also includes an +[IDL](https://en.wikipedia.org/wiki/Interface_description_language) used to +describe a GraphQL service's Type System. Tools may use these definitions to +provide various utilities such as client code generation or +service boot-strapping. + +GraphQL services which only seek to provide GraphQL query execution may +choose to not 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: This IDL is used throughout the remainder of this specification document +when illustrating example type systems. + + +### Schema Definition + +SchemaDefinition : schema { OperationTypeDefinition+ } + +OperationTypeDefinition : OperationType : NamedType + +A GraphQL Type System includes exactly one Schema Definition, which defines +the type to be used for each operation. + +In this example, a GraphQL schema is defined with both query and mutation types: + +```graphql +schema { + query: QueryRoot + mutation: MutationRoot +} + +type QueryRoot { + someField: String +} + +type MutationRoot { + setSomeField(to: String): String +} +``` + + +### Type Definition + +TypeDefinition : + - ScalarTypeDefinition + - ObjectTypeDefinition + - InterfaceTypeDefinition + - UnionTypeDefinition + - EnumTypeDefinition + - InputObjectTypeDefinition + +A GraphQL Type System is defined by many different kinds of types. + + +#### Scalar + +ScalarTypeDefinition : scalar Name + +Scalar types represent leaf values in a GraphQL type system. While this GraphQL +specification describes a set of Scalar types which all GraphQL services must +supply, custom Scalar types may be supplied by a GraphQL service. Typically, the +set of Scalar types described in this specification are omitted from documents +which describe a schema for brevity. + +In this example, a Scalar type called `DateTime` is defined: + +```graphql +scalar DateTime +``` + + +#### Object + +ObjectTypeDefinition : type Name ImplementsInterfaces? { FieldDefinition+ } + +ImplementsInterfaces : implements NamedType+ + +FieldDefinition : Name ArgumentsDefinition? : Type + +ArgumentsDefinition : ( InputValueDefinition+ ) + +InputValueDefinition : Name : Type DefaultValue? + +Object types represent a list of named fields, each of which yield a value of a +specific type. Each field itself may accept a list of named arguments. + +Objects may implement Interface types. When implementing an Interface type, the +Object type must supply all fields defined by the Interface. + +In this example, a Object type called `TodoItem` is defined: + +```graphql +type TodoItem implements Node { + id: ID + title: String + isCompleted: Boolean +} +``` + +#### Interface + +InterfaceTypeDefinition : interface Name { FieldDefinition+ } + +Interface types, similarly to Object types represent a list of named fields. +Interface types are used as the type of a field when one of many possible Object +types may yielded during execution, but some fields are guaranteed. An Object +type is a possible type of an Interface when it both declares that it implements +that Interface as well as includes all defined fields. + +In this example, an Interface type called `Node` is defined: + +```graphql +interface Node { + id: ID +} +``` + +#### Union + +UnionTypeDefinition : union Name = UnionMembers + +UnionMembers : + - NamedType + - UnionMembers | NamedType + +Union types represent a list of named Object types. Union types are used as the +type of a field when one of many possible Object types may yielded during +execution, and no fields are guaranteed. An Object type is a possible type of a +Union when it is declared by the Union. + +In this example, a Union type called `Actor` is defined: + +```graphql +union Actor = User | Business +``` + + +#### Enum + +EnumTypeDefinition : enum Name { EnumValueDefinition+ } + +EnumValueDefinition : EnumValue + +EnumValue : Name + +Enum types, like Scalar types, also represent leaf values in a GraphQL type +system. However Enum types describe the set of legal values. + +In this example, an Enum type called `Direction` is defined: + +```graphql +enum Direction { + NORTH + EAST + SOUTH + WEST +} +``` + +#### Input Object + +InputObjectTypeDefinition : input Name { InputValueDefinition+ } + +Input Object types represent complex input values which may be provided as an +field argument. Input Object types cannot be the return type of an Object or +Interface field. + +In this example, an Input Object called `Point2D` is defined: + +```graphql +input Point2D { + x: Float + y: Float +} +``` + +### Type Extension + +TypeExtensionDefinition : extend ObjectTypeDefinition + +Type extensions may be used by client-side tools in order to represent a +GraphQL type system which has been extended from the type system exposed via +introspection by a GraphQL service, for example to represent fields which a +client of GraphQL uses locally, but is not provided by a GraphQL service. + +Any fields or interfaces provided by the extension must not already exist on the +Object type. + +In this example, a client only field is added to a `Story` type: + +```graphql +extend type Story { + isHiddenLocally: Boolean +} +``` + +### Directive Definition + +DirectiveDefinition : directive @ Name ArgumentsDefinition? on DirectiveLocations + +DirectiveLocations : + - Name + - DirectiveLocations | Name + +A GraphQL Type System often also includes directives which may be used to +annotate various nodes in a GraphQL document as an indicator that they should be +evaluated differently by a validator, executor, or client tool such as a +code generator. + +Since the validation of a GraphQL document includes ensuring that any directives +used are defined and used correctly, defining a directive allows for a validator +to be aware of all possible validation rules. + +In this example, a directive is defined which can be used to annotate a +fragment definition: + +``` +directive @someAnnotation on FRAGMENT_DEFINITION + +fragment SomeFragment on SomeType @someAnnotation { + someField +} +``` diff --git a/spec/Section 5 -- Validation.md b/spec/Section 5 -- Validation.md index 429a06352..b23051d72 100644 --- a/spec/Section 5 -- Validation.md +++ b/spec/Section 5 -- Validation.md @@ -898,9 +898,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 From 7401ededa34f663ff448367fb8d999eb0799dbd6 Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Wed, 19 Oct 2016 10:34:26 -0700 Subject: [PATCH 02/28] Add directives to all schema definition forms --- spec/Appendix B -- Grammar Summary.md | 20 ++++++++++---------- spec/Section 2 -- Language.md | 16 ++++++++-------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/spec/Appendix B -- Grammar Summary.md b/spec/Appendix B -- Grammar Summary.md index ee4124718..a8bb798a1 100644 --- a/spec/Appendix B -- Grammar Summary.md +++ b/spec/Appendix B -- Grammar Summary.md @@ -187,7 +187,7 @@ TypeSystemDefinition : - TypeExtensionDefinition - DirectiveDefinition -SchemaDefinition : schema { OperationTypeDefinition+ } +SchemaDefinition : schema Directives? { OperationTypeDefinition+ } OperationTypeDefinition : OperationType : NamedType @@ -199,33 +199,33 @@ TypeDefinition : - EnumTypeDefinition - InputObjectTypeDefinition -ScalarTypeDefinition : scalar Name +ScalarTypeDefinition : scalar Name Directives? -ObjectTypeDefinition : type Name ImplementsInterfaces? { FieldDefinition+ } +ObjectTypeDefinition : type Name ImplementsInterfaces? Directives? { FieldDefinition+ } ImplementsInterfaces : implements NamedType+ -FieldDefinition : Name ArgumentsDefinition? : Type +FieldDefinition : Name ArgumentsDefinition? : Type Directives? ArgumentsDefinition : ( InputValueDefinition+ ) -InputValueDefinition : Name : Type DefaultValue? +InputValueDefinition : Name : Type DefaultValue? Directives? -InterfaceTypeDefinition : interface Name { FieldDefinition+ } +InterfaceTypeDefinition : interface Name Directives? { FieldDefinition+ } -UnionTypeDefinition : union Name = UnionMembers +UnionTypeDefinition : union Name Directives? = UnionMembers UnionMembers : - NamedType - UnionMembers | NamedType -EnumTypeDefinition : enum Name { EnumValueDefinition+ } +EnumTypeDefinition : enum Name Directives? { EnumValueDefinition+ } -EnumValueDefinition : EnumValue +EnumValueDefinition : EnumValue Directives? EnumValue : Name -InputObjectTypeDefinition : input Name { InputValueDefinition+ } +InputObjectTypeDefinition : input Name Directives? { InputValueDefinition+ } TypeExtensionDefinition : extend ObjectTypeDefinition diff --git a/spec/Section 2 -- Language.md b/spec/Section 2 -- Language.md index 8c9039000..ec13c9d57 100644 --- a/spec/Section 2 -- Language.md +++ b/spec/Section 2 -- Language.md @@ -1169,15 +1169,15 @@ scalar DateTime #### Object -ObjectTypeDefinition : type Name ImplementsInterfaces? { FieldDefinition+ } +ObjectTypeDefinition : type Name ImplementsInterfaces? Directives? { FieldDefinition+ } ImplementsInterfaces : implements NamedType+ -FieldDefinition : Name ArgumentsDefinition? : Type +FieldDefinition : Name ArgumentsDefinition? : Type Directives? ArgumentsDefinition : ( InputValueDefinition+ ) -InputValueDefinition : Name : Type DefaultValue? +InputValueDefinition : Name : Type DefaultValue? Directives? Object types represent a list of named fields, each of which yield a value of a specific type. Each field itself may accept a list of named arguments. @@ -1197,7 +1197,7 @@ type TodoItem implements Node { #### Interface -InterfaceTypeDefinition : interface Name { FieldDefinition+ } +InterfaceTypeDefinition : interface Name Directives? { FieldDefinition+ } Interface types, similarly to Object types represent a list of named fields. Interface types are used as the type of a field when one of many possible Object @@ -1215,7 +1215,7 @@ interface Node { #### Union -UnionTypeDefinition : union Name = UnionMembers +UnionTypeDefinition : union Name Directives? = UnionMembers UnionMembers : - NamedType @@ -1235,9 +1235,9 @@ union Actor = User | Business #### Enum -EnumTypeDefinition : enum Name { EnumValueDefinition+ } +EnumTypeDefinition : enum Name Directives? { EnumValueDefinition+ } -EnumValueDefinition : EnumValue +EnumValueDefinition : EnumValue Directives? EnumValue : Name @@ -1257,7 +1257,7 @@ enum Direction { #### Input Object -InputObjectTypeDefinition : input Name { InputValueDefinition+ } +InputObjectTypeDefinition : input Name Directives? { InputValueDefinition+ } Input Object types represent complex input values which may be provided as an field argument. Input Object types cannot be the return type of an Object or From 468656d2e801ea3386d8410a86d7205762d9f4ad Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Wed, 19 Oct 2016 10:35:46 -0700 Subject: [PATCH 03/28] expose more in example directive --- spec/Section 2 -- Language.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/Section 2 -- Language.md b/spec/Section 2 -- Language.md index ec13c9d57..8635bde1e 100644 --- a/spec/Section 2 -- Language.md +++ b/spec/Section 2 -- Language.md @@ -1313,9 +1313,9 @@ In this example, a directive is defined which can be used to annotate a fragment definition: ``` -directive @someAnnotation on FRAGMENT_DEFINITION +directive @someAnnotation(arg: String) on FRAGMENT_DEFINITION -fragment SomeFragment on SomeType @someAnnotation { +fragment SomeFragment on SomeType @someAnnotation(arg: "abc") { someField } ``` From 5f420d5cabcade3f5cdfa08f53ab5ec71ed3b037 Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Wed, 19 Oct 2016 10:47:20 -0700 Subject: [PATCH 04/28] Include more directive locations --- spec/Section 2 -- Language.md | 33 ++++++++++++++++++++++++++++++ spec/Section 4 -- Introspection.md | 11 ++++++++++ 2 files changed, 44 insertions(+) diff --git a/spec/Section 2 -- Language.md b/spec/Section 2 -- Language.md index 8635bde1e..bbd339b76 100644 --- a/spec/Section 2 -- Language.md +++ b/spec/Section 2 -- Language.md @@ -1309,6 +1309,27 @@ Since the validation of a GraphQL document includes ensuring that any directives used are defined and used correctly, defining a directive allows for a validator to be aware of all possible validation rules. +As part of validation, directives are only allowed to be used in locations +that are explicitly declared. Directive locations must be one of: + + * `QUERY` + * `MUTATION` + * `FIELD` + * `FRAGMENT_DEFINITION` + * `FRAGMENT_SPREAD` + * `INLINE_FRAGMENT` + * `SCHEMA` + * `SCALAR` + * `OBJECT` + * `FIELD_DEFINITION` + * `ARGUMENT_DEFINITION` + * `INTERFACE` + * `UNION` + * `ENUM` + * `ENUM_VALUE` + * `INPUT_OBJECT` + * `INPUT_FIELD_DEFINITION` + In this example, a directive is defined which can be used to annotate a fragment definition: @@ -1319,3 +1340,15 @@ fragment SomeFragment on SomeType @someAnnotation(arg: "abc") { someField } ``` + +Directives can also be used to annotate the schema language itself: + +``` +directive @some(thing: Int) on FIELD_DEFINITION | ARGUMENT_DEFINITION + +type SomeType { + field( + arg: Int @some(thing: 1) + ): String @some(thing: 2) +} +``` 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 } ``` From 680a35c437a0c9d34c1a8809b95d868535a8862c Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Wed, 19 Oct 2016 10:59:46 -0700 Subject: [PATCH 05/28] Include deprecated directive --- spec/Section 3 -- Type System.md | 35 ++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/spec/Section 3 -- Type System.md b/spec/Section 3 -- Type System.md index 06cb7e80d..d157c59b8 100644 --- a/spec/Section 3 -- Type System.md +++ b/spec/Section 3 -- Type System.md @@ -975,9 +975,15 @@ engine supports. GraphQL implementations should provide the `@skip` and `@include` directives. +GraphQL implementations that support the type system language must provide the +`@deprecated` directive when representing deprecated portions of the schema. ### @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 +1000,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,6 +1025,31 @@ must *not* be queried if either the `@skip` condition is true *or* the `@include` condition is false. +### @deprecated + +```graphql +directive @deprecated( + reason: String = "No longer supported" +) on FIELD_DEFINITION | ENUM_VALUE +``` + +The `@deprecated` directive is used within the type system language to indicate deprecated portions of the schema, such as deprecated fields on a type or +deprecated enum values. + +Deprecations include a reason for why it is deprecated, which can include +markdown formatting. + +In this example type definition, `oldField` is deprecated in favor of +using `newField`. + +```graphql +type ExampleType { + newField: String + oldField: String @deprecated(reason: "Use `newField`.") +} +``` + + ## Initial types A GraphQL schema includes types, indicating where query, mutation, and From 0a6b0569b3eace00d8db5fde447c9a5b20945506 Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Wed, 19 Oct 2016 17:50:59 -0700 Subject: [PATCH 06/28] Note on omission of schema definition --- spec/Section 2 -- Language.md | 34 ++++++++++++++++++++++++++------- spec/Section 5 -- Validation.md | 14 +++++++------- 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/spec/Section 2 -- Language.md b/spec/Section 2 -- Language.md index bbd339b76..a929289c6 100644 --- a/spec/Section 2 -- Language.md +++ b/spec/Section 2 -- Language.md @@ -1116,26 +1116,46 @@ SchemaDefinition : schema { OperationTypeDefinition+ } OperationTypeDefinition : OperationType : NamedType -A GraphQL Type System includes exactly one Schema Definition, which defines -the type to be used for each operation. +A GraphQL Type System includes at most one Schema Definition, which defines +the *root types* to be used for each operation. -In this example, a GraphQL schema is defined with both query and mutation types: +In this example, a GraphQL schema is defined with both query and mutation +root types: ```graphql schema { - query: QueryRoot - mutation: MutationRoot + query: MyQueryRootType + mutation: MyMutationRootType } -type QueryRoot { +type MyQueryRootType { someField: String } -type MutationRoot { +type MyMutationRootType { setSomeField(to: String): String } ``` +**Default Root Types** + +While any type can be the *root type* for a GraphQL query or mutation operation, +GraphQL type system definitions can omit the schema definition when the query +and mutation root types are named `Query` and `Mutation`, respectively. + +Similarly, when serializing a GraphQL schema using the type system language, a +schema definition should be omitted if only uses the default root 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 type of the schema. + +```graphql +type Query { + someField: String +} +``` + ### Type Definition diff --git a/spec/Section 5 -- Validation.md b/spec/Section 5 -- Validation.md index b23051d72..3a0679edf 100644 --- a/spec/Section 5 -- Validation.md +++ b/spec/Section 5 -- Validation.md @@ -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,10 +80,6 @@ type Cat implements Pet { union CatOrDog = Cat | Dog union DogOrHuman = Dog | Human union HumanOrAlien = Human | Alien - -type QueryRoot { - dog: Dog -} ``` @@ -555,7 +555,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 +640,7 @@ type Arguments { booleanListArgField(booleanListArg: [Boolean]!): [Boolean] } -extend type QueryRoot { +extend type Query { arguments: Arguments } ``` @@ -1516,7 +1516,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 } From e575ac834593d6a0b1db1372e5bd1d75fd504d9f Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Thu, 30 Nov 2017 13:12:14 -0800 Subject: [PATCH 07/28] Explicit ObjectTypeExtension grammar to support extending without adding fields --- spec/Appendix B -- Grammar Summary.md | 14 +++-- spec/Section 2 -- Language.md | 84 ++++++++++++++++----------- 2 files changed, 60 insertions(+), 38 deletions(-) diff --git a/spec/Appendix B -- Grammar Summary.md b/spec/Appendix B -- Grammar Summary.md index a8bb798a1..a0b4180fd 100644 --- a/spec/Appendix B -- Grammar Summary.md +++ b/spec/Appendix B -- Grammar Summary.md @@ -184,8 +184,8 @@ Directive : @ Name Arguments? TypeSystemDefinition : - SchemaDefinition - TypeDefinition - - TypeExtensionDefinition - DirectiveDefinition + - TypeExtension SchemaDefinition : schema Directives? { OperationTypeDefinition+ } @@ -201,17 +201,19 @@ TypeDefinition : ScalarTypeDefinition : scalar Name Directives? -ObjectTypeDefinition : type Name ImplementsInterfaces? Directives? { FieldDefinition+ } +ObjectTypeDefinition : type Name ImplementsInterfaces? Directives? FieldDefinitions ImplementsInterfaces : implements NamedType+ +FieldDefinitions : { FieldDefinition+ } + FieldDefinition : Name ArgumentsDefinition? : Type Directives? ArgumentsDefinition : ( InputValueDefinition+ ) InputValueDefinition : Name : Type DefaultValue? Directives? -InterfaceTypeDefinition : interface Name Directives? { FieldDefinition+ } +InterfaceTypeDefinition : interface Name Directives? FieldDefinitions UnionTypeDefinition : union Name Directives? = UnionMembers @@ -227,10 +229,12 @@ EnumValue : Name InputObjectTypeDefinition : input Name Directives? { InputValueDefinition+ } -TypeExtensionDefinition : extend ObjectTypeDefinition - DirectiveDefinition : directive @ Name ArgumentsDefinition? on DirectiveLocations DirectiveLocations : - Name - DirectiveLocations | Name + +TypeExtension : extend ObjectTypeExtension + +ObjectTypeExtension : type Name ImplementsInterfaces? Directives? FieldDefinitions? diff --git a/spec/Section 2 -- Language.md b/spec/Section 2 -- Language.md index a929289c6..4421aa0cf 100644 --- a/spec/Section 2 -- Language.md +++ b/spec/Section 2 -- Language.md @@ -1090,8 +1090,8 @@ they may be exposed via directives. TypeSystemDefinition : - SchemaDefinition - TypeDefinition - - TypeExtensionDefinition - DirectiveDefinition + - TypeExtension The GraphQL language also includes an [IDL](https://en.wikipedia.org/wiki/Interface_description_language) used to @@ -1122,7 +1122,7 @@ the *root types* to be used for each operation. In this example, a GraphQL schema is defined with both query and mutation root types: -```graphql +```graphql example schema { query: MyQueryRootType mutation: MyMutationRootType @@ -1150,7 +1150,7 @@ 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 type of the schema. -```graphql +```graphql example type Query { someField: String } @@ -1182,17 +1182,19 @@ which describe a schema for brevity. In this example, a Scalar type called `DateTime` is defined: -```graphql +```graphql example scalar DateTime ``` #### Object -ObjectTypeDefinition : type Name ImplementsInterfaces? Directives? { FieldDefinition+ } +ObjectTypeDefinition : type Name ImplementsInterfaces? Directives? FieldDefinitions ImplementsInterfaces : implements NamedType+ +FieldDefinitions : { FieldDefinition+ } + FieldDefinition : Name ArgumentsDefinition? : Type Directives? ArgumentsDefinition : ( InputValueDefinition+ ) @@ -1207,7 +1209,7 @@ Object type must supply all fields defined by the Interface. In this example, a Object type called `TodoItem` is defined: -```graphql +```graphql example type TodoItem implements Node { id: ID title: String @@ -1217,7 +1219,7 @@ type TodoItem implements Node { #### Interface -InterfaceTypeDefinition : interface Name Directives? { FieldDefinition+ } +InterfaceTypeDefinition : interface Name Directives? FieldDefinitions Interface types, similarly to Object types represent a list of named fields. Interface types are used as the type of a field when one of many possible Object @@ -1227,7 +1229,7 @@ that Interface as well as includes all defined fields. In this example, an Interface type called `Node` is defined: -```graphql +```graphql example interface Node { id: ID } @@ -1248,7 +1250,7 @@ Union when it is declared by the Union. In this example, a Union type called `Actor` is defined: -```graphql +```graphql example union Actor = User | Business ``` @@ -1266,7 +1268,7 @@ system. However Enum types describe the set of legal values. In this example, an Enum type called `Direction` is defined: -```graphql +```graphql example enum Direction { NORTH EAST @@ -1285,33 +1287,13 @@ Interface field. In this example, an Input Object called `Point2D` is defined: -```graphql +```graphql example input Point2D { x: Float y: Float } ``` -### Type Extension - -TypeExtensionDefinition : extend ObjectTypeDefinition - -Type extensions may be used by client-side tools in order to represent a -GraphQL type system which has been extended from the type system exposed via -introspection by a GraphQL service, for example to represent fields which a -client of GraphQL uses locally, but is not provided by a GraphQL service. - -Any fields or interfaces provided by the extension must not already exist on the -Object type. - -In this example, a client only field is added to a `Story` type: - -```graphql -extend type Story { - isHiddenLocally: Boolean -} -``` - ### Directive Definition DirectiveDefinition : directive @ Name ArgumentsDefinition? on DirectiveLocations @@ -1334,6 +1316,7 @@ that are explicitly declared. Directive locations must be one of: * `QUERY` * `MUTATION` + * `SUBSCRIPTION` * `FIELD` * `FRAGMENT_DEFINITION` * `FRAGMENT_SPREAD` @@ -1353,7 +1336,7 @@ that are explicitly declared. Directive locations must be one of: In this example, a directive is defined which can be used to annotate a fragment definition: -``` +```graphql example directive @someAnnotation(arg: String) on FRAGMENT_DEFINITION fragment SomeFragment on SomeType @someAnnotation(arg: "abc") { @@ -1363,7 +1346,7 @@ fragment SomeFragment on SomeType @someAnnotation(arg: "abc") { Directives can also be used to annotate the schema language itself: -``` +```graphql example directive @some(thing: Int) on FIELD_DEFINITION | ARGUMENT_DEFINITION type SomeType { @@ -1372,3 +1355,38 @@ type SomeType { ): String @some(thing: 2) } ``` + +### Type Extension + +TypeExtension : extend ObjectTypeExtension + +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 +client-side service to represent fields a GraphQL client only accesses locally, +or by a GraphQL service which is itself an extension of another GraphQL service. + + +#### Object Type Extension + +ObjectTypeExtension : type Name ImplementsInterfaces? Directives? FieldDefinitions? + +The named Object type must already exist and be an Object type. Any fields, +interfaces, or directives provided by the extension must not already exist on +the original Object type. + +In this example, a client only field is added to a `Story` type: + +```graphql example +extend type Story { + isHiddenLocally: Boolean +} +``` + +Object type extensions may not 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 +``` From eeb1a2c5e699d4ae75bbc838b278f6bed1aa1c80 Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Thu, 30 Nov 2017 13:21:11 -0800 Subject: [PATCH 08/28] Ensure directives cannot reference variables in SDL --- spec/Appendix B -- Grammar Summary.md | 30 +++++++++++++-------------- spec/Section 2 -- Language.md | 30 +++++++++++++-------------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/spec/Appendix B -- Grammar Summary.md b/spec/Appendix B -- Grammar Summary.md index a0b4180fd..4dba9cb6f 100644 --- a/spec/Appendix B -- Grammar Summary.md +++ b/spec/Appendix B -- Grammar Summary.md @@ -115,9 +115,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? @@ -177,9 +177,9 @@ NonNullType : - NamedType ! - ListType ! -Directives : Directive+ +Directives[Const] : Directive[?Const]+ -Directive : @ Name Arguments? +Directive[Const] : @ Name Arguments[?Const]? TypeSystemDefinition : - SchemaDefinition @@ -187,7 +187,7 @@ TypeSystemDefinition : - DirectiveDefinition - TypeExtension -SchemaDefinition : schema Directives? { OperationTypeDefinition+ } +SchemaDefinition : schema Directives[Const]? { OperationTypeDefinition+ } OperationTypeDefinition : OperationType : NamedType @@ -199,35 +199,35 @@ TypeDefinition : - EnumTypeDefinition - InputObjectTypeDefinition -ScalarTypeDefinition : scalar Name Directives? +ScalarTypeDefinition : scalar Name Directives[Const]? -ObjectTypeDefinition : type Name ImplementsInterfaces? Directives? FieldDefinitions +ObjectTypeDefinition : type Name ImplementsInterfaces? Directives[Const]? FieldDefinitions ImplementsInterfaces : implements NamedType+ FieldDefinitions : { FieldDefinition+ } -FieldDefinition : Name ArgumentsDefinition? : Type Directives? +FieldDefinition : Name ArgumentsDefinition? : Type Directives[Const]? ArgumentsDefinition : ( InputValueDefinition+ ) -InputValueDefinition : Name : Type DefaultValue? Directives? +InputValueDefinition : Name : Type DefaultValue? Directives[Const]? -InterfaceTypeDefinition : interface Name Directives? FieldDefinitions +InterfaceTypeDefinition : interface Name Directives[Const]? FieldDefinitions -UnionTypeDefinition : union Name Directives? = UnionMembers +UnionTypeDefinition : union Name Directives[Const]? = UnionMembers UnionMembers : - NamedType - UnionMembers | NamedType -EnumTypeDefinition : enum Name Directives? { EnumValueDefinition+ } +EnumTypeDefinition : enum Name Directives[Const]? { EnumValueDefinition+ } -EnumValueDefinition : EnumValue Directives? +EnumValueDefinition : EnumValue Directives[Const]? EnumValue : Name -InputObjectTypeDefinition : input Name Directives? { InputValueDefinition+ } +InputObjectTypeDefinition : input Name Directives[Const]? { InputValueDefinition+ } DirectiveDefinition : directive @ Name ArgumentsDefinition? on DirectiveLocations @@ -237,4 +237,4 @@ DirectiveLocations : TypeExtension : extend ObjectTypeExtension -ObjectTypeExtension : type Name ImplementsInterfaces? Directives? FieldDefinitions? +ObjectTypeExtension : type Name ImplementsInterfaces? Directives[Const]? FieldDefinitions? diff --git a/spec/Section 2 -- Language.md b/spec/Section 2 -- Language.md index 4421aa0cf..84e290553 100644 --- a/spec/Section 2 -- Language.md +++ b/spec/Section 2 -- Language.md @@ -323,9 +323,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 @@ -1064,9 +1064,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. @@ -1112,7 +1112,7 @@ when illustrating example type systems. ### Schema Definition -SchemaDefinition : schema { OperationTypeDefinition+ } +SchemaDefinition : schema Directives[Const]? { OperationTypeDefinition+ } OperationTypeDefinition : OperationType : NamedType @@ -1172,7 +1172,7 @@ A GraphQL Type System is defined by many different kinds of types. #### Scalar -ScalarTypeDefinition : scalar Name +ScalarTypeDefinition : scalar Name Directives[Const]? Scalar types represent leaf values in a GraphQL type system. While this GraphQL specification describes a set of Scalar types which all GraphQL services must @@ -1189,17 +1189,17 @@ scalar DateTime #### Object -ObjectTypeDefinition : type Name ImplementsInterfaces? Directives? FieldDefinitions +ObjectTypeDefinition : type Name ImplementsInterfaces? Directives[Const]? FieldDefinitions ImplementsInterfaces : implements NamedType+ FieldDefinitions : { FieldDefinition+ } -FieldDefinition : Name ArgumentsDefinition? : Type Directives? +FieldDefinition : Name ArgumentsDefinition? : Type Directives[Const]? ArgumentsDefinition : ( InputValueDefinition+ ) -InputValueDefinition : Name : Type DefaultValue? Directives? +InputValueDefinition : Name : Type DefaultValue? Directives[Const]? Object types represent a list of named fields, each of which yield a value of a specific type. Each field itself may accept a list of named arguments. @@ -1219,7 +1219,7 @@ type TodoItem implements Node { #### Interface -InterfaceTypeDefinition : interface Name Directives? FieldDefinitions +InterfaceTypeDefinition : interface Name Directives[Const]? FieldDefinitions Interface types, similarly to Object types represent a list of named fields. Interface types are used as the type of a field when one of many possible Object @@ -1237,7 +1237,7 @@ interface Node { #### Union -UnionTypeDefinition : union Name Directives? = UnionMembers +UnionTypeDefinition : union Name Directives[Const]? = UnionMembers UnionMembers : - NamedType @@ -1257,9 +1257,9 @@ union Actor = User | Business #### Enum -EnumTypeDefinition : enum Name Directives? { EnumValueDefinition+ } +EnumTypeDefinition : enum Name Directives[Const]? { EnumValueDefinition+ } -EnumValueDefinition : EnumValue Directives? +EnumValueDefinition : EnumValue Directives[Const]? EnumValue : Name @@ -1279,7 +1279,7 @@ enum Direction { #### Input Object -InputObjectTypeDefinition : input Name Directives? { InputValueDefinition+ } +InputObjectTypeDefinition : input Name Directives[Const]? { InputValueDefinition+ } Input Object types represent complex input values which may be provided as an field argument. Input Object types cannot be the return type of an Object or @@ -1368,7 +1368,7 @@ or by a GraphQL service which is itself an extension of another GraphQL service. #### Object Type Extension -ObjectTypeExtension : type Name ImplementsInterfaces? Directives? FieldDefinitions? +ObjectTypeExtension : type Name ImplementsInterfaces? Directives[Const]? FieldDefinitions? The named Object type must already exist and be an Object type. Any fields, interfaces, or directives provided by the extension must not already exist on From edc0af2c5fae681489adf663132409448fb178fc Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Thu, 30 Nov 2017 13:28:17 -0800 Subject: [PATCH 09/28] grammar --- spec/Section 2 -- Language.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/spec/Section 2 -- Language.md b/spec/Section 2 -- Language.md index 84e290553..c357aa329 100644 --- a/spec/Section 2 -- Language.md +++ b/spec/Section 2 -- Language.md @@ -1144,7 +1144,7 @@ GraphQL type system definitions can omit the schema definition when the query and mutation root types are named `Query` and `Mutation`, respectively. Similarly, when serializing a GraphQL schema using the type system language, a -schema definition should be omitted if only uses the default root type names. +schema definition should be omitted if it only uses the default root 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 @@ -1356,6 +1356,15 @@ type SomeType { } ``` +While defining a directive, it may not reference itself directly or indirectly: + +```graphql counter-example +directive @invalidExample( + arg: String @invalidExample(arg: "references itself") +) on ARGUMENT_DEFINITION +``` + + ### Type Extension TypeExtension : extend ObjectTypeExtension From 03622db564c6f84f7453ac328c2953a52864c3c8 Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Thu, 30 Nov 2017 13:29:18 -0800 Subject: [PATCH 10/28] Remove duplicate EnumValue --- spec/Appendix B -- Grammar Summary.md | 2 -- spec/Section 2 -- Language.md | 2 -- 2 files changed, 4 deletions(-) diff --git a/spec/Appendix B -- Grammar Summary.md b/spec/Appendix B -- Grammar Summary.md index 4dba9cb6f..18479f470 100644 --- a/spec/Appendix B -- Grammar Summary.md +++ b/spec/Appendix B -- Grammar Summary.md @@ -225,8 +225,6 @@ EnumTypeDefinition : enum Name Directives[Const]? { EnumValueDefinition+ } EnumValueDefinition : EnumValue Directives[Const]? -EnumValue : Name - InputObjectTypeDefinition : input Name Directives[Const]? { InputValueDefinition+ } DirectiveDefinition : directive @ Name ArgumentsDefinition? on DirectiveLocations diff --git a/spec/Section 2 -- Language.md b/spec/Section 2 -- Language.md index c357aa329..a3b54b215 100644 --- a/spec/Section 2 -- Language.md +++ b/spec/Section 2 -- Language.md @@ -1261,8 +1261,6 @@ EnumTypeDefinition : enum Name Directives[Const]? { EnumValueDefinition+ } EnumValueDefinition : EnumValue Directives[Const]? -EnumValue : Name - Enum types, like Scalar types, also represent leaf values in a GraphQL type system. However Enum types describe the set of legal values. From 58dc0828333f44fc07020cc0dbb156cb35a0b21c Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Thu, 30 Nov 2017 13:44:59 -0800 Subject: [PATCH 11/28] First class descriptions --- spec/Appendix B -- Grammar Summary.md | 22 +++++----- spec/Section 2 -- Language.md | 61 ++++++++++++++++++++++----- 2 files changed, 62 insertions(+), 21 deletions(-) diff --git a/spec/Appendix B -- Grammar Summary.md b/spec/Appendix B -- Grammar Summary.md index 18479f470..dcaf833df 100644 --- a/spec/Appendix B -- Grammar Summary.md +++ b/spec/Appendix B -- Grammar Summary.md @@ -199,35 +199,37 @@ TypeDefinition : - EnumTypeDefinition - InputObjectTypeDefinition -ScalarTypeDefinition : scalar Name Directives[Const]? +Description : StringValue -ObjectTypeDefinition : type Name ImplementsInterfaces? Directives[Const]? FieldDefinitions +ScalarTypeDefinition : Description? scalar Name Directives[Const]? + +ObjectTypeDefinition : Description? type Name ImplementsInterfaces? Directives[Const]? FieldDefinitions ImplementsInterfaces : implements NamedType+ FieldDefinitions : { FieldDefinition+ } -FieldDefinition : Name ArgumentsDefinition? : Type Directives[Const]? +FieldDefinition : Description? Name ArgumentsDefinition? : Type Directives[Const]? ArgumentsDefinition : ( InputValueDefinition+ ) -InputValueDefinition : Name : Type DefaultValue? Directives[Const]? +InputValueDefinition : Description? Name : Type DefaultValue? Directives[Const]? -InterfaceTypeDefinition : interface Name Directives[Const]? FieldDefinitions +InterfaceTypeDefinition : Description? interface Name Directives[Const]? FieldDefinitions -UnionTypeDefinition : union Name Directives[Const]? = UnionMembers +UnionTypeDefinition : Description? union Name Directives[Const]? = UnionMembers UnionMembers : - NamedType - UnionMembers | NamedType -EnumTypeDefinition : enum Name Directives[Const]? { EnumValueDefinition+ } +EnumTypeDefinition : Description? enum Name Directives[Const]? { EnumValueDefinition+ } -EnumValueDefinition : EnumValue Directives[Const]? +EnumValueDefinition : Description? EnumValue Directives[Const]? -InputObjectTypeDefinition : input Name Directives[Const]? { InputValueDefinition+ } +InputObjectTypeDefinition : Description? input Name Directives[Const]? { InputValueDefinition+ } -DirectiveDefinition : directive @ Name ArgumentsDefinition? on DirectiveLocations +DirectiveDefinition : Description? directive @ Name ArgumentsDefinition? on DirectiveLocations DirectiveLocations : - Name diff --git a/spec/Section 2 -- Language.md b/spec/Section 2 -- Language.md index a3b54b215..79942790c 100644 --- a/spec/Section 2 -- Language.md +++ b/spec/Section 2 -- Language.md @@ -1169,10 +1169,49 @@ TypeDefinition : A GraphQL Type System is defined by many different kinds of types. +#### Descriptions + +Description : String + +All GraphQL types, fields, and arguments should provide a {Description} to allow +type designers to publish documentation alongside capabilities of a GraphQL +service. GraphQL descriptions are defined using Markdown syntax (as specified by +[CommonMark](http://commonmark.org/)). These description strings (often +{BlockString}) occur immediately before the definition they describe. + +As an example, this simple 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: String + + """ + The translated language to be returned. + """ + toLanguage: String + + """ + The text to be translated from an original language into a + translated language. + """ + text: String + ): String +} +``` #### Scalar -ScalarTypeDefinition : scalar Name Directives[Const]? +ScalarTypeDefinition : Description? scalar Name Directives[Const]? Scalar types represent leaf values in a GraphQL type system. While this GraphQL specification describes a set of Scalar types which all GraphQL services must @@ -1189,17 +1228,17 @@ scalar DateTime #### Object -ObjectTypeDefinition : type Name ImplementsInterfaces? Directives[Const]? FieldDefinitions +ObjectTypeDefinition : Description? type Name ImplementsInterfaces? Directives[Const]? FieldDefinitions -ImplementsInterfaces : implements NamedType+ +ImplementsInterfaces : Description? implements NamedType+ FieldDefinitions : { FieldDefinition+ } -FieldDefinition : Name ArgumentsDefinition? : Type Directives[Const]? +FieldDefinition : Description? Name ArgumentsDefinition? : Type Directives[Const]? ArgumentsDefinition : ( InputValueDefinition+ ) -InputValueDefinition : Name : Type DefaultValue? Directives[Const]? +InputValueDefinition : Description? Name : Type DefaultValue? Directives[Const]? Object types represent a list of named fields, each of which yield a value of a specific type. Each field itself may accept a list of named arguments. @@ -1219,7 +1258,7 @@ type TodoItem implements Node { #### Interface -InterfaceTypeDefinition : interface Name Directives[Const]? FieldDefinitions +InterfaceTypeDefinition : Description? interface Name Directives[Const]? FieldDefinitions Interface types, similarly to Object types represent a list of named fields. Interface types are used as the type of a field when one of many possible Object @@ -1237,7 +1276,7 @@ interface Node { #### Union -UnionTypeDefinition : union Name Directives[Const]? = UnionMembers +UnionTypeDefinition : Description? union Name Directives[Const]? = UnionMembers UnionMembers : - NamedType @@ -1257,9 +1296,9 @@ union Actor = User | Business #### Enum -EnumTypeDefinition : enum Name Directives[Const]? { EnumValueDefinition+ } +EnumTypeDefinition : Description? enum Name Directives[Const]? { EnumValueDefinition+ } -EnumValueDefinition : EnumValue Directives[Const]? +EnumValueDefinition : Description? EnumValue Directives[Const]? Enum types, like Scalar types, also represent leaf values in a GraphQL type system. However Enum types describe the set of legal values. @@ -1277,7 +1316,7 @@ enum Direction { #### Input Object -InputObjectTypeDefinition : input Name Directives[Const]? { InputValueDefinition+ } +InputObjectTypeDefinition : Description? input Name Directives[Const]? { InputValueDefinition+ } Input Object types represent complex input values which may be provided as an field argument. Input Object types cannot be the return type of an Object or @@ -1294,7 +1333,7 @@ input Point2D { ### Directive Definition -DirectiveDefinition : directive @ Name ArgumentsDefinition? on DirectiveLocations +DirectiveDefinition : Description? directive @ Name ArgumentsDefinition? on DirectiveLocations DirectiveLocations : - Name From 628845c07e25123c36d02065491452eb09b4ed4b Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Thu, 30 Nov 2017 13:51:19 -0800 Subject: [PATCH 12/28] Minor wording change about markdown and TSL -> SDL --- spec/Section 3 -- Type System.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/spec/Section 3 -- Type System.md b/spec/Section 3 -- Type System.md index d157c59b8..2ebd66c9b 100644 --- a/spec/Section 3 -- Type System.md +++ b/spec/Section 3 -- Type System.md @@ -975,8 +975,8 @@ engine supports. GraphQL implementations should provide the `@skip` and `@include` directives. -GraphQL implementations that support the type system language must provide the -`@deprecated` directive when representing deprecated portions of the schema. +GraphQL implementations that support the schema definition language must provide +the `@deprecated` directive when representing deprecated portions of the schema. ### @skip @@ -1033,11 +1033,12 @@ directive @deprecated( ) on FIELD_DEFINITION | ENUM_VALUE ``` -The `@deprecated` directive is used within the type system language to indicate deprecated portions of the schema, such as deprecated fields on a type or -deprecated enum values. +The `@deprecated` directive is used within the schema definition language to +indicate deprecated portions of the schema, such as deprecated fields on a type +or deprecated enum values. -Deprecations include a reason for why it is deprecated, which can include -markdown formatting. +Deprecations include a reason for why it is deprecated, which is formatted using +Markdown syntax (as specified by [CommonMark](http://commonmark.org/)). In this example type definition, `oldField` is deprecated in favor of using `newField`. From 4559ecab063fbe9a0638837e13434b078b1cfb33 Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Thu, 30 Nov 2017 14:08:22 -0800 Subject: [PATCH 13/28] Add validation rule that executable documents cannot include SDL --- spec/Section 5 -- Validation.md | 46 ++++++++++++++++++++++++++++++--- spec/Section 6 -- Execution.md | 5 ++-- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/spec/Section 5 -- Validation.md b/spec/Section 5 -- Validation.md index 3a0679edf..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 @@ -83,6 +83,44 @@ union HumanOrAlien = Human | Alien ``` +## 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 ### Named Operation Definitions @@ -91,7 +129,7 @@ union HumanOrAlien = Human | Alien **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}. diff --git a/spec/Section 6 -- Execution.md b/spec/Section 6 -- Execution.md index bdfcf4193..bbf3153fd 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,8 +19,7 @@ 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 +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 From 7d1b7001d0c67cfabed2a1f6b750bc8f0ea32b02 Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Thu, 30 Nov 2017 14:09:39 -0800 Subject: [PATCH 14/28] Move extend keyword --- spec/Appendix B -- Grammar Summary.md | 5 +++-- spec/Section 2 -- Language.md | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/spec/Appendix B -- Grammar Summary.md b/spec/Appendix B -- Grammar Summary.md index dcaf833df..19f3b4d35 100644 --- a/spec/Appendix B -- Grammar Summary.md +++ b/spec/Appendix B -- Grammar Summary.md @@ -235,6 +235,7 @@ DirectiveLocations : - Name - DirectiveLocations | Name -TypeExtension : extend ObjectTypeExtension +TypeExtension : + - ObjectTypeExtension -ObjectTypeExtension : type Name ImplementsInterfaces? Directives[Const]? FieldDefinitions? +ObjectTypeExtension : extend type Name ImplementsInterfaces? Directives[Const]? FieldDefinitions? diff --git a/spec/Section 2 -- Language.md b/spec/Section 2 -- Language.md index 79942790c..f74e2827e 100644 --- a/spec/Section 2 -- Language.md +++ b/spec/Section 2 -- Language.md @@ -1404,7 +1404,8 @@ directive @invalidExample( ### Type Extension -TypeExtension : extend ObjectTypeExtension +TypeExtension : + - ObjectTypeExtension 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 @@ -1414,7 +1415,7 @@ or by a GraphQL service which is itself an extension of another GraphQL service. #### Object Type Extension -ObjectTypeExtension : type Name ImplementsInterfaces? Directives[Const]? FieldDefinitions? +ObjectTypeExtension : extend type Name ImplementsInterfaces? Directives[Const]? FieldDefinitions? The named Object type must already exist and be an Object type. Any fields, interfaces, or directives provided by the extension must not already exist on From 6070aec72f4d01b9af592467beff1bb5c6e42691 Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Thu, 30 Nov 2017 14:50:43 -0800 Subject: [PATCH 15/28] Order of sections --- spec/Appendix B -- Grammar Summary.md | 12 ++--- spec/Section 2 -- Language.md | 77 ++++++++++++++------------- 2 files changed, 45 insertions(+), 44 deletions(-) diff --git a/spec/Appendix B -- Grammar Summary.md b/spec/Appendix B -- Grammar Summary.md index 19f3b4d35..2e61c33e9 100644 --- a/spec/Appendix B -- Grammar Summary.md +++ b/spec/Appendix B -- Grammar Summary.md @@ -184,8 +184,8 @@ Directive[Const] : @ Name Arguments[?Const]? TypeSystemDefinition : - SchemaDefinition - TypeDefinition - - DirectiveDefinition - TypeExtension + - DirectiveDefinition SchemaDefinition : schema Directives[Const]? { OperationTypeDefinition+ } @@ -229,13 +229,13 @@ EnumValueDefinition : Description? EnumValue Directives[Const]? InputObjectTypeDefinition : Description? input Name Directives[Const]? { InputValueDefinition+ } +TypeExtension : + - ObjectTypeExtension + +ObjectTypeExtension : extend type Name ImplementsInterfaces? Directives[Const]? FieldDefinitions? + DirectiveDefinition : Description? directive @ Name ArgumentsDefinition? on DirectiveLocations DirectiveLocations : - Name - DirectiveLocations | Name - -TypeExtension : - - ObjectTypeExtension - -ObjectTypeExtension : extend type Name ImplementsInterfaces? Directives[Const]? FieldDefinitions? diff --git a/spec/Section 2 -- Language.md b/spec/Section 2 -- Language.md index f74e2827e..9f9f7cfa2 100644 --- a/spec/Section 2 -- Language.md +++ b/spec/Section 2 -- Language.md @@ -1090,8 +1090,8 @@ they may be exposed via directives. TypeSystemDefinition : - SchemaDefinition - TypeDefinition - - DirectiveDefinition - TypeExtension + - DirectiveDefinition The GraphQL language also includes an [IDL](https://en.wikipedia.org/wiki/Interface_description_language) used to @@ -1331,6 +1331,44 @@ input Point2D { } ``` + +### Type Extension + +TypeExtension : + - ObjectTypeExtension + +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 +client-side service to represent fields a GraphQL client only accesses locally, +or by a GraphQL service which is itself an extension of another GraphQL service. + + +#### Object Type Extension + +ObjectTypeExtension : extend type Name ImplementsInterfaces? Directives[Const]? FieldDefinitions? + +The named Object type must already exist and be an Object type. Any fields, +interfaces, or directives provided by the extension must not already exist on +the original Object type. + +In this example, a client only field is added to a `Story` type: + +```graphql example +extend type Story { + isHiddenLocally: Boolean +} +``` + +Object type extensions may not 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 +``` + + ### Directive Definition DirectiveDefinition : Description? directive @ Name ArgumentsDefinition? on DirectiveLocations @@ -1400,40 +1438,3 @@ directive @invalidExample( arg: String @invalidExample(arg: "references itself") ) on ARGUMENT_DEFINITION ``` - - -### Type Extension - -TypeExtension : - - ObjectTypeExtension - -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 -client-side service to represent fields a GraphQL client only accesses locally, -or by a GraphQL service which is itself an extension of another GraphQL service. - - -#### Object Type Extension - -ObjectTypeExtension : extend type Name ImplementsInterfaces? Directives[Const]? FieldDefinitions? - -The named Object type must already exist and be an Object type. Any fields, -interfaces, or directives provided by the extension must not already exist on -the original Object type. - -In this example, a client only field is added to a `Story` type: - -```graphql example -extend type Story { - isHiddenLocally: Boolean -} -``` - -Object type extensions may not 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 -``` From 4b5f7eaa13d1a04c02826f69e340e66a65cff499 Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Thu, 30 Nov 2017 18:53:28 -0800 Subject: [PATCH 16/28] Move language definitions into Type System section --- spec/Appendix B -- Grammar Summary.md | 28 +- spec/Section 2 -- Language.md | 355 --------------- spec/Section 3 -- Type System.md | 616 +++++++++++++++++++------- spec/Section 6 -- Execution.md | 10 +- 4 files changed, 486 insertions(+), 523 deletions(-) diff --git a/spec/Appendix B -- Grammar Summary.md b/spec/Appendix B -- Grammar Summary.md index 2e61c33e9..22ccc059c 100644 --- a/spec/Appendix B -- Grammar Summary.md +++ b/spec/Appendix B -- Grammar Summary.md @@ -191,6 +191,8 @@ SchemaDefinition : schema Directives[Const]? { OperationTypeDefinition+ } OperationTypeDefinition : OperationType : NamedType +Description : StringValue + TypeDefinition : - ScalarTypeDefinition - ObjectTypeDefinition @@ -199,12 +201,18 @@ TypeDefinition : - EnumTypeDefinition - InputObjectTypeDefinition -Description : StringValue +TypeExtension : + - ObjectTypeExtension ScalarTypeDefinition : Description? scalar Name Directives[Const]? ObjectTypeDefinition : Description? type Name ImplementsInterfaces? Directives[Const]? FieldDefinitions +ObjectTypeExtension : + - extend type Name ImplementsInterfaces? Directives[Const]? FieldDefinitions + - extend type Name ImplementsInterfaces? Directives[Const] + - extend type Name ImplementsInterfaces + ImplementsInterfaces : implements NamedType+ FieldDefinitions : { FieldDefinition+ } @@ -229,13 +237,17 @@ EnumValueDefinition : Description? EnumValue Directives[Const]? InputObjectTypeDefinition : Description? input Name Directives[Const]? { InputValueDefinition+ } -TypeExtension : - - ObjectTypeExtension - -ObjectTypeExtension : extend type Name ImplementsInterfaces? Directives[Const]? FieldDefinitions? - DirectiveDefinition : Description? directive @ Name ArgumentsDefinition? on DirectiveLocations DirectiveLocations : - - Name - - DirectiveLocations | Name + - DirectiveLocation + - DirectiveLocations | DirectiveLocation + +DirectiveLocation : one of + `QUERY` `SCHEMA` `ENUM` + `MUTATION` `SCALAR` `ENUM_VALUE` + `SUBSCRIPTION` `OBJECT` `INPUT_OBJECT` + `FIELD` `FIELD_DEFINITION` `INPUT_FIELD_DEFINITION` + `FRAGMENT_DEFINITION` `ARGUMENT_DEFINITION` + `FRAGMENT_SPREAD` `INTERFACE` + `INLINE_FRAGMENT` `UNION` diff --git a/spec/Section 2 -- Language.md b/spec/Section 2 -- Language.md index 9f9f7cfa2..6deda5414 100644 --- a/spec/Section 2 -- Language.md +++ b/spec/Section 2 -- Language.md @@ -1083,358 +1083,3 @@ and operations. As future versions of GraphQL adopt new configurable execution capabilities, they may be exposed via directives. - - -## Type System Definition - -TypeSystemDefinition : - - SchemaDefinition - - TypeDefinition - - TypeExtension - - DirectiveDefinition - -The GraphQL language also includes an -[IDL](https://en.wikipedia.org/wiki/Interface_description_language) used to -describe a GraphQL service's Type System. Tools may use these definitions to -provide various utilities such as client code generation or -service boot-strapping. - -GraphQL services which only seek to provide GraphQL query execution may -choose to not 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: This IDL is used throughout the remainder of this specification document -when illustrating example type systems. - - -### Schema Definition - -SchemaDefinition : schema Directives[Const]? { OperationTypeDefinition+ } - -OperationTypeDefinition : OperationType : NamedType - -A GraphQL Type System includes at most one Schema Definition, which defines -the *root types* to be used for each operation. - -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 Types** - -While any type can be the *root type* for a GraphQL query or mutation operation, -GraphQL type system definitions can omit the schema definition when the query -and mutation root types are named `Query` and `Mutation`, respectively. - -Similarly, when serializing a GraphQL schema using the type system language, a -schema definition should be omitted if it only uses the default root 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 type of the schema. - -```graphql example -type Query { - someField: String -} -``` - - -### Type Definition - -TypeDefinition : - - ScalarTypeDefinition - - ObjectTypeDefinition - - InterfaceTypeDefinition - - UnionTypeDefinition - - EnumTypeDefinition - - InputObjectTypeDefinition - -A GraphQL Type System is defined by many different kinds of types. - -#### Descriptions - -Description : String - -All GraphQL types, fields, and arguments should provide a {Description} to allow -type designers to publish documentation alongside capabilities of a GraphQL -service. GraphQL descriptions are defined using Markdown syntax (as specified by -[CommonMark](http://commonmark.org/)). These description strings (often -{BlockString}) occur immediately before the definition they describe. - -As an example, this simple 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: String - - """ - The translated language to be returned. - """ - toLanguage: String - - """ - The text to be translated from an original language into a - translated language. - """ - text: String - ): String -} -``` - -#### Scalar - -ScalarTypeDefinition : Description? scalar Name Directives[Const]? - -Scalar types represent leaf values in a GraphQL type system. While this GraphQL -specification describes a set of Scalar types which all GraphQL services must -supply, custom Scalar types may be supplied by a GraphQL service. Typically, the -set of Scalar types described in this specification are omitted from documents -which describe a schema for brevity. - -In this example, a Scalar type called `DateTime` is defined: - -```graphql example -scalar DateTime -``` - - -#### Object - -ObjectTypeDefinition : Description? type Name ImplementsInterfaces? Directives[Const]? FieldDefinitions - -ImplementsInterfaces : Description? implements NamedType+ - -FieldDefinitions : { FieldDefinition+ } - -FieldDefinition : Description? Name ArgumentsDefinition? : Type Directives[Const]? - -ArgumentsDefinition : ( InputValueDefinition+ ) - -InputValueDefinition : Description? Name : Type DefaultValue? Directives[Const]? - -Object types represent a list of named fields, each of which yield a value of a -specific type. Each field itself may accept a list of named arguments. - -Objects may implement Interface types. When implementing an Interface type, the -Object type must supply all fields defined by the Interface. - -In this example, a Object type called `TodoItem` is defined: - -```graphql example -type TodoItem implements Node { - id: ID - title: String - isCompleted: Boolean -} -``` - -#### Interface - -InterfaceTypeDefinition : Description? interface Name Directives[Const]? FieldDefinitions - -Interface types, similarly to Object types represent a list of named fields. -Interface types are used as the type of a field when one of many possible Object -types may yielded during execution, but some fields are guaranteed. An Object -type is a possible type of an Interface when it both declares that it implements -that Interface as well as includes all defined fields. - -In this example, an Interface type called `Node` is defined: - -```graphql example -interface Node { - id: ID -} -``` - -#### Union - -UnionTypeDefinition : Description? union Name Directives[Const]? = UnionMembers - -UnionMembers : - - NamedType - - UnionMembers | NamedType - -Union types represent a list of named Object types. Union types are used as the -type of a field when one of many possible Object types may yielded during -execution, and no fields are guaranteed. An Object type is a possible type of a -Union when it is declared by the Union. - -In this example, a Union type called `Actor` is defined: - -```graphql example -union Actor = User | Business -``` - - -#### Enum - -EnumTypeDefinition : Description? enum Name Directives[Const]? { EnumValueDefinition+ } - -EnumValueDefinition : Description? EnumValue Directives[Const]? - -Enum types, like Scalar types, also represent leaf values in a GraphQL type -system. However Enum types describe the set of legal values. - -In this example, an Enum type called `Direction` is defined: - -```graphql example -enum Direction { - NORTH - EAST - SOUTH - WEST -} -``` - -#### Input Object - -InputObjectTypeDefinition : Description? input Name Directives[Const]? { InputValueDefinition+ } - -Input Object types represent complex input values which may be provided as an -field argument. Input Object types cannot be the return type of an Object or -Interface field. - -In this example, an Input Object called `Point2D` is defined: - -```graphql example -input Point2D { - x: Float - y: Float -} -``` - - -### Type Extension - -TypeExtension : - - ObjectTypeExtension - -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 -client-side service to represent fields a GraphQL client only accesses locally, -or by a GraphQL service which is itself an extension of another GraphQL service. - - -#### Object Type Extension - -ObjectTypeExtension : extend type Name ImplementsInterfaces? Directives[Const]? FieldDefinitions? - -The named Object type must already exist and be an Object type. Any fields, -interfaces, or directives provided by the extension must not already exist on -the original Object type. - -In this example, a client only field is added to a `Story` type: - -```graphql example -extend type Story { - isHiddenLocally: Boolean -} -``` - -Object type extensions may not 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 -``` - - -### Directive Definition - -DirectiveDefinition : Description? directive @ Name ArgumentsDefinition? on DirectiveLocations - -DirectiveLocations : - - Name - - DirectiveLocations | Name - -A GraphQL Type System often also includes directives which may be used to -annotate various nodes in a GraphQL document as an indicator that they should be -evaluated differently by a validator, executor, or client tool such as a -code generator. - -Since the validation of a GraphQL document includes ensuring that any directives -used are defined and used correctly, defining a directive allows for a validator -to be aware of all possible validation rules. - -As part of validation, directives are only allowed to be used in locations -that are explicitly declared. Directive locations must be one of: - - * `QUERY` - * `MUTATION` - * `SUBSCRIPTION` - * `FIELD` - * `FRAGMENT_DEFINITION` - * `FRAGMENT_SPREAD` - * `INLINE_FRAGMENT` - * `SCHEMA` - * `SCALAR` - * `OBJECT` - * `FIELD_DEFINITION` - * `ARGUMENT_DEFINITION` - * `INTERFACE` - * `UNION` - * `ENUM` - * `ENUM_VALUE` - * `INPUT_OBJECT` - * `INPUT_FIELD_DEFINITION` - -In this example, a directive is defined which can be used to annotate a -fragment definition: - -```graphql example -directive @someAnnotation(arg: String) on FRAGMENT_DEFINITION - -fragment SomeFragment on SomeType @someAnnotation(arg: "abc") { - someField -} -``` - -Directives can also be used to annotate the schema language itself: - -```graphql example -directive @some(thing: Int) on FIELD_DEFINITION | ARGUMENT_DEFINITION - -type SomeType { - field( - arg: Int @some(thing: 1) - ): String @some(thing: 2) -} -``` - -While defining a directive, it may not reference itself directly or indirectly: - -```graphql counter-example -directive @invalidExample( - arg: String @invalidExample(arg: "references itself") -) on ARGUMENT_DEFINITION -``` diff --git a/spec/Section 3 -- Type System.md b/spec/Section 3 -- Type System.md index 2ebd66c9b..54a2a3d66 100644 --- a/spec/Section 3 -- Type System.md +++ b/spec/Section 3 -- Type System.md @@ -5,32 +5,199 @@ 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 -A given GraphQL schema must itself be internally valid. This section describes -the rules for this validation process where relevant. +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 not 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. + + +## Schema + +SchemaDefinition : schema Directives[Const]? { RootOperationTypeDefinition+ } + +RootOperationTypeDefinition : OperationType : NamedType -A GraphQL schema is represented by a root type for each kind of operation: +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 { + me +} +``` + +Is valid when the `query` root operation type has a field named "me". + +```graphql example +type Query { + me: User +} +``` + +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 +should 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: String + + """ + The translated language to be returned. + """ + toLanguage: String + + """ + The text to be translated from an original language into a + translated language. + """ + text: String + ): String +} +``` + ## 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 +218,45 @@ 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. + +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. + + +### Type Extensions + +TypeExtension : + - ObjectTypeExtension + +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 +## 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. +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 +271,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 +332,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 +357,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 +380,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 +401,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 +419,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 +444,15 @@ 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 +## Objects + +ObjectTypeDefinition : Description? type Name ImplementsInterfaces? Directives[Const]? FieldDefinitions + +ImplementsInterfaces : Description? implements NamedType+ + +FieldDefinitions : { 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 +681,48 @@ executor, so this is covered in that section of the spec. Objects are never valid inputs. +**Type Validation** + +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+ ) -#### Object Field Arguments +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,63 +767,80 @@ 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 Type Extension + +ObjectTypeExtension : + - extend type Name ImplementsInterfaces? Directives[Const]? FieldDefinitions + - extend type Name ImplementsInterfaces? Directives[Const] + - extend type Name ImplementsInterfaces + +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. + +In this example, a local data field is added to a `Story` type: + +```graphql example +extend type Story { + isHiddenLocally: Boolean +} +``` + +Object type extensions may not 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 -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. +## Interfaces + +InterfaceTypeDefinition : Description? interface Name Directives[Const]? FieldDefinitions + +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. ```graphql example interface NamedEntity { @@ -663,8 +924,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 +935,13 @@ Interface types have the potential to be invalid if incorrectly defined. characters {"__"} (two underscores). -### Unions +## Unions + +UnionTypeDefinition : Description? union Name Directives[Const]? = UnionMembers + +UnionMembers : + - NamedType + - UnionMembers | 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 +952,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 @@ -748,8 +1014,7 @@ 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. @@ -758,13 +1023,29 @@ Union types have the potential to be invalid if incorrectly defined. Similarly, wrapping types may 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. +## Enums + +EnumTypeDefinition : Description? enum Name Directives[Const]? { 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 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. +```graphql example +enum Direction { + NORTH + EAST + SOUTH + WEST +} +``` **Result Coercion** @@ -782,26 +1063,43 @@ 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. -### Input Objects +1. A Enum type must define one or more unique enum values. -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. -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. +## Input Objects -An `Input Object` defines a set of input fields; the input fields are either +InputObjectTypeDefinition : Description? input Name Directives[Const]? { InputValueDefinition+ } + +Fields may accept arguments to configure their behavior. These inputs are often +scalars or enums, but they sometimes need to represent more complex values. + +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 +1153,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 +1161,7 @@ Literal Value | Variables | Coerced Value 3. The return types of each defined field must be an Input type. -### Lists +## 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 +1195,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, @@ -963,20 +1261,75 @@ 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 : one of + `QUERY` `SCHEMA` `ENUM` + `MUTATION` `SCALAR` `ENUM_VALUE` + `SUBSCRIPTION` `OBJECT` `INPUT_OBJECT` + `FIELD` `FIELD_DEFINITION` `INPUT_FIELD_DEFINITION` + `FRAGMENT_DEFINITION` `ARGUMENT_DEFINITION` + `FRAGMENT_SPREAD` `INTERFACE` + `INLINE_FRAGMENT` `UNION` + +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 schema definition language must provide -the `@deprecated` directive when representing deprecated portions of the schema. +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 +} +``` + +Directives can also be used to annotate the type system definition language +as well, which is : + +```graphql example +directive @example on FIELD_DEFINITION | ARGUMENT_DEFINITION + +type SomeType { + field(arg: Int @example): String @example +} +``` + +While defining a directive, it may not reference itself directly or indirectly: + +```graphql counter-example +directive @invalidExample(arg: String @invalidExample) on ARGUMENT_DEFINITION +``` + +**Validation** + +1. A directive definition may not contain the use of a directive which + references itself directly. +2. A directive definition may not contain the use of a directive which + references itself indirectly by reference a Type or Directive which + transitively includes a reference to this directive. + ### @skip @@ -1033,9 +1386,9 @@ directive @deprecated( ) on FIELD_DEFINITION | ENUM_VALUE ``` -The `@deprecated` directive is used within the schema definition language to -indicate deprecated portions of the schema, such as deprecated fields on a type -or deprecated enum values. +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. Deprecations include a reason for why it is deprecated, which is formatted using Markdown syntax (as specified by [CommonMark](http://commonmark.org/)). @@ -1043,56 +1396,9 @@ Markdown syntax (as specified by [CommonMark](http://commonmark.org/)). In this example type definition, `oldField` is deprecated in favor of using `newField`. -```graphql +```graphql example type ExampleType { newField: String oldField: String @deprecated(reason: "Use `newField`.") } ``` - - -## 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. - -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 -} -``` - -Is valid when the type provided for the query starting type has a field -named "me". Similarly - -```graphql example -mutation setName { - setName(name: "Zuck") { - newName - } -} -``` - -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". - -```graphql example -subscription { - newMessage { - text - } -} -``` - -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 6 -- Execution.md b/spec/Section 6 -- Execution.md index bbf3153fd..7ae8706a3 100644 --- a/spec/Section 6 -- Execution.md +++ b/spec/Section 6 -- Execution.md @@ -19,11 +19,11 @@ to be formatted according to the Response section below. ## Executing Requests -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. +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): From b94438e8ab37b7dbfd873119a19e365dc8aa763a Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Thu, 30 Nov 2017 18:59:32 -0800 Subject: [PATCH 17/28] Fix type reference header and comments --- spec/Section 2 -- Language.md | 2 +- spec/Section 3 -- Type System.md | 13 +++---------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/spec/Section 2 -- Language.md b/spec/Section 2 -- Language.md index 6deda5414..0889faf4d 100644 --- a/spec/Section 2 -- Language.md +++ b/spec/Section 2 -- Language.md @@ -1021,7 +1021,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 diff --git a/spec/Section 3 -- Type System.md b/spec/Section 3 -- Type System.md index 54a2a3d66..6f83dca51 100644 --- a/spec/Section 3 -- Type System.md +++ b/spec/Section 3 -- Type System.md @@ -166,20 +166,13 @@ type Query { Translates a string from a given language into a different language. """ translate( - """ - The original language that `text` is provided in. - """ + "The original language that `text` is provided in." fromLanguage: String - """ - The translated language to be returned. - """ + "The translated language to be returned." toLanguage: String - """ - The text to be translated from an original language into a - translated language. - """ + "The text to be translated." text: String ): String } From d6919ce401b65e7af136557248fecf26ab8e628c Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Thu, 30 Nov 2017 19:02:15 -0800 Subject: [PATCH 18/28] Add more examples of descriptions --- spec/Section 3 -- Type System.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/spec/Section 3 -- Type System.md b/spec/Section 3 -- Type System.md index 6f83dca51..ec27dd75d 100644 --- a/spec/Section 3 -- Type System.md +++ b/spec/Section 3 -- Type System.md @@ -167,15 +167,29 @@ type Query { """ translate( "The original language that `text` is provided in." - fromLanguage: String + fromLanguage: Language "The translated language to be returned." - toLanguage: String + 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 +} ``` From d39cad34eb8d0411279f5bcf18b4c9cf5511d320 Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Fri, 1 Dec 2017 10:51:02 -0800 Subject: [PATCH 19/28] Grammar --- spec/Section 3 -- Type System.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/Section 3 -- Type System.md b/spec/Section 3 -- Type System.md index ec27dd75d..9588130a5 100644 --- a/spec/Section 3 -- Type System.md +++ b/spec/Section 3 -- Type System.md @@ -1334,7 +1334,7 @@ directive @invalidExample(arg: String @invalidExample) on ARGUMENT_DEFINITION 1. A directive definition may not contain the use of a directive which references itself directly. 2. A directive definition may not contain the use of a directive which - references itself indirectly by reference a Type or Directive which + references itself indirectly by referencing a Type or Directive which transitively includes a reference to this directive. From afb50d663ed0be665df6771e3d2e1f83f4967b66 Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Mon, 4 Dec 2017 10:22:39 -0800 Subject: [PATCH 20/28] Include optional leading bar for unions & directive locations. Merging and closing #323 --- spec/Appendix B -- Grammar Summary.md | 4 ++-- spec/Section 3 -- Type System.md | 23 +++++++++++++++++++++-- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/spec/Appendix B -- Grammar Summary.md b/spec/Appendix B -- Grammar Summary.md index 22ccc059c..aa699d708 100644 --- a/spec/Appendix B -- Grammar Summary.md +++ b/spec/Appendix B -- Grammar Summary.md @@ -228,7 +228,7 @@ InterfaceTypeDefinition : Description? interface Name Directives[Const]? FieldDe UnionTypeDefinition : Description? union Name Directives[Const]? = UnionMembers UnionMembers : - - NamedType + - `|`? NamedType - UnionMembers | NamedType EnumTypeDefinition : Description? enum Name Directives[Const]? { EnumValueDefinition+ } @@ -240,7 +240,7 @@ InputObjectTypeDefinition : Description? input Name Directives[Const]? { InputVa DirectiveDefinition : Description? directive @ Name ArgumentsDefinition? on DirectiveLocations DirectiveLocations : - - DirectiveLocation + - `|`? DirectiveLocation - DirectiveLocations | DirectiveLocation DirectiveLocation : one of diff --git a/spec/Section 3 -- Type System.md b/spec/Section 3 -- Type System.md index 9588130a5..2048644cb 100644 --- a/spec/Section 3 -- Type System.md +++ b/spec/Section 3 -- Type System.md @@ -947,7 +947,7 @@ Interface types have the potential to be invalid if incorrectly defined. UnionTypeDefinition : Description? union Name Directives[Const]? = UnionMembers UnionMembers : - - NamedType + - `|`? NamedType - UnionMembers | NamedType GraphQL Unions represent an object that could be one of a list of GraphQL @@ -1011,6 +1011,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 @@ -1278,7 +1287,7 @@ a non-null input type as invalid. DirectiveDefinition : Description? directive @ Name ArgumentsDefinition? on DirectiveLocations DirectiveLocations : - - DirectiveLocation + - `|`? DirectiveLocation - DirectiveLocations | DirectiveLocation DirectiveLocation : one of @@ -1312,6 +1321,16 @@ fragment SomeFragment on SomeType { } ``` +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 is : From bde02b9da4323eec50d72bf47e473f1add66a06d Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Tue, 5 Dec 2017 18:41:07 -0800 Subject: [PATCH 21/28] Allow partial definitions (as @OlegIlyenko suggests) while legitimizing the use case by allowing type extensions for all type kinds, allowing at least the addition of new directives to any existing type. --- spec/Appendix B -- Grammar Summary.md | 40 ++++++- spec/Section 3 -- Type System.md | 165 ++++++++++++++++++++++++-- 2 files changed, 192 insertions(+), 13 deletions(-) diff --git a/spec/Appendix B -- Grammar Summary.md b/spec/Appendix B -- Grammar Summary.md index aa699d708..b27ab1e36 100644 --- a/spec/Appendix B -- Grammar Summary.md +++ b/spec/Appendix B -- Grammar Summary.md @@ -202,11 +202,19 @@ TypeDefinition : - InputObjectTypeDefinition TypeExtension : + - ScalarTypeExtension - ObjectTypeExtension + - InterfaceTypeExtension + - UnionTypeExtension + - EnumTypeExtension + - InputObjectTypeDefinition ScalarTypeDefinition : Description? scalar Name Directives[Const]? -ObjectTypeDefinition : Description? type Name ImplementsInterfaces? Directives[Const]? FieldDefinitions +ScalarTypeExtension : + - extend scalar Name Directives[Const] + +ObjectTypeDefinition : Description? type Name ImplementsInterfaces? Directives[Const]? FieldDefinitions? ObjectTypeExtension : - extend type Name ImplementsInterfaces? Directives[Const]? FieldDefinitions @@ -223,19 +231,41 @@ ArgumentsDefinition : ( InputValueDefinition+ ) InputValueDefinition : Description? Name : Type DefaultValue? Directives[Const]? -InterfaceTypeDefinition : Description? interface Name Directives[Const]? FieldDefinitions +InterfaceTypeDefinition : Description? interface Name Directives[Const]? FieldDefinitions? + +InterfaceTypeExtension : + - extend interface Name Directives[Const]? FieldDefinitions + - extend interface Name Directives[Const] -UnionTypeDefinition : Description? union Name Directives[Const]? = UnionMembers +UnionTypeDefinition : Description? union Name Directives[Const]? UnionMembersDefinition? + +UnionMembersDefinition : = UnionMembers UnionMembers : - `|`? NamedType - UnionMembers | NamedType -EnumTypeDefinition : Description? enum Name Directives[Const]? { EnumValueDefinition+ } +UnionTypeExtension : + - extend union Name Directives[Const]? UnionMembersDefinition + - extend union Name Directives[Const] + +EnumTypeDefinition : Description? enum Name Directives[Const]? EnumValueDefinitions? + +EnumValueDefinitions : { EnumValueDefinition+ } EnumValueDefinition : Description? EnumValue Directives[Const]? -InputObjectTypeDefinition : Description? input Name Directives[Const]? { InputValueDefinition+ } +EnumTypeExtension : + - extend enum Name Directives[Const]? EnumValueDefinitions + - extend enum Name Directives[Const] + +InputObjectTypeDefinition : Description? input Name Directives[Const]? InputFieldDefinitions? + +InputFieldDefinitions : { InputValueDefinition+ } + +InputObjectTypeExtension : + - extend input Name Directives[Const]? InputFieldDefinitions + - extend input Name Directives[Const] DirectiveDefinition : Description? directive @ Name ArgumentsDefinition? on DirectiveLocations diff --git a/spec/Section 3 -- Type System.md b/spec/Section 3 -- Type System.md index 2048644cb..e509cb8b2 100644 --- a/spec/Section 3 -- Type System.md +++ b/spec/Section 3 -- Type System.md @@ -249,7 +249,12 @@ found by continually unwrapping the type until a named type is found. ### 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 @@ -451,9 +456,26 @@ 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. +### 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]? FieldDefinitions +ObjectTypeDefinition : Description? type Name ImplementsInterfaces? Directives[Const]? FieldDefinitions? ImplementsInterfaces : Description? implements NamedType+ @@ -791,14 +813,15 @@ type ExampleType { ``` -### Object Type Extension +### Object Extensions ObjectTypeExtension : - extend type Name ImplementsInterfaces? Directives[Const]? FieldDefinitions - extend type Name ImplementsInterfaces? Directives[Const] - extend type Name ImplementsInterfaces -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 +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. In this example, a local data field is added to a `Story` type: @@ -836,10 +859,11 @@ Object type extensions have the potential to be invalid if incorrectly defined. ## Interfaces -InterfaceTypeDefinition : Description? interface Name Directives[Const]? FieldDefinitions +InterfaceTypeDefinition : Description? interface Name Directives[Const]? FieldDefinitions? 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. +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 @@ -942,9 +966,63 @@ Interface types have the potential to be invalid if incorrectly defined. characters {"__"} (two underscores). +### Interface Extensions + +InterfaceTypeExtension : + - extend interface Name Directives[Const]? FieldDefinitions + - 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 not add additional fields, instead only adding +directives. + +In this example, a directive is added to a `NamedEntity` type without +adding fields: + +```graphql example +extend type 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. +5. Any directives provided must not already apply to the original Interface type. + + ## Unions -UnionTypeDefinition : Description? union Name Directives[Const]? = UnionMembers +UnionTypeDefinition : Description? union Name Directives[Const]? UnionMembersDefinition? + +UnionMembersDefinition : = UnionMembers UnionMembers : - `|`? NamedType @@ -1040,9 +1118,35 @@ Union types have the potential to be invalid if incorrectly defined. 2. A Union type must define one or more unique member types. +### Union Extensions + +UnionTypeExtension : + - extend union Name Directives[Const]? UnionMembersDefinition + - 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 may not be member types of a Union. + Similarly, wrapping types may 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]? { EnumValueDefinition+ } +EnumTypeDefinition : Description? enum Name Directives[Const]? EnumValueDefinitions? + +EnumValueDefinitions : { EnumValueDefinition+ } EnumValueDefinition : Description? EnumValue Directives[Const]? @@ -1086,9 +1190,33 @@ Enum types have the potential to be invalid if incorrectly defined. 1. A Enum type must define one or more unique enum values. +### Enum Extensions + +EnumTypeExtension : + - extend enum Name Directives[Const]? EnumValueDefinitions + - 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 a Enum type. +3. All values of a Enum type extension must be unique. +4. All values of a Enum type extension must not already be a value of + the original Enum. +5. Any directives provided must not already apply to the original Enum type. + + ## Input Objects -InputObjectTypeDefinition : Description? input Name Directives[Const]? { InputValueDefinition+ } +InputObjectTypeDefinition : Description? input Name Directives[Const]? InputFieldDefinitions? + +InputFieldDefinitions : { InputValueDefinition+ } Fields may accept arguments to configure their behavior. These inputs are often scalars or enums, but they sometimes need to represent more complex values. @@ -1177,6 +1305,27 @@ Literal Value | Variables | Coerced Value 3. The return types of each defined field must be an Input type. +### Input Object Extensions + +InputObjectTypeExtension : + - extend input Name Directives[Const]? InputFieldDefinitions + - 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 From 786a0e2da504c445d9f923d1e4b952600e59270e Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Wed, 6 Dec 2017 10:26:39 -0800 Subject: [PATCH 22/28] Consistent plural usage in grammar nt rules --- spec/Appendix B -- Grammar Summary.md | 32 +++++++++++++-------------- spec/Section 3 -- Type System.md | 32 +++++++++++++-------------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/spec/Appendix B -- Grammar Summary.md b/spec/Appendix B -- Grammar Summary.md index b27ab1e36..7856f59c4 100644 --- a/spec/Appendix B -- Grammar Summary.md +++ b/spec/Appendix B -- Grammar Summary.md @@ -214,16 +214,16 @@ ScalarTypeDefinition : Description? scalar Name Directives[Const]? ScalarTypeExtension : - extend scalar Name Directives[Const] -ObjectTypeDefinition : Description? type Name ImplementsInterfaces? Directives[Const]? FieldDefinitions? +ObjectTypeDefinition : Description? type Name ImplementsInterfaces? Directives[Const]? FieldsDefinition? ObjectTypeExtension : - - extend type Name ImplementsInterfaces? Directives[Const]? FieldDefinitions + - extend type Name ImplementsInterfaces? Directives[Const]? FieldsDefinition - extend type Name ImplementsInterfaces? Directives[Const] - extend type Name ImplementsInterfaces ImplementsInterfaces : implements NamedType+ -FieldDefinitions : { FieldDefinition+ } +FieldsDefinition : { FieldDefinition+ } FieldDefinition : Description? Name ArgumentsDefinition? : Type Directives[Const]? @@ -231,40 +231,40 @@ ArgumentsDefinition : ( InputValueDefinition+ ) InputValueDefinition : Description? Name : Type DefaultValue? Directives[Const]? -InterfaceTypeDefinition : Description? interface Name Directives[Const]? FieldDefinitions? +InterfaceTypeDefinition : Description? interface Name Directives[Const]? FieldsDefinition? InterfaceTypeExtension : - - extend interface Name Directives[Const]? FieldDefinitions + - extend interface Name Directives[Const]? FieldsDefinition - extend interface Name Directives[Const] -UnionTypeDefinition : Description? union Name Directives[Const]? UnionMembersDefinition? +UnionTypeDefinition : Description? union Name Directives[Const]? MemberTypesDefinition? -UnionMembersDefinition : = UnionMembers +MemberTypesDefinition : = MemberTypes -UnionMembers : +MemberTypes : - `|`? NamedType - - UnionMembers | NamedType + - MemberTypes | NamedType UnionTypeExtension : - - extend union Name Directives[Const]? UnionMembersDefinition + - extend union Name Directives[Const]? MemberTypesDefinition - extend union Name Directives[Const] -EnumTypeDefinition : Description? enum Name Directives[Const]? EnumValueDefinitions? +EnumTypeDefinition : Description? enum Name Directives[Const]? EnumValuesDefinition? -EnumValueDefinitions : { EnumValueDefinition+ } +EnumValuesDefinition : { EnumValueDefinition+ } EnumValueDefinition : Description? EnumValue Directives[Const]? EnumTypeExtension : - - extend enum Name Directives[Const]? EnumValueDefinitions + - extend enum Name Directives[Const]? EnumValuesDefinition - extend enum Name Directives[Const] -InputObjectTypeDefinition : Description? input Name Directives[Const]? InputFieldDefinitions? +InputObjectTypeDefinition : Description? input Name Directives[Const]? InputFieldsDefinition? -InputFieldDefinitions : { InputValueDefinition+ } +InputFieldsDefinition : { InputValueDefinition+ } InputObjectTypeExtension : - - extend input Name Directives[Const]? InputFieldDefinitions + - extend input Name Directives[Const]? InputFieldsDefinition - extend input Name Directives[Const] DirectiveDefinition : Description? directive @ Name ArgumentsDefinition? on DirectiveLocations diff --git a/spec/Section 3 -- Type System.md b/spec/Section 3 -- Type System.md index e509cb8b2..c9d0c5151 100644 --- a/spec/Section 3 -- Type System.md +++ b/spec/Section 3 -- Type System.md @@ -475,11 +475,11 @@ Scalar type extensions have the potential to be invalid if incorrectly defined. ## Objects -ObjectTypeDefinition : Description? type Name ImplementsInterfaces? Directives[Const]? FieldDefinitions? +ObjectTypeDefinition : Description? type Name ImplementsInterfaces? Directives[Const]? FieldsDefinition? ImplementsInterfaces : Description? implements NamedType+ -FieldDefinitions : { FieldDefinition+ } +FieldsDefinition : { FieldDefinition+ } FieldDefinition : Description? Name ArgumentsDefinition? : Type Directives[Const]? @@ -816,7 +816,7 @@ type ExampleType { ### Object Extensions ObjectTypeExtension : - - extend type Name ImplementsInterfaces? Directives[Const]? FieldDefinitions + - extend type Name ImplementsInterfaces? Directives[Const]? FieldsDefinition - extend type Name ImplementsInterfaces? Directives[Const] - extend type Name ImplementsInterfaces @@ -859,7 +859,7 @@ Object type extensions have the potential to be invalid if incorrectly defined. ## Interfaces -InterfaceTypeDefinition : Description? interface Name Directives[Const]? FieldDefinitions? +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 @@ -969,7 +969,7 @@ Interface types have the potential to be invalid if incorrectly defined. ### Interface Extensions InterfaceTypeExtension : - - extend interface Name Directives[Const]? FieldDefinitions + - extend interface Name Directives[Const]? FieldsDefinition - extend interface Name Directives[Const] Interface type extensions are used to represent an interface which has been @@ -1020,13 +1020,13 @@ Interface type extensions have the potential to be invalid if incorrectly define ## Unions -UnionTypeDefinition : Description? union Name Directives[Const]? UnionMembersDefinition? +UnionTypeDefinition : Description? union Name Directives[Const]? MemberTypesDefinition? -UnionMembersDefinition : = UnionMembers +MemberTypesDefinition : = MemberTypes -UnionMembers : +MemberTypes : - `|`? NamedType - - UnionMembers | NamedType + - MemberTypes | 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. @@ -1121,7 +1121,7 @@ Union types have the potential to be invalid if incorrectly defined. ### Union Extensions UnionTypeExtension : - - extend union Name Directives[Const]? UnionMembersDefinition + - extend union Name Directives[Const]? MemberTypesDefinition - extend union Name Directives[Const] Union type extensions are used to represent a union type which has been @@ -1144,9 +1144,9 @@ Union type extensions have the potential to be invalid if incorrectly defined. ## Enums -EnumTypeDefinition : Description? enum Name Directives[Const]? EnumValueDefinitions? +EnumTypeDefinition : Description? enum Name Directives[Const]? EnumValuesDefinition? -EnumValueDefinitions : { EnumValueDefinition+ } +EnumValuesDefinition : { EnumValueDefinition+ } EnumValueDefinition : Description? EnumValue Directives[Const]? @@ -1193,7 +1193,7 @@ Enum types have the potential to be invalid if incorrectly defined. ### Enum Extensions EnumTypeExtension : - - extend enum Name Directives[Const]? EnumValueDefinitions + - extend enum Name Directives[Const]? EnumValuesDefinition - extend enum Name Directives[Const] Enum type extensions are used to represent an enum type which has been @@ -1214,9 +1214,9 @@ Enum type extensions have the potential to be invalid if incorrectly defined. ## Input Objects -InputObjectTypeDefinition : Description? input Name Directives[Const]? InputFieldDefinitions? +InputObjectTypeDefinition : Description? input Name Directives[Const]? InputFieldsDefinition? -InputFieldDefinitions : { InputValueDefinition+ } +InputFieldsDefinition : { InputValueDefinition+ } Fields may accept arguments to configure their behavior. These inputs are often scalars or enums, but they sometimes need to represent more complex values. @@ -1308,7 +1308,7 @@ Literal Value | Variables | Coerced Value ### Input Object Extensions InputObjectTypeExtension : - - extend input Name Directives[Const]? InputFieldDefinitions + - extend input Name Directives[Const]? InputFieldsDefinition - extend input Name Directives[Const] Input object type extensions are used to represent an input object type which From 85ffa8ff92fef81e1aadeb51cf39bb60e364735c Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Wed, 6 Dec 2017 14:50:15 -0800 Subject: [PATCH 23/28] Remove ambiguous "may not" and explicitly state objects may implement interfaces via extensions --- spec/Section 3 -- Type System.md | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/spec/Section 3 -- Type System.md b/spec/Section 3 -- Type System.md index c9d0c5151..5c68c6675 100644 --- a/spec/Section 3 -- Type System.md +++ b/spec/Section 3 -- Type System.md @@ -16,7 +16,8 @@ The GraphQL language includes an 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 not parse {TypeSystemDefinition}. +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 @@ -832,8 +833,8 @@ extend type Story { } ``` -Object type extensions may not add additional fields, instead only adding -interfaces or directives. +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: @@ -994,8 +995,8 @@ extend type Business { } ``` -Interface type extensions may not add additional fields, instead only adding -directives. +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: @@ -1014,7 +1015,8 @@ Interface type extensions have the potential to be invalid if incorrectly define 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. + 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. @@ -1113,8 +1115,8 @@ Unions are never valid inputs. 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. @@ -1135,8 +1137,8 @@ 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 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. 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. @@ -1491,7 +1493,7 @@ type SomeType { } ``` -While defining a directive, it may not reference itself directly or indirectly: +While defining a directive, it must not reference itself directly or indirectly: ```graphql counter-example directive @invalidExample(arg: String @invalidExample) on ARGUMENT_DEFINITION @@ -1499,9 +1501,9 @@ directive @invalidExample(arg: String @invalidExample) on ARGUMENT_DEFINITION **Validation** -1. A directive definition may not contain the use of a directive which +1. A directive definition must not contain the use of a directive which references itself directly. -2. A directive definition may not contain the use of a directive which +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. From e607dcc00fca0f41a84ecd58ced4b598f031d498 Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Tue, 12 Dec 2017 16:43:36 -0800 Subject: [PATCH 24/28] Extract ExecutableDefinition into a separate gramatical rule --- spec/Appendix B -- Grammar Summary.md | 5 ++++- spec/Section 2 -- Language.md | 27 +++++++++++++++++---------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/spec/Appendix B -- Grammar Summary.md b/spec/Appendix B -- Grammar Summary.md index 7856f59c4..bc87c4efb 100644 --- a/spec/Appendix B -- Grammar Summary.md +++ b/spec/Appendix B -- Grammar Summary.md @@ -94,9 +94,12 @@ lines and uniform indentation with {BlockStringValue()}. Document : Definition+ Definition : + - ExecutableDefinition + - TypeSystemDefinition + +ExecutableDefinition : - OperationDefinition - FragmentDefinition - - TypeSystemDefinition OperationDefinition : - SelectionSet diff --git a/spec/Section 2 -- Language.md b/spec/Section 2 -- Language.md index 0889faf4d..c523b780d 100644 --- a/spec/Section 2 -- Language.md +++ b/spec/Section 2 -- Language.md @@ -153,7 +153,7 @@ lacks the punctuation often used to describe mathematical expressions. Name :: /[_A-Za-z][_0-9A-Za-z]*/ GraphQL Documents are full of named things: operations, fields, arguments, -directives, fragments, and variables. All names must follow the same +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` @@ -169,17 +169,23 @@ characters to support interoperation with as many other systems as possible. Document : Definition+ Definition : + - ExecutableDefinition + - TypeSystemDefinition + +ExecutableDefinition : - OperationDefinition - FragmentDefinition - - TypeSystemDefinition A GraphQL Document describes a complete file or request string operated on -by a GraphQL service or client tool. A document contains multiple definitions of -Operations and Fragments, and if consumed by a client tool may also include Type -Definitions. GraphQL Documents are only executable by a server if they -contain an Operation but do not contain a Type Definition. However documents -which do not contain Operations may still be parsed and validated to allow -client tools to represent a single request across many documents. +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 represented in the shorthand form, which omits both the query keyword and @@ -188,8 +194,9 @@ 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 implementations which only seek to provide GraphQL query execution may -omit the {TypeSystemDefinition} rule from {Definition}. +GraphQL services which only seek to provide GraphQL query execution may choose +to only include {ExecutableDefinition} and omit the {TypeSystemDefinition} rule +from {Definition}. ## Operations From aeada74be2766c139bb7c96cff38fa5890ab66e1 Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Tue, 12 Dec 2017 17:05:08 -0800 Subject: [PATCH 25/28] Address review from @vergenzt --- spec/Appendix B -- Grammar Summary.md | 33 +++++++++--- spec/Section 3 -- Type System.md | 78 ++++++++++++++++++--------- 2 files changed, 79 insertions(+), 32 deletions(-) diff --git a/spec/Appendix B -- Grammar Summary.md b/spec/Appendix B -- Grammar Summary.md index bc87c4efb..ae9435c6f 100644 --- a/spec/Appendix B -- Grammar Summary.md +++ b/spec/Appendix B -- Grammar Summary.md @@ -276,11 +276,28 @@ DirectiveLocations : - `|`? DirectiveLocation - DirectiveLocations | DirectiveLocation -DirectiveLocation : one of - `QUERY` `SCHEMA` `ENUM` - `MUTATION` `SCALAR` `ENUM_VALUE` - `SUBSCRIPTION` `OBJECT` `INPUT_OBJECT` - `FIELD` `FIELD_DEFINITION` `INPUT_FIELD_DEFINITION` - `FRAGMENT_DEFINITION` `ARGUMENT_DEFINITION` - `FRAGMENT_SPREAD` `INTERFACE` - `INLINE_FRAGMENT` `UNION` +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` diff --git a/spec/Section 3 -- Type System.md b/spec/Section 3 -- Type System.md index 5c68c6675..9177d7345 100644 --- a/spec/Section 3 -- Type System.md +++ b/spec/Section 3 -- Type System.md @@ -73,21 +73,21 @@ at the top level of a GraphQL query. For example, a basic GraphQL query like: ```graphql example query { - me + myName } ``` -Is valid when the `query` root operation type has a field named "me". +Is valid when the `query` root operation type has a field named "myName". ```graphql example type Query { - me: User + 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 -should be different types. +must be different types. ```graphql example mutation { @@ -97,7 +97,8 @@ mutation { } ``` -When using the type system definition language, a document must include at most one `schema` definition. +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: @@ -120,7 +121,8 @@ type MyMutationRootType { **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 +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 @@ -149,7 +151,8 @@ 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}) +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 @@ -240,7 +243,8 @@ 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. +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, @@ -1002,7 +1006,7 @@ In this example, a directive is added to a `NamedEntity` type without adding fields: ```graphql example -extend type NamedEntity @addedDirective +extend interface NamedEntity @addedDirective ``` **Type Validation** @@ -1189,7 +1193,7 @@ input value with the same name. Enum types have the potential to be invalid if incorrectly defined. -1. A Enum type must define one or more unique enum values. +1. An Enum type must define one or more unique enum values. ### Enum Extensions @@ -1207,11 +1211,11 @@ extension of another GraphQL service. Enum type extensions have the potential to be invalid if incorrectly defined. -1. The named type must already be defined and must be a Enum type. -3. All values of a Enum type extension must be unique. -4. All values of a Enum type extension must not already be a value of +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. -5. Any directives provided must not already apply to the original Enum type. +4. Any directives provided must not already apply to the original Enum type. ## Input Objects @@ -1391,6 +1395,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 @@ -1399,7 +1407,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. @@ -1441,14 +1450,31 @@ DirectiveLocations : - `|`? DirectiveLocation - DirectiveLocations | DirectiveLocation -DirectiveLocation : one of - `QUERY` `SCHEMA` `ENUM` - `MUTATION` `SCALAR` `ENUM_VALUE` - `SUBSCRIPTION` `OBJECT` `INPUT_OBJECT` - `FIELD` `FIELD_DEFINITION` `INPUT_FIELD_DEFINITION` - `FRAGMENT_DEFINITION` `ARGUMENT_DEFINITION` - `FRAGMENT_SPREAD` `INTERFACE` - `INLINE_FRAGMENT` `UNION` +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 @@ -1483,7 +1509,11 @@ directive @example on ``` Directives can also be used to annotate the type system definition language -as well, which is : +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 From 0444c3e88e6fa55b6e9da1d81a80bdcce0e3f45a Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Tue, 19 Dec 2017 17:33:49 -0800 Subject: [PATCH 26/28] Use `&` to separate implemented interfaces, simplify grammar definitions --- spec/Appendix B -- Grammar Summary.md | 16 ++++++++-------- spec/Section 3 -- Type System.md | 24 ++++++++++++++++-------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/spec/Appendix B -- Grammar Summary.md b/spec/Appendix B -- Grammar Summary.md index ae9435c6f..017efe315 100644 --- a/spec/Appendix B -- Grammar Summary.md +++ b/spec/Appendix B -- Grammar Summary.md @@ -224,7 +224,9 @@ ObjectTypeExtension : - extend type Name ImplementsInterfaces? Directives[Const] - extend type Name ImplementsInterfaces -ImplementsInterfaces : implements NamedType+ +ImplementsInterfaces : + - implements `&`? NamedType + - ImplementsInterfaces & NamedType FieldsDefinition : { FieldDefinition+ } @@ -240,16 +242,14 @@ InterfaceTypeExtension : - extend interface Name Directives[Const]? FieldsDefinition - extend interface Name Directives[Const] -UnionTypeDefinition : Description? union Name Directives[Const]? MemberTypesDefinition? +UnionTypeDefinition : Description? union Name Directives[Const]? UnionMemberTypes? -MemberTypesDefinition : = MemberTypes - -MemberTypes : - - `|`? NamedType - - MemberTypes | NamedType +UnionMemberTypes : + - = `|`? NamedType + - UnionMemberTypes | NamedType UnionTypeExtension : - - extend union Name Directives[Const]? MemberTypesDefinition + - extend union Name Directives[Const]? UnionMemberTypes - extend union Name Directives[Const] EnumTypeDefinition : Description? enum Name Directives[Const]? EnumValuesDefinition? diff --git a/spec/Section 3 -- Type System.md b/spec/Section 3 -- Type System.md index 9177d7345..4d5a39f1f 100644 --- a/spec/Section 3 -- Type System.md +++ b/spec/Section 3 -- Type System.md @@ -482,7 +482,9 @@ Scalar type extensions have the potential to be invalid if incorrectly defined. ObjectTypeDefinition : Description? type Name ImplementsInterfaces? Directives[Const]? FieldsDefinition? -ImplementsInterfaces : Description? implements NamedType+ +ImplementsInterfaces : + - implements `&`? NamedType + - ImplementsInterfaces & NamedType FieldsDefinition : { FieldDefinition+ } @@ -878,18 +880,26 @@ 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 } ``` @@ -1026,12 +1036,10 @@ Interface type extensions have the potential to be invalid if incorrectly define ## Unions -UnionTypeDefinition : Description? union Name Directives[Const]? MemberTypesDefinition? - -MemberTypesDefinition : = MemberTypes +UnionTypeDefinition : Description? union Name Directives[Const]? UnionMemberTypes? -MemberTypes : - - `|`? NamedType +UnionMemberTypes : + - = `|`? NamedType - MemberTypes | NamedType GraphQL Unions represent an object that could be one of a list of GraphQL @@ -1127,7 +1135,7 @@ Union types have the potential to be invalid if incorrectly defined. ### Union Extensions UnionTypeExtension : - - extend union Name Directives[Const]? MemberTypesDefinition + - extend union Name Directives[Const]? UnionMemberTypes - extend union Name Directives[Const] Union type extensions are used to represent a union type which has been From 555265940bdfe0519294d538c3d87f1ac8897e2b Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Thu, 21 Dec 2017 18:22:17 -0800 Subject: [PATCH 27/28] Fix reference in grammar summary --- spec/Appendix B -- Grammar Summary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/Appendix B -- Grammar Summary.md b/spec/Appendix B -- Grammar Summary.md index 017efe315..56b7d1676 100644 --- a/spec/Appendix B -- Grammar Summary.md +++ b/spec/Appendix B -- Grammar Summary.md @@ -210,7 +210,7 @@ TypeExtension : - InterfaceTypeExtension - UnionTypeExtension - EnumTypeExtension - - InputObjectTypeDefinition + - InputObjectTypeExtension ScalarTypeDefinition : Description? scalar Name Directives[Const]? From 27d59b77b2fcddfdea05fb8877a57cf999e51116 Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Thu, 8 Feb 2018 12:53:04 -0800 Subject: [PATCH 28/28] Fix reference to UnionMemberTypes --- spec/Section 3 -- Type System.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/Section 3 -- Type System.md b/spec/Section 3 -- Type System.md index 4d5a39f1f..e52cfbbe0 100644 --- a/spec/Section 3 -- Type System.md +++ b/spec/Section 3 -- Type System.md @@ -1040,7 +1040,7 @@ UnionTypeDefinition : Description? union Name Directives[Const]? UnionMemberType UnionMemberTypes : - = `|`? NamedType - - MemberTypes | 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.