├── assets └── banner.png ├── .gitignore ├── signed-agreements ├── Facebook-GraphQL-OWFa1.0.pdf └── README.md ├── .github ├── PULL_REQUEST_TEMPLATE.md ├── ISSUE_TEMPLATE.md ├── workflows │ └── ci.yml └── algorithm-format-check.mjs ├── .prettierignore ├── cspell.yml ├── spec ├── metadata.json ├── GraphQL.md ├── Appendix D -- Specified Definitions.md ├── Appendix A -- Conformance.md ├── Section 1 -- Overview.md ├── Appendix B -- Notation Conventions.md ├── Appendix C -- Grammar Summary.md ├── Section 7 -- Response.md └── Section 4 -- Introspection.md ├── scripts ├── update-appendix-specified-definitions.mjs └── generate-contributor-list.mjs ├── package.json ├── LICENSE.md ├── STYLE_GUIDE.md ├── CONTRIBUTING.md ├── README.md └── changelogs └── September2025.md /assets/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphql/graphql-spec/HEAD/assets/banner.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *~ 3 | .*.haste_cache.* 4 | .DS_Store 5 | npm-debug.log 6 | /build 7 | /public 8 | /gh-pages 9 | /node_modules 10 | -------------------------------------------------------------------------------- /signed-agreements/Facebook-GraphQL-OWFa1.0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphql/graphql-spec/HEAD/signed-agreements/Facebook-GraphQL-OWFa1.0.pdf -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | !!! IMPORTANT !!! 2 | 3 | Please Read https://github.com/graphql/graphql-spec/blob/master/CONTRIBUTING.md 4 | before creating a Pull Request. 5 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *~ 3 | .*.haste_cache.* 4 | .DS_Store 5 | npm-debug.log 6 | /build 7 | /changelogs 8 | /out 9 | /gh-pages 10 | /node_modules 11 | /package.json 12 | -------------------------------------------------------------------------------- /cspell.yml: -------------------------------------------------------------------------------- 1 | language: en-US 2 | ignoreRegExpList: 3 | # Posessives 4 | - /[a-z]{2,}'s/ 5 | words: 6 | # Terms of art 7 | - endianness 8 | - interoperation 9 | - monospace 10 | - openwebfoundation 11 | - parallelization 12 | - structs 13 | - subselection 14 | # Fictional characters / examples 15 | - alderaan 16 | - hagrid 17 | - leia 18 | - newhope 19 | - othername 20 | - skywalker 21 | - tatooine 22 | - zuck 23 | - zuckerberg 24 | - brontie 25 | - oneOf 26 | # Forbid Alternative spellings 27 | flagWords: 28 | - implementor 29 | - implementors 30 | -------------------------------------------------------------------------------- /spec/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "biblio": { 3 | "https://www.unicode.org/glossary": { 4 | "byte-order-mark": "#byte_order_mark", 5 | "leading-surrogate": "#leading_surrogate", 6 | "trailing-surrogate": "#trailing_surrogate", 7 | "supplementary-character": "#supplementary_character", 8 | "supplementary-code-point": "#supplementary_code_point", 9 | "surrogate-code-point": "#surrogate_code_point", 10 | "surrogate-pair": "#surrogate_pair", 11 | "unicode-scalar-value": "#unicode_scalar_value", 12 | "utf-16": "#UTF_16" 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | !!! IMPORTANT !!! 2 | 3 | Before creating your issue: 4 | 5 | - Have a question? Find community resources at https://graphql.org/community/ 6 | 7 | - Find an editing mistake? Create a Pull Request with the edited fix! The Github 8 | UI allows you to edit files directly, find the source files at: 9 | https://github.com/graphql/graphql-spec/tree/master/spec 10 | 11 | - Improvements to documentation? Head over to 12 | https://github.com/graphql/graphql.github.io 13 | 14 | - Feature request? First read 15 | https://github.com/graphql/graphql-spec/blob/master/CONTRIBUTING.md and prefer 16 | creating a Pull Request! 17 | -------------------------------------------------------------------------------- /signed-agreements/README.md: -------------------------------------------------------------------------------- 1 | # Legacy Signed Agreements 2 | 3 | The signed agreement found in this directory was contributed when this 4 | specification was licensed under OWFa 1.0 on September 26, 2017 by Facebook. 5 | 6 | Since then the [GraphQL Foundation](https://graphql.org/foundation/) was formed 7 | in 2019, at which point the GraphQL Specification Project became a 8 | [Joint Development Foundation](https://www.jointdevelopment.org/) project. 9 | 10 | The charter and legal documents currently governing this specification and other 11 | GraphQL projects can be found in the 12 | [GraphQL Foundation repository](https://github.com/graphql/foundation). 13 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | jobs: 10 | test-spelling: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v3 14 | - uses: actions/setup-node@v3 15 | - run: npm ci 16 | - run: npm run test:spelling 17 | test-format: 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: actions/checkout@v3 21 | - uses: actions/setup-node@v3 22 | - run: npm ci 23 | - run: npm run test:format 24 | - run: npm run test:algorithm-format 25 | test-build: 26 | runs-on: ubuntu-latest 27 | steps: 28 | - uses: actions/checkout@v3 29 | - uses: actions/setup-node@v3 30 | - run: npm ci 31 | - run: npm run test:build 32 | publish: 33 | if: github.ref == 'refs/heads/main' 34 | needs: 35 | - test-spelling 36 | - test-format 37 | - test-build 38 | runs-on: ubuntu-latest 39 | steps: 40 | - uses: actions/checkout@v3 41 | with: 42 | fetch-depth: 0 43 | - uses: actions/setup-node@v3 44 | - run: npm ci 45 | - run: npm run build 46 | - uses: peaceiris/actions-gh-pages@v3 47 | with: 48 | github_token: ${{ secrets.GITHUB_TOKEN }} 49 | keep_files: true 50 | cname: spec.graphql.org 51 | user_name: "github-actions[bot]" 52 | user_email: "github-actions[bot]@users.noreply.github.com" 53 | -------------------------------------------------------------------------------- /scripts/update-appendix-specified-definitions.mjs: -------------------------------------------------------------------------------- 1 | import prettier from "prettier"; 2 | import { writeFile } from "node:fs/promises"; 3 | import { 4 | printIntrospectionSchema, 5 | buildSchema, 6 | specifiedScalarTypes, 7 | printType, 8 | parse, 9 | print, 10 | visit, 11 | Kind 12 | } from "graphql"; 13 | 14 | function stripDescriptions(sdl) { 15 | const ast = parse(sdl); 16 | const noDescAst = visit(ast, { 17 | enter: (node) => { 18 | // Not in spec yet 19 | if (node.name?.value === "FRAGMENT_VARIABLE_DEFINITION") { 20 | return null 21 | } 22 | }, 23 | leave: (node) => ({ ...node, description: undefined }) 24 | }); 25 | return print(noDescAst); 26 | } 27 | 28 | function printSpecifiedScalars() { 29 | return specifiedScalarTypes 30 | .map((type) => stripDescriptions(printType(type))) 31 | .join("\n\n"); 32 | } 33 | 34 | const introspectionSchema = stripDescriptions( 35 | printIntrospectionSchema(buildSchema(`type Query { i: Int }`)) 36 | ); 37 | 38 | const allSpecifiedTypesSDL = prettier 39 | .format(printSpecifiedScalars() + "\n\n" + introspectionSchema, { 40 | parser: "graphql" 41 | }) 42 | .trimEnd(); 43 | 44 | await writeFile( 45 | "./spec/Appendix D -- Specified Definitions.md", 46 | `# D. Appendix: Type System Definitions 47 | 48 | This appendix lists all type system definitions specified in this document. 49 | 50 | The order of types, fields, arguments, values and directives is non-normative. 51 | 52 | \`\`\`graphql 53 | ${allSpecifiedTypesSDL} 54 | \`\`\` 55 | ` 56 | ); 57 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "graphql-spec", 3 | "private": true, 4 | "contributors": [ 5 | "Lee Byron (http://leebyron.com/)", 6 | "Nicholas Schrock ", 7 | "Daniel Schafer " 8 | ], 9 | "license": "OWFa-1.0", 10 | "homepage": "https://spec.graphql.org/", 11 | "repository": { 12 | "type": "git", 13 | "url": "http://github.com/graphql/graphql-spec.git" 14 | }, 15 | "scripts": { 16 | "test": "npm run test:spelling && npm run test:format && npm run test:build", 17 | "test:spelling": "cspell \"spec/**/*.md\" README.md LICENSE.md", 18 | "format": "prettier --write \"**/*.{md,yml,yaml,json}\"", 19 | "test:format": "prettier --check \"**/*.{md,yml,yaml,json}\" || npm run suggest:format", 20 | "test:algorithm-format": "node .github/algorithm-format-check.mjs", 21 | "suggest:format": "echo \"\nTo resolve this, run: $(tput bold)npm run format$(tput sgr0)\" && exit 1", 22 | "build": "./build.sh", 23 | "test:build": "spec-md --metadata spec/metadata.json spec/GraphQL.md > /dev/null", 24 | "watch": "nodemon -e json,md --exec \"npm run build\"", 25 | "update-appendix-specified-definitions": "node scripts/update-appendix-specified-definitions.mjs; prettier --write \"spec/Appendix D -- Specified Definitions.md\"" 26 | }, 27 | "devDependencies": { 28 | "cspell": "5.9.1", 29 | "nodemon": "2.0.20", 30 | "prettier": "2.8.2", 31 | "spec-md": "3.1.0", 32 | "graphql": "^17.0.0-alpha.9" 33 | }, 34 | "prettier": { 35 | "proseWrap": "always", 36 | "trailingComma": "none" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # Appendix: Copyright and Licensing 2 | 3 | The GraphQL Specification Project is made available by the 4 | [Joint Development Foundation](https://www.jointdevelopment.org/) Projects, LLC, 5 | GraphQL Series. The current 6 | [Working Group](https://github.com/graphql/graphql-wg) charter, which includes 7 | the IP policy governing all working group deliverables (including 8 | specifications, source code, and datasets) may be found at 9 | [https://technical-charter.graphql.org](https://technical-charter.graphql.org). 10 | 11 | **Copyright Notice** 12 | 13 | Copyright © 2015-2018, Facebook, Inc. 14 | 15 | Copyright © 2019-present, GraphQL contributors 16 | 17 | THESE MATERIALS ARE PROVIDED “AS IS”. The parties expressly disclaim any 18 | warranties (express, implied, or otherwise), including implied warranties of 19 | merchantability, non-infringement, fitness for a particular purpose, or title, 20 | related to the materials. The entire risk as to implementing or otherwise using 21 | the materials is assumed by the implementer and user. IN NO EVENT WILL THE 22 | PARTIES BE LIABLE TO ANY OTHER PARTY FOR LOST PROFITS OR ANY FORM OF INDIRECT, 23 | SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER FROM ANY CAUSES 24 | OF ACTION OF ANY KIND WITH RESPECT TO THIS DELIVERABLE OR ITS GOVERNING 25 | AGREEMENT, WHETHER BASED ON BREACH OF CONTRACT, TORT (INCLUDING NEGLIGENCE), OR 26 | OTHERWISE, AND WHETHER OR NOT THE OTHER MEMBER HAS BEEN ADVISED OF THE 27 | POSSIBILITY OF SUCH DAMAGE. 28 | 29 | **Licensing** 30 | 31 | The licenses for the GraphQL Specification Project are: 32 | 33 | | Deliverable | License | 34 | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | 35 | | Specifications | [Open Web Foundation Agreement 1.0 (Patent and Copyright Grants)](https://www.openwebfoundation.org/the-agreements/the-owf-1-0-agreements-granted-claims/owfa-1-0) | 36 | | Source code | [MIT License](https://opensource.org/licenses/MIT) | 37 | | Data sets | [CC0 1.0](https://creativecommons.org/publicdomain/zero/1.0/) | 38 | -------------------------------------------------------------------------------- /spec/GraphQL.md: -------------------------------------------------------------------------------- 1 | # GraphQL 2 | 3 | _Current Working Draft_ 4 | 5 | **Introduction** 6 | 7 | This is the specification for GraphQL, a query language and execution engine for 8 | describing and performing the capabilities and requirements of data models for 9 | client-server applications. 10 | 11 | A conforming implementation of GraphQL must fulfill all normative requirements 12 | described in this specification (see [Conformance](#sec-Appendix-Conformance)). 13 | The GraphQL specification is provided under the OWFa 1.0 license (see 14 | [Copyright and Licensing](#sec-Appendix-Copyright-and-Licensing)). 15 | 16 | GraphQL was originally created in 2012 and the development of this open standard 17 | started in 2015. It is a deliverable of the 18 | [GraphQL Specification Project](https://graphql.org/community/), established in 19 | 2019 with the [Joint Development Foundation](https://www.jointdevelopment.org/). 20 | 21 | The [GraphQL Foundation](https://graphql.org/foundation/) was formed in 2019 as 22 | a neutral focal point for organizations who support development of the GraphQL 23 | ecosystem. If your organization benefits from GraphQL, please consider 24 | [becoming a member](https://graphql.org/foundation/join/#graphql-foundation). 25 | 26 | This specification is developed on GitHub at 27 | [graphql/graphql-spec](https://github.com/graphql/graphql-spec/). Contributions 28 | are managed by the 29 | [GraphQL Working Group](https://github.com/graphql/graphql-wg), hosted by the 30 | [GraphQL Technical Steering Committee](https://github.com/graphql/graphql-wg/blob/main/GraphQL-TSC.md). 31 | To learn more see the 32 | [contribution guide](https://github.com/graphql/graphql-spec/blob/main/CONTRIBUTING.md). 33 | 34 | GraphQL has evolved and may continue to evolve in future editions of this 35 | specification. Previous editions of the GraphQL specification can be found at 36 | permalinks that match their 37 | [release tag](https://github.com/graphql/graphql-spec/releases). The latest 38 | working draft release can be found at 39 | [https://spec.graphql.org/draft](https://spec.graphql.org/draft). 40 | 41 | # [Overview](Section%201%20--%20Overview.md) 42 | 43 | # [Language](Section%202%20--%20Language.md) 44 | 45 | # [Type System](Section%203%20--%20Type%20System.md) 46 | 47 | # [Introspection](Section%204%20--%20Introspection.md) 48 | 49 | # [Validation](Section%205%20--%20Validation.md) 50 | 51 | # [Execution](Section%206%20--%20Execution.md) 52 | 53 | # [Response](Section%207%20--%20Response.md) 54 | 55 | # [Appendix: Conformance](Appendix%20A%20--%20Conformance.md) 56 | 57 | # [Appendix: Notation Conventions](Appendix%20B%20--%20Notation%20Conventions.md) 58 | 59 | # [Appendix: Grammar Summary](Appendix%20C%20--%20Grammar%20Summary.md) 60 | 61 | # [Appendix: Specified Definitions](Appendix%20D%20--%20Specified%20Definitions.md) 62 | 63 | # [Appendix: Licensing](../LICENSE.md) 64 | -------------------------------------------------------------------------------- /spec/Appendix D -- Specified Definitions.md: -------------------------------------------------------------------------------- 1 | # D. Appendix: Type System Definitions 2 | 3 | This appendix lists all type system definitions specified in this document. 4 | 5 | The order of types, fields, arguments, values and directives is non-normative. 6 | 7 | ```graphql 8 | scalar String 9 | 10 | scalar Int 11 | 12 | scalar Float 13 | 14 | scalar Boolean 15 | 16 | scalar ID 17 | 18 | directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT 19 | 20 | directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT 21 | 22 | directive @deprecated( 23 | reason: String! = "No longer supported" 24 | ) on FIELD_DEFINITION | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION | ENUM_VALUE 25 | 26 | directive @specifiedBy(url: String!) on SCALAR 27 | 28 | directive @oneOf on INPUT_OBJECT 29 | 30 | type __Schema { 31 | description: String 32 | types: [__Type!]! 33 | queryType: __Type! 34 | mutationType: __Type 35 | subscriptionType: __Type 36 | directives: [__Directive!]! 37 | } 38 | 39 | type __Type { 40 | kind: __TypeKind! 41 | name: String 42 | description: String 43 | specifiedByURL: String 44 | fields(includeDeprecated: Boolean! = false): [__Field!] 45 | interfaces: [__Type!] 46 | possibleTypes: [__Type!] 47 | enumValues(includeDeprecated: Boolean! = false): [__EnumValue!] 48 | inputFields(includeDeprecated: Boolean! = false): [__InputValue!] 49 | ofType: __Type 50 | isOneOf: Boolean 51 | } 52 | 53 | enum __TypeKind { 54 | SCALAR 55 | OBJECT 56 | INTERFACE 57 | UNION 58 | ENUM 59 | INPUT_OBJECT 60 | LIST 61 | NON_NULL 62 | } 63 | 64 | type __Field { 65 | name: String! 66 | description: String 67 | args(includeDeprecated: Boolean! = false): [__InputValue!]! 68 | type: __Type! 69 | isDeprecated: Boolean! 70 | deprecationReason: String 71 | } 72 | 73 | type __InputValue { 74 | name: String! 75 | description: String 76 | type: __Type! 77 | defaultValue: String 78 | isDeprecated: Boolean! 79 | deprecationReason: String 80 | } 81 | 82 | type __EnumValue { 83 | name: String! 84 | description: String 85 | isDeprecated: Boolean! 86 | deprecationReason: String 87 | } 88 | 89 | type __Directive { 90 | name: String! 91 | description: String 92 | isRepeatable: Boolean! 93 | locations: [__DirectiveLocation!]! 94 | args(includeDeprecated: Boolean! = false): [__InputValue!]! 95 | } 96 | 97 | enum __DirectiveLocation { 98 | QUERY 99 | MUTATION 100 | SUBSCRIPTION 101 | FIELD 102 | FRAGMENT_DEFINITION 103 | FRAGMENT_SPREAD 104 | INLINE_FRAGMENT 105 | VARIABLE_DEFINITION 106 | SCHEMA 107 | SCALAR 108 | OBJECT 109 | FIELD_DEFINITION 110 | ARGUMENT_DEFINITION 111 | INTERFACE 112 | UNION 113 | ENUM 114 | ENUM_VALUE 115 | INPUT_OBJECT 116 | INPUT_FIELD_DEFINITION 117 | } 118 | ``` 119 | -------------------------------------------------------------------------------- /spec/Appendix A -- Conformance.md: -------------------------------------------------------------------------------- 1 | # A. Appendix: Conformance 2 | 3 | A conforming implementation of GraphQL must fulfill all normative requirements. 4 | Conformance requirements are described in this document via both descriptive 5 | assertions and key words with clearly defined meanings. 6 | 7 | The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", 8 | "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in the normative portions of 9 | this document are to be interpreted as described in 10 | [IETF RFC 2119](https://tools.ietf.org/html/rfc2119). These key words may appear 11 | in lowercase and still retain their meaning unless explicitly declared as 12 | non-normative. 13 | 14 | A conforming implementation of GraphQL may provide additional functionality, but 15 | must not do so where explicitly disallowed or where it would otherwise result in 16 | non-conformance. 17 | 18 | **Conforming Algorithms** 19 | 20 | Algorithm steps phrased in imperative grammar (e.g. "Return the result of 21 | calling resolver") are to be interpreted with the same level of requirement as 22 | the algorithm it is contained within. Any algorithm referenced within an 23 | algorithm step (e.g. "Let completedResult be the result of calling 24 | CompleteValue()") is to be interpreted as having at least the same level of 25 | requirement as the algorithm containing that step. 26 | 27 | Conformance requirements expressed as algorithms and data collections can be 28 | fulfilled by an implementation of this specification in any way as long as the 29 | perceived result is equivalent. Algorithms described in this document are 30 | written to be easy to understand. Implementers are encouraged to include 31 | equivalent but optimized implementations. 32 | 33 | See [Appendix A](#sec-Appendix-Notation-Conventions) for more details about the 34 | definition of algorithms, data collections, and other notational conventions 35 | used in this document. 36 | 37 | **Non-Normative Portions** 38 | 39 | All contents of this document are normative except portions explicitly declared 40 | as non-normative. 41 | 42 | Examples in this document are non-normative, and are presented to aid 43 | understanding of introduced concepts and the behavior of normative portions of 44 | the specification. Examples are either introduced explicitly in prose (e.g. "for 45 | example") or are set apart in example or counterexample blocks, like this: 46 | 47 | ```example 48 | This is an example of a non-normative example. 49 | ``` 50 | 51 | ```counter-example 52 | This is an example of a non-normative counterexample. 53 | ``` 54 | 55 | Notes in this document are non-normative, and are presented to clarify intent, 56 | draw attention to potential edge cases and pitfalls, and answer common questions 57 | that arise during implementation. Notes are either introduced explicitly in 58 | prose (e.g. "Note: ") or are set apart in a note block, like this: 59 | 60 | Note: This is an example of a non-normative note. 61 | -------------------------------------------------------------------------------- /spec/Section 1 -- Overview.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | GraphQL is a query language designed to build client applications by providing 4 | an intuitive and flexible syntax and system for describing their data 5 | requirements and interactions. 6 | 7 | For example, this GraphQL _request_ will receive the name of the user with id 4 8 | from the Facebook implementation of GraphQL. 9 | 10 | ```graphql example 11 | { 12 | user(id: 4) { 13 | name 14 | } 15 | } 16 | ``` 17 | 18 | Which produces the resulting data (in JSON): 19 | 20 | ```json example 21 | { 22 | "user": { 23 | "name": "Mark Zuckerberg" 24 | } 25 | } 26 | ``` 27 | 28 | GraphQL is not a programming language capable of arbitrary computation, but is 29 | instead a language used to make requests to application services that have 30 | capabilities defined in this specification. GraphQL does not mandate a 31 | particular programming language or storage system for application services that 32 | implement it. Instead, application services take their capabilities and map them 33 | to a uniform language, type system, and philosophy that GraphQL encodes. This 34 | provides a unified interface friendly to product development and a powerful 35 | platform for tool-building. 36 | 37 | GraphQL has a number of design principles: 38 | 39 | - **Product-centric**: GraphQL is unapologetically driven by the requirements of 40 | views and the front-end engineers that write them. GraphQL starts with their 41 | way of thinking and requirements and builds the language and runtime necessary 42 | to enable that. 43 | 44 | - **Hierarchical**: Most product development today involves the creation and 45 | manipulation of view hierarchies. To achieve congruence with the structure of 46 | these applications, a GraphQL request itself is structured hierarchically. The 47 | request is shaped just like the data in its response. It is a natural way for 48 | clients to describe data requirements. 49 | 50 | - **Strong-typing**: Every GraphQL service defines an application-specific type 51 | system. Requests are executed within the context of that type system. Given a 52 | GraphQL operation, tools can ensure that it is both syntactically correct and 53 | valid within that type system before execution, i.e. at development time, and 54 | the service can make certain guarantees about the shape and nature of the 55 | response. 56 | 57 | - **Client-specified response**: Through its type system, a GraphQL service 58 | publishes the capabilities that its clients are allowed to consume. It is the 59 | client that is responsible for specifying exactly how it will consume those 60 | published capabilities. These requests are specified at field-level 61 | granularity. In the majority of client-server applications written without 62 | GraphQL, the service determines the shape of data returned from its various 63 | endpoints. A GraphQL response, on the other hand, contains exactly what a 64 | client asks for and no more. 65 | 66 | - **Self-describing**: GraphQL is self-describing and introspective. A GraphQL 67 | service's type system can be queryable by the GraphQL language itself, which 68 | includes readable documentation. GraphQL introspection serves as a powerful 69 | platform for building common developer tools and client software libraries. 70 | 71 | Because of these principles, GraphQL is a powerful and productive environment 72 | for building client applications. Product developers and designers building 73 | applications against working GraphQL services—supported with quality tools—can 74 | quickly become productive without reading extensive documentation and with 75 | little or no formal training. To enable that experience, there must be those 76 | that build those services and tools. 77 | 78 | The following formal specification serves as a reference for those builders. It 79 | describes the language and its grammar, the type system and the introspection 80 | system used to query it, and the execution and validation engines with the 81 | algorithms to power them. The goal of this specification is to provide a 82 | foundation and framework for an ecosystem of GraphQL tools, client libraries, 83 | and service implementations—spanning both organizations and platforms—that has 84 | yet to be built. We look forward to working with the community in order to do 85 | that. 86 | -------------------------------------------------------------------------------- /STYLE_GUIDE.md: -------------------------------------------------------------------------------- 1 | **This document is a work in progress.** 2 | 3 | # GraphQL Specification Style Guide 4 | 5 | This document outlines the styles used in the GraphQL spec to aid editorial and 6 | consistency. The writing style portions are inspired by the AP style guide. When 7 | making changes to the GraphQL specification, please aim to be consistent with 8 | this style guide. 9 | 10 | ## Auto-Formatting 11 | 12 | The GraphQL specification is formatted using the `prettier` tool, so you should 13 | not need to think about gaps between paragraphs and titles, nor about word 14 | wrapping - this is handled for you. 15 | 16 | ## Headings 17 | 18 | The GraphQL specification uses two types of headings: numbered headings and 19 | unnumbered headings. All headings should be written in Title Case (see below). 20 | 21 | ### Numbered Headings 22 | 23 | Lines beginning with a `#` will become numbered headings in the spec-md output. 24 | 25 | ``` 26 | # H1 27 | ## H2 28 | ### H3 29 | #### H4 30 | ##### H5 31 | ``` 32 | 33 | ### Unnumbered Headings 34 | 35 | Unnumbered headings are added to split large blocks of text up without impacting 36 | the spec numbering system. In the output are styled similarly to an H4. An 37 | unnumbered heading is a line on its own that is bolded: 38 | 39 | ```md 40 | \*\*This Is an Example of an Unnumbered Heading\*\* 41 | ``` 42 | 43 | ### Title Case 44 | 45 | Title case is used for headings. Every word in a heading (including words after 46 | hyphens) should be capitalized, with the following exceptions: 47 | 48 | - articles: a, an, the 49 | - conjunctions under 4 letters in length: for, and, nor, but, or, yet, so, as, 50 | if 51 | - prepositions under 4 letters in length: in, at, to, on, off, of, for, vs., per 52 | - directive names and type names are unchanged: @include, @specifiedBy, 53 | \_\_EnumValue, \_\_Schema 54 | 55 | All elements in hyphenated words follow the same rules, e.g. headings may 56 | contain `Non-Null`, `Context-Free`, `Built-in` (`in` is a preposition, so is not 57 | capitalized). 58 | 59 | ## Algorithms 60 | 61 | A named algorithm definition starts with the name of the algorithm in 62 | `PascalCase`, an open parenthesis, a comma-and-space separated list of 63 | arguments, a close parenthesis and then a colon. It is followed by a blank 64 | newline and a list of steps in the algorithm which may be numbered or bulleted. 65 | 66 | Each step in an algorithm should either end in a colon (`:`) with an indented 67 | step on the next line, or a fullstop (`.`). (A step after a step ending in a 68 | full stop may or may not be indented, use your discretion.) 69 | 70 | Indentation in algorithms is significant. 71 | 72 | Every step in an algorithm should start with a capital letter. 73 | 74 | ``` 75 | MyAlgorithm(argOne, argTwo): 76 | 77 | - Let {something} be {true}. 78 | - For each {arg} in {argOne}: 79 | - If {arg} is greater than {argTwo}: 80 | - Let {something} be {false}. 81 | - Otherwise if {arg} is less than {argTwo}: 82 | - Let {something} be {true}. 83 | - Return {something}. 84 | ``` 85 | 86 | ## Definitions 87 | 88 | For important terms, use 89 | [Spec Markdown definition paragraphs](https://spec-md.com/#sec-Definition-Paragraph). 90 | 91 | Definition paragraphs start with `::` and add the matching italicized term to 92 | the [specification index](https://spec.graphql.org/draft/#index), making it easy 93 | to reference them. 94 | 95 | ## Tone of Voice 96 | 97 | The GraphQL specification is a reference document and should use neutral and 98 | descriptive tone of voice. 99 | 100 | **Favor the present tense** 101 | 102 | The present tense is usually clearer and shorter: 103 | 104 | ✅ Present: The client then sends a request to the server. 105 | 106 | ❌ Future: The client will then send a request to the server. 107 | 108 | **Write in the third person** 109 | 110 | The specification should avoid the first person (“we,” “our”) and instead use 111 | the third person or passive constructions when necessary. For example: 112 | 113 | ✅ “The server validates the request against the schema.” 114 | 115 | ❌ “We validate the request against the schema.” 116 | 117 | **Use RFC 2119 keywords** 118 | 119 | The specification should use the normative keywords defined in 120 | [RFC 2119](https://www.rfc-editor.org/rfc/rfc2119) (**MUST**, **MUST NOT**, 121 | **SHOULD**, **SHOULD NOT**, **MAY**). However, in the context of a sentence 122 | these words should be lower-cased (e.g., “must,” “should,” “may”) in context of 123 | a sentence. This avoids unnecessary visual emphasis while preserving normative 124 | meaning. 125 | 126 | ✅ “A query must contain a single root operation type.” 127 | 128 | ❌ “A query MUST contain a single root operation type.” 129 | 130 | **Avoid unnecessary hyphenation** 131 | 132 | Only use hypenated compound words when either commonly used elsewhere in english 133 | or technical writing. Otherwise prefer separate words or a non-hyphenated 134 | compound word, whichever is most commonly accepted. 135 | 136 | ✅ User defined shorthand words are separated by whitespace 137 | 138 | ❌ User-defined short-hand words are separated by white-space 139 | -------------------------------------------------------------------------------- /.github/algorithm-format-check.mjs: -------------------------------------------------------------------------------- 1 | import { readFile, readdir } from "node:fs/promises"; 2 | 3 | const SPEC_DIR = new URL("../spec", import.meta.url).pathname; 4 | 5 | /** @see {@link https://spec-md.com/#sec-Value-Literals} */ 6 | const valueLiteralsRegexp = /\{((?:[^{}]|(?:\{[^{}]*\}))+)\}/g; 7 | 8 | process.exitCode = 0; 9 | const filenames = await readdir(SPEC_DIR); 10 | for (const filename of filenames) { 11 | if (!filename.endsWith(".md")) { 12 | continue; 13 | } 14 | const markdown = await readFile(`${SPEC_DIR}/${filename}`, "utf8"); 15 | 16 | /** 17 | * Not strictly 'lines' since we try and group indented things together as if 18 | * they were one line. Close enough though. 19 | */ 20 | const lines = markdown.split(/\n(?=[\S\n]|\s*(?:-|[0-9]+\.) )/); 21 | 22 | for (let i = 0, l = lines.length; i < l; i++) { 23 | const line = lines[i]; 24 | 25 | // Check algorithm is consistently formatted 26 | { 27 | // Is it an algorithm definition? 28 | const matches = line.match(/^([a-z0-9A-Z]+)(\s*)\(([^)]*)\)(\s*):(\s*)$/); 29 | const grammarMatches = 30 | filename === "Section 2 -- Language.md" && 31 | line.match(/^([A-Za-z0-9]+) ::?\s+((\S).*)$/); 32 | if (matches) { 33 | const [, algorithmName, ns1, _args, ns2, ns3] = matches; 34 | if (ns1 || ns2 || ns3) { 35 | console.log( 36 | `Bad whitespace in definition of ${algorithmName} in '${filename}':` 37 | ); 38 | console.dir(line); 39 | console.log(); 40 | process.exitCode = 1; 41 | } 42 | if (lines[i + 1] !== "") { 43 | console.log( 44 | `No empty space after algorithm ${algorithmName} header in '${filename}'` 45 | ); 46 | console.log(); 47 | process.exitCode = 1; 48 | } 49 | for (let j = i + 2; j < l; j++) { 50 | const step = lines[j]; 51 | if (!step.match(/^\s*(-|[0-9]+\.) /)) { 52 | if (step !== "") { 53 | console.log( 54 | `Bad algorithm ${algorithmName} step in '${filename}':` 55 | ); 56 | console.dir(step); 57 | console.log(); 58 | process.exitCode = 1; 59 | } 60 | break; 61 | } 62 | if (!step.match(/[.:]$/)) { 63 | console.log( 64 | `Bad formatting for '${algorithmName}' step (does not end in '.' or ':') in '${filename}':` 65 | ); 66 | console.dir(step); 67 | console.log(); 68 | process.exitCode = 1; 69 | } 70 | if (step.match(/^\s*(-|[0-9]+\.)\s+[a-z]/)) { 71 | console.log( 72 | `Bad formatting of '${algorithmName}' step (should start with a capital) in '${filename}':` 73 | ); 74 | console.dir(step); 75 | console.log(); 76 | process.exitCode = 1; 77 | } 78 | const assertMatch = step.match(/^\s*(-|[0-9]+\.)\s*Assert([^:])/); 79 | if (assertMatch) { 80 | console.log( 81 | `Bad formatting of '${algorithmName}' step (Assert should be immediately followed by ':'; found '${assertMatch[2]}') in '${filename}':` 82 | ); 83 | console.dir(step); 84 | console.log(); 85 | process.exitCode = 1; 86 | } 87 | 88 | const stepWithoutValueLiterals = step.replace( 89 | valueLiteralsRegexp, 90 | "" 91 | ); 92 | if (stepWithoutValueLiterals.match(/\b[A-Z][A-Za-z0-9]+\(/)) { 93 | console.log( 94 | `Bad formatting of '${algorithmName}' step (algorithm call should be wrapped in braces: \`{MyAlgorithm(a, b, c)}\`) in '${filename}':` 95 | ); 96 | console.dir(step); 97 | console.log(); 98 | process.exitCode = 1; 99 | } 100 | 101 | const valueLiterals = step.matchAll(valueLiteralsRegexp, ""); 102 | for (const lit of valueLiterals) { 103 | const inner = lit[1]; 104 | if (inner.includes("{")) { 105 | console.log( 106 | `Bad formatting of '${algorithmName}' step (algorithm call should not contain braces: \`${lit}\`) in '${filename}':` 107 | ); 108 | console.dir(step); 109 | console.log(); 110 | process.exitCode = 1; 111 | } 112 | } 113 | 114 | const trimmedInnerLine = step.replace(/\s+/g, " "); 115 | if ( 116 | trimmedInnerLine.match( 117 | /(?:[rR]eturn|is (?:not )?)(true|false|null)\b/ 118 | ) && 119 | !trimmedInnerLine.match(/null or empty/) 120 | ) { 121 | console.log( 122 | `Potential bad formatting of '${algorithmName}' step (true/false/null should be wrapped in curly braces, e.g. '{true}') in '${filename}':` 123 | ); 124 | console.dir(step); 125 | console.log(); 126 | process.exitCode = 1; 127 | } 128 | } 129 | } else if (grammarMatches) { 130 | // This is super loosey-goosey 131 | const [, grammarName, rest] = grammarMatches; 132 | if (rest.trim() === "one of") { 133 | // Still grammar, not algorithm 134 | continue; 135 | } 136 | if (rest.trim() === "" && lines[i + 1] !== "") { 137 | console.log( 138 | `No empty space after grammar ${grammarName} header in '${filename}'` 139 | ); 140 | console.log(); 141 | process.exitCode = 1; 142 | } 143 | while (lines[i + 1].trim() !== "") { 144 | // Continuation of definition 145 | i++; 146 | } 147 | if (!lines[i + 2].startsWith("- ")) { 148 | // Not an algorithm; probably more grammar 149 | continue; 150 | } 151 | for (let j = i + 2; j < l; j++) { 152 | const step = lines[j]; 153 | if (!step.match(/^\s*(-|[0-9]+\.) /)) { 154 | if (step !== "") { 155 | console.log(`Bad grammar ${grammarName} step in '${filename}':`); 156 | console.dir(step); 157 | console.log(); 158 | process.exitCode = 1; 159 | } 160 | break; 161 | } 162 | if (!step.match(/[.:]$/)) { 163 | console.log( 164 | `Bad formatting for '${grammarName}' step (does not end in '.' or ':') in '${filename}':` 165 | ); 166 | console.dir(step); 167 | console.log(); 168 | process.exitCode = 1; 169 | } 170 | if (step.match(/^\s*(-|[0-9]\.)\s+[a-z]/)) { 171 | console.log( 172 | `Bad formatting of '${grammarName}' step (should start with a capital) in '${filename}':` 173 | ); 174 | console.dir(step); 175 | console.log(); 176 | process.exitCode = 1; 177 | } 178 | const trimmedInnerLine = step.replace(/\s+/g, " "); 179 | if ( 180 | trimmedInnerLine.match( 181 | /(?:[rR]eturn|is (?:not )?)(true|false|null)\b/ 182 | ) && 183 | !trimmedInnerLine.match(/null or empty/) 184 | ) { 185 | console.log( 186 | `Potential bad formatting of '${grammarName}' step (true/false/null should be wrapped in curly braces, e.g. '{true}') in '${filename}':` 187 | ); 188 | console.dir(step); 189 | console.log(); 190 | process.exitCode = 1; 191 | } 192 | const assertMatch = step.match(/^\s*(-|[0-9]+\.)\s*Assert([^:])/); 193 | if (assertMatch) { 194 | console.log( 195 | `Bad formatting of '${grammarName}' step (Assert should be immediately followed by ':'; found '${assertMatch[2]}') in '${filename}':` 196 | ); 197 | console.dir(step); 198 | console.log(); 199 | process.exitCode = 1; 200 | } 201 | } 202 | } 203 | } 204 | 205 | // Check `- ...:` step is followed by an indent 206 | { 207 | const matches = line.match(/^(\s*)- .*:\s*$/); 208 | if (matches) { 209 | const indent = matches[1]; 210 | const nextLine = lines[i + 1]; 211 | if (!nextLine.startsWith(`${indent} `)) { 212 | console.log( 213 | `Lacking indent in '${filename}' following ':' character:` 214 | ); 215 | console.dir(line); 216 | console.dir(nextLine); 217 | console.log(); 218 | // TODO: process.exitCode = 1; 219 | } 220 | } 221 | } 222 | } 223 | } 224 | 225 | if (process.exitCode === 0) { 226 | console.log(`Everything looks okay!`); 227 | } else { 228 | console.log(`Please resolve the errors detailed above.`); 229 | } 230 | -------------------------------------------------------------------------------- /spec/Appendix B -- Notation Conventions.md: -------------------------------------------------------------------------------- 1 | # B. Appendix: Notation Conventions 2 | 3 | This specification document contains a number of notation conventions used to 4 | describe technical concepts such as language grammar and semantics as well as 5 | runtime algorithms. 6 | 7 | This appendix seeks to explain these notations in greater detail to avoid 8 | ambiguity. 9 | 10 | ## Context-Free Grammar 11 | 12 | A context-free grammar consists of a number of productions. Each production has 13 | an abstract symbol called a "non-terminal" as its left-hand side, and zero or 14 | more possible sequences of non-terminal symbols and/or terminal characters as 15 | its right-hand side. 16 | 17 | Starting from a single goal non-terminal symbol, a context-free grammar 18 | describes a language: the set of possible sequences of characters that can be 19 | described by repeatedly replacing any non-terminal in the goal sequence with one 20 | of the sequences it is defined by, until all non-terminal symbols have been 21 | replaced by terminal characters. 22 | 23 | Terminals are represented in this document in a monospace font in two forms: a 24 | specific Unicode character or sequence of Unicode characters (i.e. {`=`} or 25 | {`terminal`}), and prose typically describing a specific Unicode code point 26 | {"Space (U+0020)"}. Sequences of Unicode characters only appear in syntactic 27 | grammars and represent a {Name} token of that specific sequence. 28 | 29 | Non-terminal production rules are represented in this document using the 30 | following notation for a non-terminal with a single definition: 31 | 32 | NonTerminalWithSingleDefinition : NonTerminal `terminal` 33 | 34 | While using the following notation for a production with a list of definitions: 35 | 36 | NonTerminalWithManyDefinitions : 37 | 38 | - OtherNonTerminal `terminal` 39 | - `terminal` 40 | 41 | A definition may refer to itself, which describes repetitive sequences, for 42 | example: 43 | 44 | ListOfLetterA : 45 | 46 | - ListOfLetterA `a` 47 | - `a` 48 | 49 | ## Lexical and Syntactic Grammar 50 | 51 | The GraphQL language is defined in a syntactic grammar where terminal symbols 52 | are tokens. Tokens are defined in a lexical grammar which matches patterns of 53 | source characters. The result of parsing a source text sequence of Unicode 54 | characters first produces a sequence of lexical tokens according to the lexical 55 | grammar which then produces abstract syntax tree (AST) according to the 56 | syntactic grammar. 57 | 58 | A lexical grammar production describes non-terminal "tokens" by patterns of 59 | terminal Unicode characters. No "whitespace" or other ignored characters may 60 | appear between any terminal Unicode characters in the lexical grammar 61 | production. A lexical grammar production is distinguished by a two colon `::` 62 | definition. 63 | 64 | Word :: Letter+ 65 | 66 | A Syntactic grammar production describes non-terminal "rules" by patterns of 67 | terminal Tokens. {Whitespace} and other {Ignored} sequences may appear before or 68 | after any terminal {Token}. A syntactic grammar production is distinguished by a 69 | one colon `:` definition. 70 | 71 | Sentence : Word+ `.` 72 | 73 | ## Grammar Notation 74 | 75 | This specification uses some additional notation to describe common patterns, 76 | such as optional or repeated patterns, or parameterized alterations of the 77 | definition of a non-terminal. This section explains these shorthand notations 78 | and their expanded definitions in the context-free grammar. 79 | 80 | **Constraints** 81 | 82 | A grammar production may specify that certain expansions are not permitted by 83 | using the phrase "but not" and then indicating the expansions to be excluded. 84 | 85 | For example, the following production means that the non-terminal {SafeWord} may 86 | be replaced by any sequence of characters that could replace {Word} provided 87 | that the same sequence of characters could not replace {SevenCarlinWords}. 88 | 89 | SafeWord : Word but not SevenCarlinWords 90 | 91 | A grammar may also list a number of restrictions after "but not" separated by 92 | "or". 93 | 94 | For example: 95 | 96 | NonBooleanName : Name but not `true` or `false` 97 | 98 | **Lookahead Restrictions** 99 | 100 | A grammar production may specify that certain characters or tokens are not 101 | permitted to follow it by using the pattern {[lookahead != NotAllowed]}. 102 | Lookahead restrictions are often used to remove ambiguity from the grammar. 103 | 104 | The following example makes it clear that {Letter+} must be greedy, since {Word} 105 | cannot be followed by yet another {Letter}. 106 | 107 | Word :: Letter+ [lookahead != Letter] 108 | 109 | **Optionality and Lists** 110 | 111 | A subscript suffix "{Symbol?}" is shorthand for two possible sequences, one 112 | including that symbol and one excluding it. 113 | 114 | As an example: 115 | 116 | Sentence : Noun Verb Adverb? 117 | 118 | is shorthand for 119 | 120 | Sentence : 121 | 122 | - Noun Verb Adverb 123 | - Noun Verb 124 | 125 | A subscript suffix "{Symbol+}" is shorthand for a list of one or more of that 126 | symbol, represented as an additional recursive production. 127 | 128 | As an example: 129 | 130 | Book : Cover Page+ Cover 131 | 132 | is shorthand for 133 | 134 | Book : Cover Page_list Cover 135 | 136 | Page_list : 137 | 138 | - Page_list Page 139 | - Page 140 | 141 | **Parameterized Grammar Productions** 142 | 143 | A symbol definition subscript suffix parameter in braces "{Symbol[Param]}" is 144 | shorthand for two symbol definitions, one appended with that parameter name, the 145 | other without. The same subscript suffix on a symbol is shorthand for that 146 | variant of the definition. If the parameter starts with "?", that form of the 147 | symbol is used if in a symbol definition with the same parameter. Some possible 148 | sequences can be included or excluded conditionally when respectively prefixed 149 | with "\[+Param]" and "\[~Param]". 150 | 151 | As an example: 152 | 153 | Example[Param] : 154 | 155 | - A 156 | - B[Param] 157 | - C[?Param] 158 | - [+Param] D 159 | - [~Param] E 160 | 161 | is shorthand for 162 | 163 | Example : 164 | 165 | - A 166 | - B_param 167 | - C 168 | - E 169 | 170 | Example_param : 171 | 172 | - A 173 | - B_param 174 | - C_param 175 | - D 176 | 177 | ## Grammar Semantics 178 | 179 | This specification describes the semantic value of many grammar productions in 180 | the form of a list of algorithmic steps. 181 | 182 | For example, this describes how a parser should interpret a string literal: 183 | 184 | StringValue :: `""` 185 | 186 | - Return an empty Unicode character sequence. 187 | 188 | StringValue :: `"` StringCharacter+ `"` 189 | 190 | - Return the Unicode character sequence of all {StringCharacter} Unicode 191 | character values. 192 | 193 | ## Algorithms 194 | 195 | This specification describes some algorithms used by the static and runtime 196 | semantics, they're defined in the form of a function-like syntax with the 197 | algorithm's name and the arguments it accepts along with a list of algorithmic 198 | steps to take in the order listed. Each step may establish references to other 199 | values, check various conditions, call other algorithms, and eventually return a 200 | value representing the outcome of the algorithm for the provided arguments. 201 | 202 | For example, the following example describes an algorithm named {Fibonacci} 203 | which accepts a single argument {number}. The algorithm's steps produce the next 204 | number in the Fibonacci sequence: 205 | 206 | Fibonacci(number): 207 | 208 | - If {number} is {0}: 209 | - Return {1}. 210 | - If {number} is {1}: 211 | - Return {2}. 212 | - Let {previousNumber} be {number} - {1}. 213 | - Let {previousPreviousNumber} be {number} - {2}. 214 | - Return {Fibonacci(previousNumber)} + {Fibonacci(previousPreviousNumber)}. 215 | 216 | Note: Algorithms described in this document are written to be easy to 217 | understand. Implementers are encouraged to include observably equivalent but 218 | optimized implementations. 219 | 220 | ## Data Collections 221 | 222 | Algorithms within this specification refer to abstract data collection types to 223 | express normative structural, uniqueness, and ordering requirements. Temporary 224 | data collections internal to an algorithm use these types to best describe 225 | expected behavior, but implementers are encouraged to provide observably 226 | equivalent but optimized implementations. Implementations may use any data 227 | structure as long as the expected requirements are met. 228 | 229 | **List** 230 | 231 | :: A _list_ is an ordered collection of values which may contain duplicates. A 232 | value added to a list is ordered after existing values. 233 | 234 | **Set** 235 | 236 | :: A _set_ is a collection of values which must not contain duplicates. 237 | 238 | :: An _ordered set_ is a set which has a defined order. A value added to an 239 | ordered set, which does not already contain that value, is ordered after 240 | existing values. 241 | 242 | **Map** 243 | 244 | :: A _map_ is a collection of entries, each of which has a key and value. Each 245 | entry has a unique key, and can be directly referenced by that key. 246 | 247 | :: An _ordered map_ is a map which has a defined order. An entry added to an 248 | ordered map, which does not have an entry with that key, is ordered after 249 | existing entries. 250 | 251 | Note: This specification defines ordered data collection only when strictly 252 | required. When an order is observable, implementations should preserve it to 253 | improve output legibility and stability. For example if applying a grammar to an 254 | input string yields a _set_ of elements, serialization should emit those 255 | elements in the same source order. 256 | -------------------------------------------------------------------------------- /spec/Appendix C -- Grammar Summary.md: -------------------------------------------------------------------------------- 1 | # C. Appendix: Grammar Summary 2 | 3 | ## Source Text 4 | 5 | SourceCharacter :: "Any Unicode scalar value" 6 | 7 | ## Ignored Tokens 8 | 9 | Ignored :: 10 | 11 | - UnicodeBOM 12 | - Whitespace 13 | - LineTerminator 14 | - Comment 15 | - Comma 16 | 17 | UnicodeBOM :: "Byte Order Mark (U+FEFF)" 18 | 19 | Whitespace :: 20 | 21 | - "Horizontal Tab (U+0009)" 22 | - "Space (U+0020)" 23 | 24 | LineTerminator :: 25 | 26 | - "New Line (U+000A)" 27 | - "Carriage Return (U+000D)" [lookahead != "New Line (U+000A)"] 28 | - "Carriage Return (U+000D)" "New Line (U+000A)" 29 | 30 | Comment :: `#` CommentChar\* [lookahead != CommentChar] 31 | 32 | CommentChar :: SourceCharacter but not LineTerminator 33 | 34 | Comma :: , 35 | 36 | ## Lexical Tokens 37 | 38 | Token :: 39 | 40 | - Punctuator 41 | - Name 42 | - IntValue 43 | - FloatValue 44 | - StringValue 45 | 46 | Punctuator :: one of ! $ & ( ) ... : = @ [ ] { | } 47 | 48 | Name :: 49 | 50 | - NameStart NameContinue\* [lookahead != NameContinue] 51 | 52 | NameStart :: 53 | 54 | - Letter 55 | - `_` 56 | 57 | NameContinue :: 58 | 59 | - Letter 60 | - Digit 61 | - `_` 62 | 63 | Letter :: one of 64 | 65 | - `A` `B` `C` `D` `E` `F` `G` `H` `I` `J` `K` `L` `M` 66 | - `N` `O` `P` `Q` `R` `S` `T` `U` `V` `W` `X` `Y` `Z` 67 | - `a` `b` `c` `d` `e` `f` `g` `h` `i` `j` `k` `l` `m` 68 | - `n` `o` `p` `q` `r` `s` `t` `u` `v` `w` `x` `y` `z` 69 | 70 | Digit :: one of 71 | 72 | - `0` `1` `2` `3` `4` `5` `6` `7` `8` `9` 73 | 74 | IntValue :: IntegerPart [lookahead != {Digit, `.`, NameStart}] 75 | 76 | IntegerPart :: 77 | 78 | - NegativeSign? 0 79 | - NegativeSign? NonZeroDigit Digit\* 80 | 81 | NegativeSign :: - 82 | 83 | NonZeroDigit :: Digit but not `0` 84 | 85 | FloatValue :: 86 | 87 | - IntegerPart FractionalPart ExponentPart [lookahead != {Digit, `.`, NameStart}] 88 | - IntegerPart FractionalPart [lookahead != {Digit, `.`, NameStart}] 89 | - IntegerPart ExponentPart [lookahead != {Digit, `.`, NameStart}] 90 | 91 | FractionalPart :: . Digit+ 92 | 93 | ExponentPart :: ExponentIndicator Sign? Digit+ 94 | 95 | ExponentIndicator :: one of `e` `E` 96 | 97 | Sign :: one of + - 98 | 99 | StringValue :: 100 | 101 | - `""` [lookahead != `"`] 102 | - `"` StringCharacter+ `"` 103 | - BlockString 104 | 105 | StringCharacter :: 106 | 107 | - SourceCharacter but not `"` or `\` or LineTerminator 108 | - `\u` EscapedUnicode 109 | - `\` EscapedCharacter 110 | 111 | EscapedUnicode :: 112 | 113 | - `{` HexDigit+ `}` 114 | - HexDigit HexDigit HexDigit HexDigit 115 | 116 | HexDigit :: one of 117 | 118 | - `0` `1` `2` `3` `4` `5` `6` `7` `8` `9` 119 | - `A` `B` `C` `D` `E` `F` 120 | - `a` `b` `c` `d` `e` `f` 121 | 122 | EscapedCharacter :: one of `"` `\` `/` `b` `f` `n` `r` `t` 123 | 124 | BlockString :: `"""` BlockStringCharacter\* `"""` 125 | 126 | BlockStringCharacter :: 127 | 128 | - SourceCharacter but not `"""` or `\"""` 129 | - `\"""` 130 | 131 | Note: Block string values are interpreted to exclude blank initial and trailing 132 | lines and uniform indentation with {BlockStringValue()}. 133 | 134 | ## Document Syntax 135 | 136 | Description : StringValue 137 | 138 | Document : Definition+ 139 | 140 | Definition : 141 | 142 | - ExecutableDefinition 143 | - TypeSystemDefinitionOrExtension 144 | 145 | ExecutableDocument : ExecutableDefinition+ 146 | 147 | ExecutableDefinition : 148 | 149 | - OperationDefinition 150 | - FragmentDefinition 151 | 152 | OperationDefinition : 153 | 154 | - Description? OperationType Name? VariablesDefinition? Directives? SelectionSet 155 | - SelectionSet 156 | 157 | OperationType : one of `query` `mutation` `subscription` 158 | 159 | SelectionSet : { Selection+ } 160 | 161 | Selection : 162 | 163 | - Field 164 | - FragmentSpread 165 | - InlineFragment 166 | 167 | Field : Alias? Name Arguments? Directives? SelectionSet? 168 | 169 | Alias : Name : 170 | 171 | Arguments[Const] : ( Argument[?Const]+ ) 172 | 173 | Argument[Const] : Name : Value[?Const] 174 | 175 | FragmentSpread : ... FragmentName Directives? 176 | 177 | InlineFragment : ... TypeCondition? Directives? SelectionSet 178 | 179 | FragmentDefinition : Description? fragment FragmentName TypeCondition 180 | Directives? SelectionSet 181 | 182 | FragmentName : Name but not `on` 183 | 184 | TypeCondition : on NamedType 185 | 186 | Value[Const] : 187 | 188 | - [~Const] Variable 189 | - IntValue 190 | - FloatValue 191 | - StringValue 192 | - BooleanValue 193 | - NullValue 194 | - EnumValue 195 | - ListValue[?Const] 196 | - ObjectValue[?Const] 197 | 198 | BooleanValue : one of `true` `false` 199 | 200 | NullValue : `null` 201 | 202 | EnumValue : Name but not `true`, `false` or `null` 203 | 204 | ListValue[Const] : 205 | 206 | - [ ] 207 | - [ Value[?Const]+ ] 208 | 209 | ObjectValue[Const] : 210 | 211 | - { } 212 | - { ObjectField[?Const]+ } 213 | 214 | ObjectField[Const] : Name : Value[?Const] 215 | 216 | VariablesDefinition : ( VariableDefinition+ ) 217 | 218 | VariableDefinition : Description? Variable : Type DefaultValue? 219 | Directives[Const]? 220 | 221 | Variable : $ Name 222 | 223 | DefaultValue : = Value[Const] 224 | 225 | Type : 226 | 227 | - NamedType 228 | - ListType 229 | - NonNullType 230 | 231 | NamedType : Name 232 | 233 | ListType : [ Type ] 234 | 235 | NonNullType : 236 | 237 | - NamedType ! 238 | - ListType ! 239 | 240 | Directives[Const] : Directive[?Const]+ 241 | 242 | Directive[Const] : @ Name Arguments[?Const]? 243 | 244 | TypeSystemDocument : TypeSystemDefinition+ 245 | 246 | TypeSystemDefinition : 247 | 248 | - SchemaDefinition 249 | - TypeDefinition 250 | - DirectiveDefinition 251 | 252 | TypeSystemExtensionDocument : TypeSystemDefinitionOrExtension+ 253 | 254 | TypeSystemDefinitionOrExtension : 255 | 256 | - TypeSystemDefinition 257 | - TypeSystemExtension 258 | 259 | TypeSystemExtension : 260 | 261 | - SchemaExtension 262 | - TypeExtension 263 | 264 | SchemaDefinition : Description? schema Directives[Const]? { 265 | RootOperationTypeDefinition+ } 266 | 267 | SchemaExtension : 268 | 269 | - extend schema Directives[Const]? { RootOperationTypeDefinition+ } 270 | - extend schema Directives[Const] [lookahead != `{`] 271 | 272 | RootOperationTypeDefinition : OperationType : NamedType 273 | 274 | TypeDefinition : 275 | 276 | - ScalarTypeDefinition 277 | - ObjectTypeDefinition 278 | - InterfaceTypeDefinition 279 | - UnionTypeDefinition 280 | - EnumTypeDefinition 281 | - InputObjectTypeDefinition 282 | 283 | TypeExtension : 284 | 285 | - ScalarTypeExtension 286 | - ObjectTypeExtension 287 | - InterfaceTypeExtension 288 | - UnionTypeExtension 289 | - EnumTypeExtension 290 | - InputObjectTypeExtension 291 | 292 | ScalarTypeDefinition : Description? scalar Name Directives[Const]? 293 | 294 | ScalarTypeExtension : 295 | 296 | - extend scalar Name Directives[Const] 297 | 298 | ObjectTypeDefinition : 299 | 300 | - Description? type Name ImplementsInterfaces? Directives[Const]? 301 | FieldsDefinition 302 | - Description? type Name ImplementsInterfaces? Directives[Const]? [lookahead != 303 | `{`] 304 | 305 | ObjectTypeExtension : 306 | 307 | - extend type Name ImplementsInterfaces? Directives[Const]? FieldsDefinition 308 | - extend type Name ImplementsInterfaces? Directives[Const] [lookahead != `{`] 309 | - extend type Name ImplementsInterfaces [lookahead != `{`] 310 | 311 | ImplementsInterfaces : 312 | 313 | - ImplementsInterfaces & NamedType 314 | - implements `&`? NamedType 315 | 316 | FieldsDefinition : { FieldDefinition+ } 317 | 318 | FieldDefinition : Description? Name ArgumentsDefinition? : Type 319 | Directives[Const]? 320 | 321 | ArgumentsDefinition : ( InputValueDefinition+ ) 322 | 323 | InputValueDefinition : Description? Name : Type DefaultValue? Directives[Const]? 324 | 325 | InterfaceTypeDefinition : 326 | 327 | - Description? interface Name ImplementsInterfaces? Directives[Const]? 328 | FieldsDefinition 329 | - Description? interface Name ImplementsInterfaces? Directives[Const]? 330 | [lookahead != `{`] 331 | 332 | InterfaceTypeExtension : 333 | 334 | - extend interface Name ImplementsInterfaces? Directives[Const]? 335 | FieldsDefinition 336 | - extend interface Name ImplementsInterfaces? Directives[Const] [lookahead != 337 | `{`] 338 | - extend interface Name ImplementsInterfaces [lookahead != `{`] 339 | 340 | UnionTypeDefinition : Description? union Name Directives[Const]? 341 | UnionMemberTypes? 342 | 343 | UnionMemberTypes : 344 | 345 | - UnionMemberTypes | NamedType 346 | - = `|`? NamedType 347 | 348 | UnionTypeExtension : 349 | 350 | - extend union Name Directives[Const]? UnionMemberTypes 351 | - extend union Name Directives[Const] 352 | 353 | EnumTypeDefinition : 354 | 355 | - Description? enum Name Directives[Const]? EnumValuesDefinition 356 | - Description? enum Name Directives[Const]? [lookahead != `{`] 357 | 358 | EnumValuesDefinition : { EnumValueDefinition+ } 359 | 360 | EnumValueDefinition : Description? EnumValue Directives[Const]? 361 | 362 | EnumTypeExtension : 363 | 364 | - extend enum Name Directives[Const]? EnumValuesDefinition 365 | - extend enum Name Directives[Const] [lookahead != `{`] 366 | 367 | InputObjectTypeDefinition : 368 | 369 | - Description? input Name Directives[Const]? InputFieldsDefinition 370 | - Description? input Name Directives[Const]? [lookahead != `{`] 371 | 372 | InputFieldsDefinition : { InputValueDefinition+ } 373 | 374 | InputObjectTypeExtension : 375 | 376 | - extend input Name Directives[Const]? InputFieldsDefinition 377 | - extend input Name Directives[Const] [lookahead != `{`] 378 | 379 | DirectiveDefinition : Description? directive @ Name ArgumentsDefinition? 380 | `repeatable`? on DirectiveLocations 381 | 382 | DirectiveLocations : 383 | 384 | - DirectiveLocations | DirectiveLocation 385 | - `|`? DirectiveLocation 386 | 387 | DirectiveLocation : 388 | 389 | - ExecutableDirectiveLocation 390 | - TypeSystemDirectiveLocation 391 | 392 | ExecutableDirectiveLocation : one of 393 | 394 | - `QUERY` 395 | - `MUTATION` 396 | - `SUBSCRIPTION` 397 | - `FIELD` 398 | - `FRAGMENT_DEFINITION` 399 | - `FRAGMENT_SPREAD` 400 | - `INLINE_FRAGMENT` 401 | - `VARIABLE_DEFINITION` 402 | 403 | TypeSystemDirectiveLocation : one of 404 | 405 | - `SCHEMA` 406 | - `SCALAR` 407 | - `OBJECT` 408 | - `FIELD_DEFINITION` 409 | - `ARGUMENT_DEFINITION` 410 | - `INTERFACE` 411 | - `UNION` 412 | - `ENUM` 413 | - `ENUM_VALUE` 414 | - `INPUT_OBJECT` 415 | - `INPUT_FIELD_DEFINITION` 416 | 417 | ## Schema Coordinate Syntax 418 | 419 | Note: Schema coordinates must not contain {Ignored}. 420 | 421 | SchemaCoordinateToken :: 422 | 423 | - SchemaCoordinatePunctuator 424 | - Name 425 | 426 | SchemaCoordinatePunctuator :: one of ( ) . : @ 427 | 428 | SchemaCoordinate :: 429 | 430 | - TypeCoordinate 431 | - MemberCoordinate 432 | - ArgumentCoordinate 433 | - DirectiveCoordinate 434 | - DirectiveArgumentCoordinate 435 | 436 | TypeCoordinate :: Name 437 | 438 | MemberCoordinate :: Name . Name 439 | 440 | ArgumentCoordinate :: Name . Name ( Name : ) 441 | 442 | DirectiveCoordinate :: @ Name 443 | 444 | DirectiveArgumentCoordinate :: @ Name ( Name : ) 445 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # GraphQL Specification Contribution Guide 2 | 3 | GraphQL is still an evolving language. This repository contains the 4 | specification text as well as Pull Requests with suggested improvements and 5 | contributions. 6 | 7 | Contributions that do not change the interpretation of the spec but instead 8 | improve legibility, fix editorial errors, clear up ambiguity and improve 9 | examples are encouraged. These "editorial changes" will normally be given the 10 | ["✏ Editorial" label](https://github.com/graphql/graphql-spec/issues?q=sort%3Aupdated-desc+is%3Aopen+label%3A%22%E2%9C%8F%EF%B8%8F+Editorial%22) 11 | and are often merged by a spec editor with little process. 12 | 13 | However, contributions that _do_ meaningfully change the interpretation of the 14 | spec must follow an RFC (Request For Comments) process led by a _champion_ 15 | through a series of _stages_ intended to improve _visibility_, allow for 16 | _discussion_ to reach the best solution, and arrive at _consensus_. This process 17 | becomes ever more important as GraphQL's community broadens. 18 | 19 | When proposing or weighing-in on any issue or pull request, consider the 20 | [Code of Conduct](https://github.com/graphql/foundation/blob/main/CODE-OF-CONDUCT.md) 21 | to better understand expected and unacceptable behavior. 22 | 23 | ## Contributing to GraphQL Libraries 24 | 25 | A common point of confusion for those who wish to contribute to GraphQL is where 26 | to start. In fact, you may have found yourself here after attempting to make an 27 | improvement to a GraphQL library. Should a new addition be made to the GraphQL 28 | spec first or a GraphQL library first? Admittedly, this can become a bit of a 29 | [chicken-or-egg](https://en.wikipedia.org/wiki/Chicken_or_the_egg) dilemma. 30 | 31 | GraphQL libraries seek to be "spec compliant", which means they discourage 32 | changes that cause them to behave differently from the spec as written. However, 33 | they also encourage pull requests for changes that accompany an RFC _proposal_ 34 | or RFC _draft_. In fact, a spec contribution RFC won't be _accepted_ until it 35 | has experience being implemented in a GraphQL library. 36 | 37 | To allow a library to remain spec compliant while also implementing _proposals_ 38 | and _drafts_, the library's maintainers may request that these new features are 39 | disabled by default with opt-in option flags or they may simply wait to merge a 40 | well-tested pull request until the spec proposal is _accepted_. 41 | 42 | ## Guiding Principles 43 | 44 | GraphQL's evolution is guided by a few principles. Suggested contributions 45 | should use these principles to guide the details of an RFC and decisions to move 46 | forward. See editor Lee Byron talk about 47 | [guiding principles at GraphQL Europe 2017](https://youtu.be/mePT9MNTM98?t=17m9s). 48 | 49 | - **Backwards compatibility** 50 | 51 | Once a query is written, it should always mean the same thing and return the 52 | same shaped result. Future changes should not change the meaning of existing 53 | schema or requests or in any other way cause an existing compliant GraphQL 54 | service to become non-compliant for prior versions of the spec. 55 | 56 | - **Performance is a feature** 57 | 58 | GraphQL typically avoids syntax or behaviors that could jeopardize runtime 59 | efficiency, or that make demands of GraphQL services which cannot efficiently 60 | be fulfilled. 61 | 62 | - **Favor no change** 63 | 64 | As GraphQL is implemented in over a dozen languages under the collaboration of 65 | hundreds of individuals, incorporating any change has a high cost. 66 | Accordingly, proposed changes must meet a very high bar of added value. The 67 | burden of proof is on the contributor to illustrate this value. 68 | 69 | - **Enable new capabilities motivated by real use cases** 70 | 71 | Every change should intend on unlocking a real and reasonable use case. Real 72 | examples are always more compelling than theoretical ones, and common 73 | scenarios are more compelling than rare ones. RFCs should do more than offer a 74 | different way to reach an already achievable outcome. 75 | 76 | - **Simplicity and consistency over expressiveness and terseness** 77 | 78 | Plenty of behaviors and patterns found in other languages are intentionally 79 | absent from GraphQL. "Possible but awkward" is often favored over more complex 80 | alternatives. Simplicity (e.g. fewer concepts) is more important than 81 | expressing more sophisticated ideas or writing less. 82 | 83 | - **Preserve option value** 84 | 85 | It's hard to know what the future brings; whenever possible, decisions should 86 | be made that allow for more options in the future. Sometimes this is 87 | unintuitive: spec rules often begin more strict than necessary with a future 88 | option to loosen when motivated by a real use case. 89 | 90 | - **Understandability is just as important as correctness** 91 | 92 | The GraphQL spec, despite describing technical behavior, is intended to be 93 | read by people. Use natural tone and include motivation and examples. 94 | 95 | ## RFC Contribution Champions 96 | 97 | Contributing to GraphQL requires a lot of dedicated work. To set clear 98 | expectations and provide accountability, each proposed RFC (request for 99 | comments) must have a _champion_ who is responsible for addressing feedback and 100 | completing next steps. An RFC may have multiple _champions_. The spec editors 101 | are not responsible for completing RFCs which lack a _champion_ (though an 102 | editor may be a _champion_ for an RFC). 103 | 104 | An RFC which does not have a _champion_ may not progress through stages, and can 105 | become stale. Stale proposals may be picked up by a new _champion_ or may be 106 | _rejected_. 107 | 108 | ## RFC Contribution Stages 109 | 110 | RFCs are guided by a _champion_ through a series of stages: _strawman_, 111 | _proposal_, _draft_, and _accepted_ (or _rejected_), each of which has suggested 112 | entrance criteria and next steps detailed below. RFCs typically advance one 113 | stage at a time, but may advance multiple stages at a time. Stage advancements 114 | typically occur during [Working Group](https://github.com/graphql/graphql-wg) 115 | meetings, but may also occur on GitHub. 116 | 117 | In general, it's preferable to start with a pull request so that we can best 118 | evaluate the RFC in detail. However, starting with an issue is also permitted if 119 | the full details are not worked out. 120 | 121 | All RFCs start as either a _strawman_ or _proposal_. 122 | 123 | ## Stage 0: _Strawman_ 124 | 125 | An RFC at the _strawman_ stage captures a described problem or 126 | partially-considered solutions. A _strawman_ does not need to meet any entrance 127 | criteria. A _strawman's_ goal is to prove or disprove a problem and guide 128 | discussion towards either rejection or a preferred solution. A _strawman_ may be 129 | an issue or a pull request (though an illustrative pull request is preferrable). 130 | 131 | _There is no entrance criteria for a Strawman_ 132 | 133 | As implied by the name 134 | [strawman](https://en.wikipedia.org/wiki/Straw_man_proposal), the goal at this 135 | stage is to knock it down (_reject_) by considering other possible related 136 | solutions, showing that the motivating problem can be solved with no change to 137 | the specification, or that it is not aligned with the _guiding principles_. 138 | 139 | Once determined that the _strawman_ is compelling, it should seek the entrance 140 | criteria for _proposal_. 141 | 142 | ## Stage 1: _Proposal_ 143 | 144 | An RFC at the _proposal_ stage is a solution to a problem with enough fidelity 145 | to be discussed in detail. It must be backed by a willing _champion_. A 146 | _proposal_'s goal is to make a compelling case for acceptance by describing both 147 | the problem and the solution via examples and spec edits. A _proposal_ should be 148 | a pull request. 149 | 150 | _Entrance criteria:_ 151 | 152 | - Identified _champion_ 153 | - Clear explanation of problem and solution 154 | - Illustrative examples 155 | - Incomplete spec edits 156 | - Identification of potential concerns, challenges, and drawbacks 157 | 158 | A _proposal_ is subject to the same discussion as a _strawman_: ensuring that it 159 | is well aligned with the _guiding principles_, is a problem worth solving, and 160 | is the preferred solution to that problem. A _champion_ is not expected to have 161 | confidence in every detail at this stage and should instead focus on identifying 162 | and resolving issues and edge-cases. To better understand the technical 163 | ramifications of the _proposal_, a _champion_ is encouraged to implement it in a 164 | GraphQL library. 165 | 166 | Most _proposals_ are expected to evolve or change and may be rejected. 167 | Therefore, it is unwise to rely on a _proposal_ in a production GraphQL service. 168 | GraphQL libraries _may_ implement _proposals_, though are encouraged to not 169 | enable the _proposed_ feature without explicit opt-in. 170 | 171 | ## Stage 2: _Draft_ 172 | 173 | An RFC at the _draft_ stage is a fully formed solution. There is working group 174 | consensus the problem identified should be solved, and this particular solution 175 | is preferred. A _draft's_ goal is to precisely and completely describe the 176 | solution and resolve any concerns through library implementations. A _draft_ 177 | must be a pull request. 178 | 179 | _Entrance criteria:_ 180 | 181 | - Consensus the solution is preferred (typically via Working Group) 182 | - Resolution of identified concerns and challenges 183 | - Precisely described with spec edits 184 | - Compliant implementation in GraphQL.js (might not be merged) 185 | 186 | A _proposal_ becomes a _draft_ when the set of problems or drawbacks have been 187 | fully considered and accepted or resolved, and the solution is deemed desirable. 188 | A _draft_'s goal is to complete final spec edits that are ready to be merged and 189 | implement the _draft_ in GraphQL libraries along with tests to gain confidence 190 | that the spec text is sufficient. 191 | 192 | _Drafts_ may continue to evolve and change, occasionally dramatically, and are 193 | not guaranteed to be accepted. Therefore, it is unwise to rely on a _draft_ in a 194 | production GraphQL Service. GraphQL libraries _should_ implement _drafts_ to 195 | provide valuable feedback, though are encouraged not to enable the _draft_ 196 | feature without explicit opt-in when possible. 197 | 198 | ## Stage 3: _Accepted_ 199 | 200 | An RFC at the _accepted_ stage is a completed solution. According to a spec 201 | editor it is ready to be merged as-is into the spec document. The RFC is ready 202 | to be deployed in GraphQL libraries. An _accepted_ RFC must be implemented in 203 | GraphQL.js. 204 | 205 | _Entrance criteria:_ 206 | 207 | - Consensus the solution is complete (via editor or working group) 208 | - Complete spec edits, including examples and prose 209 | - Compliant implementation in GraphQL.js (fully tested and merged or ready to 210 | merge) 211 | 212 | A _draft_ is _accepted_ when the working group or editor has been convinced via 213 | implementations and tests that it appropriately handles all edge cases; that the 214 | spec changes not only precisely describe the new syntax and semantics but 215 | include sufficient motivating prose and examples; and that the RFC includes 216 | edits to any other affected areas of the spec. Once _accepted_, its _champion_ 217 | should encourage adoption of the RFC by opening issues or pull requests on other 218 | popular GraphQL libraries. 219 | 220 | An _accepted_ RFC is merged into the GraphQL spec's main branch by an editor and 221 | will be included in the next released revision. 222 | 223 | ## Stage X: _Rejected_ 224 | 225 | An RFC may be _rejected_ at any point and for any reason. Most rejections occur 226 | when a _strawman_ is proven to be unnecessary, is misaligned with the _guiding 227 | principles_, or fails to meet the entrance criteria to become a _proposal_. A 228 | _proposal_ may become _rejected_ for similar reasons as well as if it fails to 229 | reach consensus or loses the confidence of its _champion_. Likewise a _draft_ 230 | may encounter unforeseen issues during implementations which cause it to lose 231 | consensus or the confidence of its _champion_. 232 | 233 | RFCs which have lost a _champion_ will not be _rejected_ immediately, but may 234 | become _rejected_ if they fail to attract a new _champion_. 235 | 236 | Once _rejected_, an RFC will typically not be reconsidered. Reconsideration is 237 | possible if a _champion_ believes the original reason for rejection no longer 238 | applies due to new circumstances or new evidence. 239 | -------------------------------------------------------------------------------- /scripts/generate-contributor-list.mjs: -------------------------------------------------------------------------------- 1 | import { execFileSync } from "node:child_process"; 2 | import https from "node:https"; 3 | 4 | // ---------- flags / utils 5 | const RAW_ARGS = process.argv.slice(2); 6 | const DEBUG = RAW_ARGS.includes("--debug"); 7 | const logd = (...xs) => { if (DEBUG) console.error(...xs) }; 8 | 9 | const collator = new Intl.Collator("en", { sensitivity: "base" }); 10 | const cmp = (a, b) => collator.compare(a, b); 11 | const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); 12 | const toLower = (s) => (s || "").toLowerCase(); 13 | function die(msg, code = 1) { console.error(msg); process.exit(code) } 14 | 15 | function normalizeName(s) { 16 | return (s || "") 17 | .normalize("NFKD") 18 | .replace(/\p{Diacritic}/gu, "") 19 | .replace(/\s+/g, " ") 20 | .trim() 21 | .toLowerCase(); 22 | } 23 | function pickBetterName(current, candidate) { 24 | if (!current) return (candidate || "").trim(); 25 | const c = current.trim(); 26 | const d = (candidate || "").trim(); 27 | if (!c && d) return d; 28 | const spaceC = /\s/.test(c), spaceD = /\s/.test(d); 29 | if (spaceD && !spaceC) return d; 30 | if (d.length > c.length) return d; 31 | return c; 32 | } 33 | function sanitizeDisplayName(raw, fallback) { 34 | const s = (raw || "").trim(); 35 | if (!s) return fallback; 36 | if (/moved\s+to\s+@/i.test(s)) return fallback; 37 | if (/@/.test(s)) return fallback; 38 | if (/^\s*[-–—]+\s*$/.test(s)) return fallback; 39 | return s; 40 | } 41 | 42 | function parseArgs() { 43 | const args = RAW_ARGS.filter(x => x !== "--debug"); 44 | if (args.length === 0) die("Usage: node scripts/generate-contributor-list.mjs [-- ] [--debug]"); 45 | const dd = args.indexOf("--"); 46 | return { range: args[0], paths: dd === -1 ? [] : args.slice(dd + 1) }; 47 | } 48 | 49 | function execGit(argv, opts = {}) { 50 | try { 51 | return execFileSync("git", argv, { encoding: "utf8", maxBuffer: 1024 * 1024 * 400, ...opts }); 52 | } catch (e) { 53 | die(`git ${argv.join(" ")} failed: ${e.message}`); 54 | } 55 | } 56 | function repoNameWithOwner() { 57 | let url = ""; 58 | try { url = execGit(["remote", "get-url", "origin"]).trim(); } catch { } 59 | const m = url.match(/github\.com[:/](?[^/]+)\/(?[^/]+?)(?:\.git)?$/i); 60 | if (m?.groups) return `${m.groups.owner}/${m.groups.repo}`; 61 | die("Could not determine GitHub repo from 'origin' remote."); 62 | } 63 | function revList(range, paths) { 64 | const args = ["rev-list", range]; 65 | if (paths.length) args.push("--", ...paths); 66 | const out = execGit(args); 67 | return out.split(/\r?\n/).filter(Boolean); 68 | } 69 | function parseCoAuthorLines(message) { 70 | const out = []; 71 | const re = /^[ \t]*Co-authored-by:\s*(.+?)\s*<([^>]+)>/gim; 72 | let m; 73 | while ((m = re.exec(message))) out.push({ name: m[1].trim(), email: m[2].trim() }); 74 | return out; 75 | } 76 | function loginFromNoreply(email) { 77 | const m = email.toLowerCase().match(/^(?:\d+\+)?([a-z0-9-]+)@users\.noreply\.github\.com$/i); 78 | return m ? m[1] : ""; 79 | } 80 | function candidateHandlesFromEmailAndName(email, name) { 81 | const cands = new Set(); 82 | const local = email.split("@")[0]; 83 | const bare = local.replace(/[._]/g, ""); 84 | const bareNoDigits = bare.replace(/\d+$/, ""); 85 | cands.add(bare); cands.add(bareNoDigits); 86 | const parts = local.split(/[._-]+/).filter(Boolean); 87 | if (parts.length >= 2) { 88 | const first = parts[0], last = parts[parts.length - 1]; 89 | cands.add(`${first}${last}`); 90 | cands.add(`${first}-${last}`); 91 | cands.add(`${first}_${last}`); 92 | cands.add(`${first[0]}${last}`); 93 | if (last.length >= 3) cands.add(`${first}${last.slice(0, 3)}`); 94 | } 95 | const nameParts = name.split(/\s+/).filter(Boolean); 96 | if (nameParts.length >= 2) { 97 | const f = nameParts[0].replace(/[^A-Za-z0-9-]/g, ""); 98 | const l = nameParts[nameParts.length - 1].replace(/[^A-Za-z0-9-]/g, ""); 99 | if (f && l) { 100 | cands.add(`${f}${l}`); 101 | cands.add(`${f}-${l}`); 102 | cands.add(`${f[0]}${l}`); 103 | } 104 | } 105 | const q = name.match(/'([^']{1,39})'/); if (q) cands.add(q[1]); 106 | const p = name.match(/\(([^) ]{1,39})\)/); if (p) cands.add(p[1]); 107 | return Array.from(cands).filter(s => /^[A-Za-z0-9-]{2,39}$/.test(s)); 108 | } 109 | 110 | // ---------- GraphQL 111 | const REPO = repoNameWithOwner(); 112 | const [OWNER, NAME] = REPO.split("/"); 113 | function getToken() { 114 | const env = process.env.GITHUB_TOKEN || process.env.GH_TOKEN || ""; 115 | if (env) return env; 116 | try { return execFileSync("gh", ["auth", "token"], { encoding: "utf8" }).trim(); } catch { return ""; } 117 | } 118 | const TOKEN = getToken(); 119 | if (!TOKEN) console.error("Warning: no GITHUB_TOKEN/GH_TOKEN (or gh auth token). Resolution will be limited."); 120 | 121 | async function graphql(query, variables) { 122 | const body = JSON.stringify(variables ? { query, variables } : { query }); 123 | const options = { 124 | hostname: "api.github.com", 125 | path: "/graphql", 126 | method: "POST", 127 | headers: { 128 | "User-Agent": "contributors-table-graphql", 129 | "Authorization": `Bearer ${TOKEN}`, 130 | "Content-Type": "application/json", 131 | "Content-Length": Buffer.byteLength(body), 132 | }, 133 | }; 134 | return await new Promise((resolve) => { 135 | const req = https.request(options, (res) => { 136 | let data = ""; 137 | res.setEncoding("utf8"); 138 | res.on("data", (c) => (data += c)); 139 | res.on("end", () => { 140 | try { 141 | const json = JSON.parse(data || "{}"); 142 | if (json.errors && DEBUG) console.error("GraphQL errors:", JSON.stringify(json.errors, null, 2)); 143 | resolve(json); 144 | } catch { resolve({}); } 145 | }); 146 | }); 147 | req.on("error", () => resolve({})); 148 | req.write(body); 149 | req.end(); 150 | }); 151 | } 152 | 153 | // Batch fetch commit author + message for SHAs; count primary-author occurrences per login 154 | async function fetchCommitsByOidBatch(oids) { 155 | const out = new Map(); // oid -> { login | "", name, email, message } 156 | const authorCount = new Map(); // login -> # of primary authored commits in range 157 | const chunkSize = 40; 158 | for (let i = 0; i < oids.length; i += chunkSize) { 159 | const chunk = oids.slice(i, i + chunkSize); 160 | const fields = chunk.map((oid, idx) => ` 161 | c${idx}: object(oid: "${oid}") { 162 | ... on Commit { 163 | message 164 | author { user { login } name email } 165 | } 166 | }`).join("\n"); 167 | const q = `query($owner:String!, $name:String!) { repository(owner:$owner, name:$name) { ${fields} } }`; 168 | const res = await graphql(q, { owner: OWNER, name: NAME }); 169 | const repo = res?.data?.repository || {}; 170 | for (let idx = 0; idx < chunk.length; idx++) { 171 | const node = repo[`c${idx}`]; 172 | if (!node) continue; 173 | const info = { 174 | login: node?.author?.user?.login || "", 175 | name: node?.author?.name || "", 176 | email: node?.author?.email || "", 177 | message: node?.message || "", 178 | }; 179 | out.set(chunk[idx], info); 180 | const L = info.login; 181 | if (L) authorCount.set(L, (authorCount.get(L) || 0) + 1); 182 | } 183 | } 184 | return { commitInfo: out, authorCount }; 185 | } 186 | 187 | // GraphQL user search helpers (users only) 188 | async function searchUsersByNameExact(name) { 189 | if (!TOKEN) return ""; 190 | const queryStr = `"${name.replace(/"/g, '\\"')}" in:name type:user`; 191 | const q = `query($q:String!){ search(type: USER, query: $q, first: 25) { nodes { ... on User { login name } } } }`; 192 | const r = await graphql(q, { q: queryStr }); 193 | const nodes = r?.data?.search?.nodes ?? []; 194 | const target = normalizeName(name); 195 | for (const it of nodes) { 196 | if (!it?.login) continue; 197 | if (normalizeName(it.name || "") === target) return it.login; 198 | } 199 | return ""; 200 | } 201 | async function searchUsersByLoginToken(token) { 202 | if (!TOKEN) return ""; 203 | const q = `query($q:String!){ search(type: USER, query: $q, first: 5) { nodes { ... on User { login name } } } }`; 204 | const r = await graphql(q, { q: `${token} in:login type:user` }); 205 | const items = r?.data?.search?.nodes ?? []; 206 | if (items.length === 1) return items[0]?.login || ""; 207 | return ""; 208 | } 209 | async function fetchProfileNames(logins) { 210 | const out = new Map(); 211 | const chunkSize = 40; 212 | for (let i = 0; i < logins.length; i += chunkSize) { 213 | const chunk = logins.slice(i, i + chunkSize); 214 | const fields = chunk.map((login, idx) => `u${idx}: user(login: "${login}") { login name }`).join("\n"); 215 | const q = `query { ${fields} }`; 216 | const r = await graphql(q); 217 | const data = r?.data || {}; 218 | for (let idx = 0; idx < chunk.length; idx++) { 219 | const u = data[`u${idx}`]; 220 | out.set(chunk[idx], (u?.name || "").trim()); 221 | } 222 | } 223 | return out; 224 | } 225 | 226 | // ---------- main 227 | async function main() { 228 | const { range, paths } = parseArgs(); 229 | 230 | const shas = revList(range, paths); 231 | if (!shas.length) die("No commits in the specified range/path."); 232 | 233 | // 1) Commit info + primary author counts 234 | const { commitInfo, authorCount } = await fetchCommitsByOidBatch(shas); 235 | 236 | // 2) Collect authors and co-authors 237 | const loginBestName = new Map(); // login -> name hint 238 | const pool = []; // [{ name, email }] to resolve (co-authors + primaries with missing login) 239 | 240 | for (const sha of shas) { 241 | const info = commitInfo.get(sha); 242 | if (!info) continue; 243 | const { login, name, email, message } = info; 244 | 245 | if (login) { 246 | loginBestName.set(login, pickBetterName(loginBestName.get(login) || "", name)); 247 | } else { 248 | const guess = loginFromNoreply(email); 249 | if (guess) loginBestName.set(guess, pickBetterName(loginBestName.get(guess) || "", name)); 250 | else pool.push({ name, email }); 251 | } 252 | for (const ca of parseCoAuthorLines(message)) pool.push(ca); 253 | } 254 | 255 | // 3) Resolve pool (GraphQL users search only) 256 | const emailToLogin = new Map(); // emailLower -> login 257 | const concurrency = 8; 258 | let idx = 0; 259 | 260 | async function worker() { 261 | while (idx < pool.length) { 262 | const i = idx++; 263 | const { name, email } = pool[i]; 264 | const ekey = toLower(email); 265 | if (emailToLogin.has(ekey)) continue; 266 | 267 | let login = loginFromNoreply(email); 268 | if (!login) login = await searchUsersByNameExact(name); 269 | if (!login) { 270 | const cands = candidateHandlesFromEmailAndName(email, name); 271 | for (const cand of cands) { 272 | const solo = await searchUsersByLoginToken(cand); 273 | if (solo) { login = solo; break; } 274 | } 275 | } 276 | if (!login && DEBUG) logd(`Unresolved: "${name}" <${email}>`); 277 | emailToLogin.set(ekey, login || ""); 278 | if (login) loginBestName.set(login, pickBetterName(loginBestName.get(login) || "", name)); 279 | 280 | if (i % 10 === 0) await sleep(60); 281 | } 282 | } 283 | await Promise.all(Array.from({ length: concurrency }, worker)); 284 | 285 | // 4) Build candidate rows (resolved only), fetch profile names 286 | const resolvedLogins = Array.from(loginBestName.keys()); 287 | const profileNames = await fetchProfileNames(resolvedLogins); 288 | 289 | const candidates = resolvedLogins.map(login => { 290 | const prof = (profileNames.get(login) || "").trim(); 291 | const hint = (loginBestName.get(login) || "").trim(); 292 | const display = sanitizeDisplayName(prof || hint || login, prof || login); 293 | return { login, display, authorCommits: authorCount.get(login) || 0 }; 294 | }); 295 | 296 | // 5) Collapse duplicate people with the same display name 297 | const byDisplay = new Map(); // normName -> best candidate 298 | const score = (x) => (x.authorCommits > 0 ? 2 : 0) + (x.display.toLowerCase() !== x.login.toLowerCase() ? 1 : 0); 299 | for (const c of candidates) { 300 | const key = normalizeName(c.display); 301 | if (!byDisplay.has(key)) { byDisplay.set(key, c); continue; } 302 | const cur = byDisplay.get(key); 303 | if (score(c) > score(cur) || (score(c) === score(cur) && c.login.toLowerCase() < cur.login.toLowerCase())) { 304 | if (DEBUG) logd(`Collapsed duplicate "${c.display}": keeping ${c.login} over ${cur.login}`); 305 | byDisplay.set(key, c); 306 | } 307 | } 308 | const resolvedRows = Array.from(byDisplay.values()) 309 | .filter((v, i, arr) => arr.findIndex(x => x.login.toLowerCase() === v.login.toLowerCase()) === i) 310 | .map(({ display, login }) => ({ name: display, gh: `[@${login}](https://github.com/${login})`, login })); 311 | 312 | // 6) Unmatched → show email (dedupe by name+email) 313 | const unmatched = []; 314 | const seenUnk = new Set(); 315 | for (const { name, email } of pool) { 316 | const login = emailToLogin.get(toLower(email)); 317 | if (login) continue; 318 | const nm = sanitizeDisplayName(name || "(Unknown)", name || "(Unknown)"); 319 | const key = normalizeName(nm) + "|" + email.toLowerCase(); 320 | if (seenUnk.has(key)) continue; 321 | seenUnk.add(key); 322 | unmatched.push({ name: nm, gh: email, login: "" }); 323 | } 324 | 325 | // 7) Merge, sort, output 326 | const allRows = [...resolvedRows, ...unmatched]; 327 | allRows.sort((a, b) => cmp(a.name, b.name)); 328 | 329 | console.log("| Author | Github"); 330 | console.log("| ----------------------------- | ---------------------------------"); 331 | for (const r of allRows) { 332 | console.log(`| ${r.name} | ${r.gh}`); 333 | } 334 | } 335 | 336 | main().catch((e) => die(String(e))); 337 | -------------------------------------------------------------------------------- /spec/Section 7 -- Response.md: -------------------------------------------------------------------------------- 1 | # Response 2 | 3 | When a GraphQL service receives a _request_, it must return a well-formed 4 | response. The service's response describes the result of executing the requested 5 | operation if successful, and describes any errors raised during the request. 6 | 7 | A response may contain both a partial response as well as a list of errors in 8 | the case that any _execution error_ was raised and replaced with {null}. 9 | 10 | ## Response Format 11 | 12 | :: A GraphQL request returns a _response_. A _response_ is either an _execution 13 | result_, a _response stream_, or a _request error result_. 14 | 15 | ### Execution Result 16 | 17 | :: A GraphQL request returns an _execution result_ when the GraphQL operation is 18 | a query or mutation and the request included execution. Additionally, for each 19 | event in a subscription's _source stream_, the _response stream_ will emit an 20 | _execution result_. 21 | 22 | An _execution result_ must be a map. 23 | 24 | The _execution result_ must contain an entry with key {"data"}. The value of 25 | this entry is described in the "Data" section. 26 | 27 | If execution raised any errors, the _execution result_ must contain an entry 28 | with key {"errors"}. The value of this entry must be a non-empty list of 29 | _execution error_ raised during execution. Each error must be a map as described 30 | in the "Errors" section below. If the request completed without raising any 31 | errors, this entry must not be present. 32 | 33 | Note: When {"errors"} is present in an _execution result_, it may be helpful for 34 | it to appear first when serialized to make it more apparent that errors are 35 | present. 36 | 37 | The _execution result_ may also contain an entry with key `extensions`. The 38 | value of this entry is described in the "Extensions" section. 39 | 40 | ### Response Stream 41 | 42 | :: A GraphQL request returns a _response stream_ when the GraphQL operation is a 43 | subscription and the request included execution. A response stream must be a 44 | stream of _execution result_. 45 | 46 | ### Request Error Result 47 | 48 | :: A GraphQL request returns a _request error result_ when one or more _request 49 | error_ are raised, causing the request to fail before execution. This request 50 | will result in no response data. 51 | 52 | Note: A _request error_ may be raised before execution due to missing 53 | information, syntax errors, validation failure, coercion failure, or any other 54 | reason the implementation may determine should prevent the request from 55 | proceeding. 56 | 57 | A _request error result_ must be a map. 58 | 59 | The _request error result_ map must contain an entry with key {"errors"}. The 60 | value of this entry must be a non-empty list of _request error_ raised during 61 | the _request_. It must contain at least one _request error_ indicating why no 62 | data was able to be returned. Each error must be a map as described in the 63 | "Errors" section below. 64 | 65 | Note: It may be helpful for the {"errors"} key to appear first when serialized 66 | to make it more apparent that errors are present. 67 | 68 | The _request error result_ map must not contain an entry with key {"data"}. 69 | 70 | The _request error result_ map may also contain an entry with key `extensions`. 71 | The value of this entry is described in the "Extensions" section. 72 | 73 | ### Response Position 74 | 75 | 76 | 77 | 78 | 79 | :: A _response position_ is a uniquely identifiable position in the response 80 | data produced during execution. It is either a direct entry in the {resultMap} 81 | of a {ExecuteSelectionSet()}, or it is a position in a (potentially nested) List 82 | value. Each response position is uniquely identifiable via a _response path_. 83 | 84 | :: A _response path_ uniquely identifies a _response position_ via a list of 85 | path segments (response names or list indices) starting at the root of the 86 | response and ending with the associated response position. 87 | 88 | The value for a _response path_ must be a list of path segments. Path segments 89 | that represent field _response name_ must be strings, and path segments that 90 | represent list indices must be 0-indexed integers. If a path segment is 91 | associated with an aliased field it must use the aliased name, since it 92 | represents a path in the response, not in the request. 93 | 94 | When a _response path_ is present on an _error result_, it identifies the 95 | _response position_ which raised the error. 96 | 97 | A single field execution may result in multiple response positions. For example, 98 | 99 | ```graphql example 100 | { 101 | hero(episode: $episode) { 102 | name 103 | friends { 104 | name 105 | } 106 | } 107 | } 108 | ``` 109 | 110 | The hero's name would be found in the _response position_ identified by the 111 | _response path_ `["hero", "name"]`. The List of the hero's friends would be 112 | found at `["hero", "friends"]`, the hero's first friend at 113 | `["hero", "friends", 0]` and that friend's name at 114 | `["hero", "friends", 0, "name"]`. 115 | 116 | ### Data 117 | 118 | The {"data"} entry in the _execution result_ will be the result of the execution 119 | of the requested operation. If the operation was a query, this output will be an 120 | object of the query root operation type; if the operation was a mutation, this 121 | output will be an object of the mutation root operation type. 122 | 123 | The response data is the result of accumulating the resolved result of all 124 | response positions during execution. 125 | 126 | If an error was raised before execution begins, the _response_ must be a 127 | _request error result_ which will result in no response data. 128 | 129 | If an error was raised during the execution that prevented a valid response, the 130 | {"data"} entry in the response should be `null`. 131 | 132 | ### Errors 133 | 134 | The {"errors"} entry in the _execution result_ or _request error result_ is a 135 | non-empty list of errors raised during the _request_, where each error is a map 136 | of data described by the error result format below. 137 | 138 | **Request Errors** 139 | 140 | :: A _request error_ is an error raised during a _request_ which results in no 141 | response data. Typically raised before execution begins, a request error may 142 | occur due to a parse grammar or validation error in the _Document_, an inability 143 | to determine which operation to execute, or invalid input values for variables. 144 | 145 | A request error is typically the fault of the requesting client. 146 | 147 | If a request error is raised, the _response_ must be a _request error result_. 148 | The {"data"} entry in this map must not be present, the {"errors"} entry must 149 | include the error, and request execution should be halted. 150 | 151 | **Execution Errors** 152 | 153 | 154 | 155 | 156 | 157 | :: An _execution error_ is an error raised during the execution of a particular 158 | field which results in partial response data. This may occur due to failure to 159 | coerce the arguments for the field, an internal error during value resolution, 160 | or failure to coerce the resulting value. 161 | 162 | Note: In previous versions of this specification _execution error_ was called 163 | _field error_. 164 | 165 | An execution error is typically the fault of a GraphQL service. 166 | 167 | An _execution error_ must occur at a specific _response position_, and may occur 168 | in any response position. The response position of an execution error is 169 | indicated via a _response path_ in the error response's {"path"} entry. 170 | 171 | When an execution error is raised at a given _response position_, then that 172 | response position must not be present within the _response_ {"data"} entry 173 | (except {null}), and the {"errors"} entry must include the error. Nested 174 | execution is halted and sibling execution attempts to continue, producing 175 | partial result (see 176 | [Handling Execution Errors](#sec-Handling-Execution-Errors)). 177 | 178 | **Error Result Format** 179 | 180 | Every error must contain an entry with the key {"message"} with a string 181 | description of the error intended for the developer as a guide to understand and 182 | correct the error. 183 | 184 | If an error can be associated to a particular point in the requested GraphQL 185 | document, it should contain an entry with the key {"locations"} with a list of 186 | locations, where each location is a map with the keys {"line"} and {"column"}, 187 | both positive numbers starting from `1` which describe the beginning of an 188 | associated syntax element. 189 | 190 | If an error can be associated to a particular field in the GraphQL result, it 191 | must contain an entry with the key {"path"} with a _response path_ which 192 | describes the _response position_ which raised the error. This allows clients to 193 | identify whether a {null} resolved result is a true value or the result of an 194 | _execution error_. 195 | 196 | For example, if fetching one of the friends' names fails in the following 197 | operation: 198 | 199 | ```graphql example 200 | { 201 | hero(episode: $episode) { 202 | name 203 | heroFriends: friends { 204 | id 205 | name 206 | } 207 | } 208 | } 209 | ``` 210 | 211 | The response might look like: 212 | 213 | ```json example 214 | { 215 | "errors": [ 216 | { 217 | "message": "Name for character with ID 1002 could not be fetched.", 218 | "locations": [{ "line": 6, "column": 7 }], 219 | "path": ["hero", "heroFriends", 1, "name"] 220 | } 221 | ], 222 | "data": { 223 | "hero": { 224 | "name": "R2-D2", 225 | "heroFriends": [ 226 | { 227 | "id": "1000", 228 | "name": "Luke Skywalker" 229 | }, 230 | { 231 | "id": "1002", 232 | "name": null 233 | }, 234 | { 235 | "id": "1003", 236 | "name": "Leia Organa" 237 | } 238 | ] 239 | } 240 | } 241 | } 242 | ``` 243 | 244 | If the field which experienced an error was declared as `Non-Null`, the `null` 245 | result will bubble up to the next nullable field. In that case, the `path` for 246 | the error should include the full path to the result field where the error was 247 | raised, even if that field is not present in the response. 248 | 249 | For example, if the `name` field from above had declared a `Non-Null` return 250 | type in the schema, the result would look different but the error reported would 251 | be the same: 252 | 253 | ```json example 254 | { 255 | "errors": [ 256 | { 257 | "message": "Name for character with ID 1002 could not be fetched.", 258 | "locations": [{ "line": 6, "column": 7 }], 259 | "path": ["hero", "heroFriends", 1, "name"] 260 | } 261 | ], 262 | "data": { 263 | "hero": { 264 | "name": "R2-D2", 265 | "heroFriends": [ 266 | { 267 | "id": "1000", 268 | "name": "Luke Skywalker" 269 | }, 270 | null, 271 | { 272 | "id": "1003", 273 | "name": "Leia Organa" 274 | } 275 | ] 276 | } 277 | } 278 | } 279 | ``` 280 | 281 | GraphQL services may provide an additional entry to errors with key 282 | `extensions`. This entry, if set, must have a map as its value. This entry is 283 | reserved for implementers to add additional information to errors however they 284 | see fit, and there are no additional restrictions on its contents. 285 | 286 | ```json example 287 | { 288 | "errors": [ 289 | { 290 | "message": "Name for character with ID 1002 could not be fetched.", 291 | "locations": [{ "line": 6, "column": 7 }], 292 | "path": ["hero", "heroFriends", 1, "name"], 293 | "extensions": { 294 | "code": "CAN_NOT_FETCH_BY_ID", 295 | "timestamp": "Fri Feb 9 14:33:09 UTC 2018" 296 | } 297 | } 298 | ] 299 | } 300 | ``` 301 | 302 | GraphQL services should not provide any additional entries to the error format 303 | since they could conflict with additional entries that may be added in future 304 | versions of this specification. 305 | 306 | Note: Previous versions of this spec did not describe the `extensions` entry for 307 | error formatting. While non-specified entries are not violations, they are still 308 | discouraged. 309 | 310 | ```json counter-example 311 | { 312 | "errors": [ 313 | { 314 | "message": "Name for character with ID 1002 could not be fetched.", 315 | "locations": [{ "line": 6, "column": 7 }], 316 | "path": ["hero", "heroFriends", 1, "name"], 317 | "code": "CAN_NOT_FETCH_BY_ID", 318 | "timestamp": "Fri Feb 9 14:33:09 UTC 2018" 319 | } 320 | ] 321 | } 322 | ``` 323 | 324 | ### Extensions 325 | 326 | The {"extensions"} entry in an _execution result_ or _request error result_, if 327 | set, must have a map as its value. This entry is reserved for implementers to 328 | extend the protocol however they see fit, and hence there are no additional 329 | restrictions on its contents. 330 | 331 | ### Additional Entries 332 | 333 | To ensure future changes to the protocol do not break existing services and 334 | clients, the _execution result_ and _request error result_ maps must not contain 335 | any entries other than those described above. Clients must ignore any entries 336 | other than those described above. 337 | 338 | ## Serialization Format 339 | 340 | GraphQL does not require a specific serialization format. However, clients 341 | should use a serialization format that supports the major primitives in the 342 | GraphQL response. In particular, the serialization format must at least support 343 | representations of the following four primitives: 344 | 345 | - Map 346 | - List 347 | - String 348 | - Null 349 | 350 | A serialization format should also support the following primitives, each 351 | representing one of the common GraphQL scalar types, however a string or simpler 352 | primitive may be used as a substitute if any are not directly supported: 353 | 354 | - Boolean 355 | - Int 356 | - Float 357 | - Enum Value 358 | 359 | This is not meant to be an exhaustive list of what a serialization format may 360 | encode. For example custom scalars representing a Date, Time, URI, or number 361 | with a different precision may be represented in whichever relevant format a 362 | given serialization format may support. 363 | 364 | ### JSON Serialization 365 | 366 | JSON is the most common serialization format for GraphQL. Though as mentioned 367 | above, GraphQL does not require a specific serialization format. 368 | 369 | When using JSON as a serialization of GraphQL responses, the following JSON 370 | values should be used to encode the related GraphQL values: 371 | 372 | | GraphQL Value | JSON Value | 373 | | ------------- | ----------------- | 374 | | Map | Object | 375 | | List | Array | 376 | | Null | {null} | 377 | | String | String | 378 | | Boolean | {true} or {false} | 379 | | Int | Number | 380 | | Float | Number | 381 | | Enum Value | String | 382 | 383 | Note: For consistency and ease of notation, examples of responses are given in 384 | JSON format throughout this document. 385 | 386 | ### Serialized Map Ordering 387 | 388 | Since the result of evaluating a _selection set_ is ordered, the serialized Map 389 | of results should preserve this order by writing the map entries in the same 390 | order as those fields were requested as defined by selection set execution. 391 | Producing a serialized response where fields are represented in the same order 392 | in which they appear in the request improves human readability during debugging 393 | and enables more efficient parsing of responses if the order of properties can 394 | be anticipated. 395 | 396 | Serialization formats which represent an ordered map should preserve the order 397 | of requested fields as defined by {CollectFields()} in the Execution section. 398 | Serialization formats which only represent unordered maps but where order is 399 | still implicit in the serialization's textual order (such as JSON) should 400 | preserve the order of requested fields textually. 401 | 402 | For example, if the request was `{ name, age }`, a GraphQL service responding in 403 | JSON should respond with `{ "name": "Mark", "age": 30 }` and should not respond 404 | with `{ "age": 30, "name": "Mark" }`. 405 | 406 | While JSON Objects are specified as an 407 | [unordered collection of key-value pairs](https://tools.ietf.org/html/rfc7159#section-4) 408 | the pairs are represented in an ordered manner. In other words, while the JSON 409 | strings `{ "name": "Mark", "age": 30 }` and `{ "age": 30, "name": "Mark" }` 410 | encode the same value, they also have observably different property orderings. 411 | 412 | Note: This does not violate the JSON spec, as clients may still interpret 413 | objects in the response as unordered Maps and arrive at a valid value. 414 | -------------------------------------------------------------------------------- /spec/Section 4 -- Introspection.md: -------------------------------------------------------------------------------- 1 | # Introspection 2 | 3 | A GraphQL service supports introspection over its schema. This schema is queried 4 | using GraphQL itself, creating a powerful platform for tool-building. 5 | 6 | Take an example request for a trivial app. In this case there is a User type 7 | with three fields: id, name, and birthday. 8 | 9 | For example, given a service with the following type definition: 10 | 11 | ```graphql example 12 | type User { 13 | id: String 14 | name: String 15 | birthday: Date 16 | } 17 | ``` 18 | 19 | A request containing the operation: 20 | 21 | ```graphql example 22 | { 23 | __type(name: "User") { 24 | name 25 | fields { 26 | name 27 | type { 28 | name 29 | } 30 | } 31 | } 32 | } 33 | ``` 34 | 35 | would produce the result: 36 | 37 | ```json example 38 | { 39 | "__type": { 40 | "name": "User", 41 | "fields": [ 42 | { 43 | "name": "id", 44 | "type": { "name": "String" } 45 | }, 46 | { 47 | "name": "name", 48 | "type": { "name": "String" } 49 | }, 50 | { 51 | "name": "birthday", 52 | "type": { "name": "Date" } 53 | } 54 | ] 55 | } 56 | } 57 | ``` 58 | 59 | **Reserved Names** 60 | 61 | Types and fields required by the GraphQL introspection system that are used in 62 | the same context as user defined types and fields are prefixed with {"\_\_"} 63 | (two underscores), in order to avoid naming collisions with user defined GraphQL 64 | types. 65 | 66 | Otherwise, any {Name} within a GraphQL type system must not start with two 67 | underscores {"\_\_"}. 68 | 69 | ## Type Name Introspection 70 | 71 | GraphQL supports type name introspection within any _selection set_ in an 72 | operation, with the single exception of selections at the root of a subscription 73 | operation. Type name introspection is accomplished via the meta-field 74 | `__typename: String!` on any Object, Interface, or Union. It returns the name of 75 | the concrete Object type at that point during execution. 76 | 77 | This is most often used when querying against Interface or Union types to 78 | identify which actual Object type of the possible types has been returned. 79 | 80 | As a meta-field, `__typename` is implicit and does not appear in the fields list 81 | in any defined type. 82 | 83 | Note: `__typename` may not be included as a root field in a subscription 84 | operation. 85 | 86 | ## Schema Introspection 87 | 88 | The schema introspection system is accessible from the meta-fields `__schema` 89 | and `__type` which are accessible from the type of the root of a query 90 | operation. 91 | 92 | ```graphql 93 | __schema: __Schema! 94 | __type(name: String!): __Type 95 | ``` 96 | 97 | Like all meta-fields, these are implicit and do not appear in the fields list in 98 | the root type of the query operation. 99 | 100 | **First Class Documentation** 101 | 102 | All types in the introspection system provide a `description` field of type 103 | `String` to allow type designers to publish documentation in addition to 104 | capabilities. A GraphQL service may return the `description` field using 105 | Markdown syntax (as specified by [CommonMark](https://commonmark.org/)). 106 | Therefore it is recommended that any tool that displays `description` use a 107 | CommonMark-compliant Markdown renderer. 108 | 109 | **Deprecation** 110 | 111 | To support the management of backwards compatibility, GraphQL fields, arguments, 112 | input fields, and enum values can indicate whether or not they are deprecated 113 | (`isDeprecated: Boolean!`) along with a description of why it is deprecated 114 | (`deprecationReason: String`). 115 | 116 | Tools built using GraphQL introspection should respect deprecation by 117 | discouraging deprecated use through information hiding or developer-facing 118 | warnings. 119 | 120 | **Stable Ordering** 121 | 122 | The observable order of all data collections should be preserved to improve 123 | schema legibility and stability. When a schema is produced from a 124 | {TypeSystemDocument}, introspection should return items in the same source order 125 | for each element list: object fields, input object fields, arguments, enum 126 | values, directives, union member types, and implemented interfaces. 127 | 128 | **Schema Introspection Schema** 129 | 130 | The schema introspection system is itself represented as a GraphQL schema. Below 131 | are the full set of type system definitions providing schema introspection, 132 | which are fully defined in the sections below. 133 | 134 | ```graphql 135 | type __Schema { 136 | description: String 137 | types: [__Type!]! 138 | queryType: __Type! 139 | mutationType: __Type 140 | subscriptionType: __Type 141 | directives: [__Directive!]! 142 | } 143 | 144 | type __Type { 145 | kind: __TypeKind! 146 | name: String 147 | description: String 148 | # may be non-null for custom SCALAR, otherwise null. 149 | specifiedByURL: String 150 | # must be non-null for OBJECT and INTERFACE, otherwise null. 151 | fields(includeDeprecated: Boolean! = false): [__Field!] 152 | # must be non-null for OBJECT and INTERFACE, otherwise null. 153 | interfaces: [__Type!] 154 | # must be non-null for INTERFACE and UNION, otherwise null. 155 | possibleTypes: [__Type!] 156 | # must be non-null for ENUM, otherwise null. 157 | enumValues(includeDeprecated: Boolean! = false): [__EnumValue!] 158 | # must be non-null for INPUT_OBJECT, otherwise null. 159 | inputFields(includeDeprecated: Boolean! = false): [__InputValue!] 160 | # must be non-null for NON_NULL and LIST, otherwise null. 161 | ofType: __Type 162 | # must be non-null for INPUT_OBJECT, otherwise null. 163 | isOneOf: Boolean 164 | } 165 | 166 | enum __TypeKind { 167 | SCALAR 168 | OBJECT 169 | INTERFACE 170 | UNION 171 | ENUM 172 | INPUT_OBJECT 173 | LIST 174 | NON_NULL 175 | } 176 | 177 | type __Field { 178 | name: String! 179 | description: String 180 | args(includeDeprecated: Boolean! = false): [__InputValue!]! 181 | type: __Type! 182 | isDeprecated: Boolean! 183 | deprecationReason: String 184 | } 185 | 186 | type __InputValue { 187 | name: String! 188 | description: String 189 | type: __Type! 190 | defaultValue: String 191 | isDeprecated: Boolean! 192 | deprecationReason: String 193 | } 194 | 195 | type __EnumValue { 196 | name: String! 197 | description: String 198 | isDeprecated: Boolean! 199 | deprecationReason: String 200 | } 201 | 202 | type __Directive { 203 | name: String! 204 | description: String 205 | isRepeatable: Boolean! 206 | locations: [__DirectiveLocation!]! 207 | args(includeDeprecated: Boolean! = false): [__InputValue!]! 208 | } 209 | 210 | enum __DirectiveLocation { 211 | QUERY 212 | MUTATION 213 | SUBSCRIPTION 214 | FIELD 215 | FRAGMENT_DEFINITION 216 | FRAGMENT_SPREAD 217 | INLINE_FRAGMENT 218 | VARIABLE_DEFINITION 219 | SCHEMA 220 | SCALAR 221 | OBJECT 222 | FIELD_DEFINITION 223 | ARGUMENT_DEFINITION 224 | INTERFACE 225 | UNION 226 | ENUM 227 | ENUM_VALUE 228 | INPUT_OBJECT 229 | INPUT_FIELD_DEFINITION 230 | } 231 | ``` 232 | 233 | ### The \_\_Schema Type 234 | 235 | The `__Schema` type is returned from the `__schema` meta-field and provides all 236 | information about the schema of a GraphQL service. 237 | 238 | Fields\: 239 | 240 | - `description` may return a String or {null}. 241 | - `queryType` is the root type of a query operation. 242 | - `mutationType` is the root type of a mutation operation, if supported. 243 | Otherwise {null}. 244 | - `subscriptionType` is the root type of a subscription operation, if supported. 245 | Otherwise {null}. 246 | - `types` must return the set of all named types contained within this schema. 247 | Any named type which can be found through a field of any introspection type 248 | must be included in this set. 249 | - `directives` must return the set of all directives available within this 250 | schema including all built-in directives. 251 | 252 | ### The \_\_Type Type 253 | 254 | `__Type` is at the core of the type introspection system. It represents all 255 | types in the system: both named types (e.g. Scalars and Object types) and type 256 | modifiers (e.g. List and Non-Null types). 257 | 258 | Type modifiers are used to modify the type presented in the field `ofType`. This 259 | modified type may recursively be a modified type, representing a list or 260 | non-null type, and combinations thereof, ultimately modifying a named type. 261 | 262 | There are several different kinds of type. In each kind, different fields are 263 | actually valid. All possible kinds are listed in the `__TypeKind` enum. 264 | 265 | Each sub-section below defines the expected fields of `__Type` given each 266 | possible value of the `__TypeKind` enum: 267 | 268 | - {"SCALAR"} 269 | - {"OBJECT"} 270 | - {"INTERFACE"} 271 | - {"UNION"} 272 | - {"ENUM"} 273 | - {"INPUT_OBJECT"} 274 | - {"LIST"} 275 | - {"NON_NULL"} 276 | 277 | **Scalar** 278 | 279 | Represents scalar types such as Int, String, and Boolean. Scalars cannot have 280 | fields. 281 | 282 | Also represents [Custom scalars](#sec-Scalars.Custom-Scalars) which may provide 283 | `specifiedByURL` as a _scalar specification URL_. 284 | 285 | Fields\: 286 | 287 | - `kind` must return `__TypeKind.SCALAR`. 288 | - `name` must return a String. 289 | - `description` may return a String or {null}. 290 | - `specifiedByURL` may return a String (in the form of a URL) for custom 291 | scalars, otherwise must be {null}. 292 | - All other fields must return {null}. 293 | 294 | **Object** 295 | 296 | Object types represent concrete instantiations of sets of fields. The 297 | introspection types (e.g. `__Type`, `__Field`, etc.) are examples of objects. 298 | 299 | Fields\: 300 | 301 | - `kind` must return `__TypeKind.OBJECT`. 302 | - `name` must return a String. 303 | - `description` may return a String or {null}. 304 | - `fields` must return the set of fields that can be selected for this type. 305 | - Accepts the argument `includeDeprecated` which defaults to {false}. If 306 | {true}, deprecated fields are also returned. 307 | - `interfaces` must return the set of interfaces that an object implements (if 308 | none, `interfaces` must return the empty set). 309 | - All other fields must return {null}. 310 | 311 | **Union** 312 | 313 | Unions are an abstract type where no common fields are declared. The possible 314 | types of a union are explicitly listed out in `possibleTypes`. An object type 315 | can be a member of a union without modification to that type. 316 | 317 | Fields\: 318 | 319 | - `kind` must return `__TypeKind.UNION`. 320 | - `name` must return a String. 321 | - `description` may return a String or {null}. 322 | - `possibleTypes` returns the list of types that can be represented within this 323 | union. They must be object types. 324 | - All other fields must return {null}. 325 | 326 | **Interface** 327 | 328 | Interfaces are an abstract type where there are common fields declared. Any type 329 | that implements an interface must define all the named fields where each 330 | implementing field type is equal to or a sub-type of (covariant) the interface 331 | type. The implementations of this interface are explicitly listed out in 332 | `possibleTypes`. 333 | 334 | Fields\: 335 | 336 | - `kind` must return `__TypeKind.INTERFACE`. 337 | - `name` must return a String. 338 | - `description` may return a String or {null}. 339 | - `fields` must return the set of fields required by this interface. 340 | - Accepts the argument `includeDeprecated` which defaults to {false}. If 341 | {true}, deprecated fields are also returned. 342 | - `interfaces` must return the set of interfaces that an interface implements 343 | (if none, `interfaces` must return the empty set). 344 | - `possibleTypes` returns the list of types that implement this interface. They 345 | must be object types. 346 | - All other fields must return {null}. 347 | 348 | **Enum** 349 | 350 | Enums are special scalars that can only have a defined set of values. 351 | 352 | Fields\: 353 | 354 | - `kind` must return `__TypeKind.ENUM`. 355 | - `name` must return a String. 356 | - `description` may return a String or {null}. 357 | - `enumValues` must return the set of enum values as a list of `__EnumValue`. 358 | There must be at least one and they must have unique names. 359 | - Accepts the argument `includeDeprecated` which defaults to {false}. If 360 | {true}, deprecated enum values are also returned. 361 | - All other fields must return {null}. 362 | 363 | **Input Object** 364 | 365 | Input objects are composite types defined as a list of named input values. They 366 | are only used as inputs to arguments and variables and cannot be a field return 367 | type. 368 | 369 | For example the input object `Point` could be defined as: 370 | 371 | ```graphql example 372 | input Point { 373 | x: Int 374 | y: Int 375 | } 376 | ``` 377 | 378 | Fields\: 379 | 380 | - `kind` must return `__TypeKind.INPUT_OBJECT`. 381 | - `name` must return a String. 382 | - `description` may return a String or {null}. 383 | - `inputFields` must return the set of input fields as a list of `__InputValue`. 384 | - Accepts the argument `includeDeprecated` which defaults to {false}. If 385 | {true}, deprecated input fields are also returned. 386 | - `isOneOf` must return {true} when representing a _OneOf Input Object_, 387 | otherwise {false}. 388 | - All other fields must return {null}. 389 | 390 | **List** 391 | 392 | Lists represent sequences of values in GraphQL. A List type is a type modifier: 393 | it wraps another type instance in the `ofType` field, which defines the type of 394 | each item in the list. 395 | 396 | The modified type in the `ofType` field may itself be a modified type, allowing 397 | the representation of Lists of Lists, or Lists of Non-Nulls. 398 | 399 | Fields\: 400 | 401 | - `kind` must return `__TypeKind.LIST`. 402 | - `ofType` must return a type of any kind. 403 | - All other fields must return {null}. 404 | 405 | **Non-Null** 406 | 407 | GraphQL types are nullable. The value {null} is a valid response for field type. 408 | 409 | A Non-Null type is a type modifier: it wraps another type instance in the 410 | `ofType` field. Non-null types do not allow {null} as a response, and indicate 411 | required inputs for arguments and input object fields. 412 | 413 | The modified type in the `ofType` field may itself be a modified List type, 414 | allowing the representation of Non-Null of Lists. However it must not be a 415 | modified Non-Null type to avoid a redundant Non-Null of Non-Null. 416 | 417 | Fields\: 418 | 419 | - `kind` must return `__TypeKind.NON_NULL`. 420 | - `ofType` must return a type of any kind except Non-Null. 421 | - All other fields must return {null}. 422 | 423 | ### The \_\_Field Type 424 | 425 | The `__Field` type represents each field in an Object or Interface type. 426 | 427 | Fields\: 428 | 429 | - `name` must return a String. 430 | - `description` may return a String or {null}. 431 | - `args` returns a List of `__InputValue` representing the arguments this field 432 | accepts. 433 | - Accepts the argument `includeDeprecated` which defaults to {false}. If 434 | {true}, deprecated arguments are also returned. 435 | - `type` must return a `__Type` that represents the type of value returned by 436 | this field. 437 | - `isDeprecated` returns {true} if this field should no longer be used, 438 | otherwise {false}. 439 | - `deprecationReason` returns the reason why this field is deprecated, or null 440 | if this field is not deprecated. 441 | 442 | ### The \_\_InputValue Type 443 | 444 | The `__InputValue` type represents field and directive arguments as well as the 445 | `inputFields` of an input object. 446 | 447 | Fields\: 448 | 449 | - `name` must return a String. 450 | - `description` may return a String or {null}. 451 | - `type` must return a `__Type` that represents the type this input value 452 | expects. 453 | - `defaultValue` may return a String encoding (using the GraphQL language) of 454 | the default value used by this input value in the condition a value is not 455 | provided at runtime. If this input value has no default value, returns {null}. 456 | - `isDeprecated` returns {true} if this input field or argument should no longer 457 | be used, otherwise {false}. 458 | - `deprecationReason` returns the reason why this input field or argument is 459 | deprecated, or null if the input field or argument is not deprecated. 460 | 461 | ### The \_\_EnumValue Type 462 | 463 | The `__EnumValue` type represents one of possible values of an enum. 464 | 465 | Fields\: 466 | 467 | - `name` must return a String. 468 | - `description` may return a String or {null}. 469 | - `isDeprecated` returns {true} if this enum value should no longer be used, 470 | otherwise {false}. 471 | - `deprecationReason` returns the reason why this enum value is deprecated, or 472 | null if the enum value is not deprecated. 473 | 474 | ### The \_\_Directive Type 475 | 476 | The `__Directive` type represents a directive that a service supports. 477 | 478 | This includes both any _built-in directive_ and any _custom directive_. 479 | 480 | Individual directives may only be used in locations that are explicitly 481 | supported. All possible locations are listed in the `__DirectiveLocation` enum: 482 | 483 | - {"QUERY"} 484 | - {"MUTATION"} 485 | - {"SUBSCRIPTION"} 486 | - {"FIELD"} 487 | - {"FRAGMENT_DEFINITION"} 488 | - {"FRAGMENT_SPREAD"} 489 | - {"INLINE_FRAGMENT"} 490 | - {"VARIABLE_DEFINITION"} 491 | - {"SCHEMA"} 492 | - {"SCALAR"} 493 | - {"OBJECT"} 494 | - {"FIELD_DEFINITION"} 495 | - {"ARGUMENT_DEFINITION"} 496 | - {"INTERFACE"} 497 | - {"UNION"} 498 | - {"ENUM"} 499 | - {"ENUM_VALUE"} 500 | - {"INPUT_OBJECT"} 501 | - {"INPUT_FIELD_DEFINITION"} 502 | 503 | Fields\: 504 | 505 | - `name` must return a String. 506 | - `description` may return a String or {null}. 507 | - `locations` returns a List of `__DirectiveLocation` representing the valid 508 | locations this directive may be placed. 509 | - `args` returns a List of `__InputValue` representing the arguments this 510 | directive accepts. 511 | - Accepts the argument `includeDeprecated` which defaults to {false}. If 512 | {true}, deprecated arguments are also returned. 513 | - `isRepeatable` must return a Boolean that indicates if the directive may be 514 | used repeatedly at a single location. 515 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![The query language for modern APIs](./assets/banner.png)](https://graphql.org/) 2 | 3 | # GraphQL 4 | 5 | GraphQL Logo 6 | 7 | The GraphQL specification is edited in the markdown files found in 8 | [`/spec`](./spec) the latest release of which is published at 9 | https://graphql.github.io/graphql-spec/. 10 | 11 | The latest draft specification can be found at 12 | https://graphql.github.io/graphql-spec/draft/ which tracks the latest commit to 13 | the main branch in this repository. 14 | 15 | Previous releases of the GraphQL specification can be found at permalinks that 16 | match their [release tag](https://github.com/graphql/graphql-spec/releases). For 17 | example, https://graphql.github.io/graphql-spec/October2016/. If you are linking 18 | directly to the GraphQL specification, it's best to link to a tagged permalink 19 | for the particular referenced version. 20 | 21 | ## Overview 22 | 23 | This is a Working Draft of the Specification for GraphQL, a query language for 24 | APIs created by Facebook. 25 | 26 | The target audience for this specification is not the client developer, but 27 | those who have, or are actively interested in, building their own GraphQL 28 | implementations and tools. 29 | 30 | In order to be broadly adopted, GraphQL will have to target a wide variety of 31 | backend environments, frameworks, and languages, which will necessitate a 32 | collaborative effort across projects and organizations. This specification 33 | serves as a point of coordination for this effort. 34 | 35 | Looking for help? Find resources 36 | [from the community](https://graphql.org/community/). 37 | 38 | ## Getting Started 39 | 40 | GraphQL consists of a type system, query language and execution semantics, 41 | static validation, and type introspection, each outlined below. To guide you 42 | through each of these components, we've written an example designed to 43 | illustrate the various pieces of GraphQL. 44 | 45 | This example is not comprehensive, but it is designed to quickly introduce the 46 | core concepts of GraphQL, to provide some context before diving into the more 47 | detailed specification or the 48 | [GraphQL.js](https://github.com/graphql/graphql-js) reference implementation. 49 | 50 | The premise of the example is that we want to use GraphQL to query for 51 | information about characters and locations in the original Star Wars trilogy. 52 | 53 | ### Type System 54 | 55 | At the heart of any GraphQL implementation is a description of what types of 56 | objects it can return, described in a GraphQL type system and returned in the 57 | GraphQL Schema. 58 | 59 | For our Star Wars example, the 60 | [starWarsSchema.ts](https://github.com/graphql/graphql-js/blob/main/src/__tests__/starWarsSchema.ts) 61 | file in GraphQL.js defines this type system. 62 | 63 | The most basic type in the system will be `Human`, representing characters like 64 | Luke, Leia, and Han. All humans in our type system will have a name, so we 65 | define the `Human` type to have a field called "name". This returns a String, 66 | and we know that it is not null (since all `Human`s have a name), so we will 67 | define the "name" field to be a non-nullable String. Using a shorthand notation 68 | that we will use throughout the spec and documentation, we would describe the 69 | human type as: 70 | 71 | ```graphql 72 | type Human { 73 | name: String 74 | } 75 | ``` 76 | 77 | This shorthand is convenient for describing the basic shape of a type system; 78 | the JavaScript implementation is more full-featured, and allows types and fields 79 | to be documented. It also sets up the mapping between the type system and the 80 | underlying data; for a test case in GraphQL.js, the underlying data is a 81 | [set of JavaScript objects](https://github.com/graphql/graphql-js/blob/main/src/__tests__/starWarsData.ts), 82 | but in most cases the backing data will be accessed through some service, and 83 | this type system layer will be responsible for mapping from types and fields to 84 | that service. 85 | 86 | A common pattern in many APIs, and indeed in GraphQL is to give objects an ID 87 | that can be used to refetch the object. So let's add that to our Human type. 88 | We'll also add a string for their home planet. 89 | 90 | ```graphql 91 | type Human { 92 | id: String 93 | name: String 94 | homePlanet: String 95 | } 96 | ``` 97 | 98 | Since we're talking about the Star Wars trilogy, it would be useful to describe 99 | the episodes in which each character appears. To do so, we'll first define an 100 | enum, which lists the three episodes in the trilogy: 101 | 102 | ```graphql 103 | enum Episode { 104 | NEWHOPE 105 | EMPIRE 106 | JEDI 107 | } 108 | ``` 109 | 110 | Now we want to add a field to `Human` describing what episodes they were in. 111 | This will return a list of `Episode`s: 112 | 113 | ```graphql 114 | type Human { 115 | id: String 116 | name: String 117 | appearsIn: [Episode] 118 | homePlanet: String 119 | } 120 | ``` 121 | 122 | Now, let's introduce another type, `Droid`: 123 | 124 | ```graphql 125 | type Droid { 126 | id: String 127 | name: String 128 | appearsIn: [Episode] 129 | primaryFunction: String 130 | } 131 | ``` 132 | 133 | Now we have two types! Let's add a way of going between them: humans and droids 134 | both have friends. But humans can be friends with both humans and droids. How do 135 | we refer to either a human or a droid? 136 | 137 | If we look, we note that there's common functionality between humans and droids; 138 | they both have IDs, names, and episodes in which they appear. So we'll add an 139 | interface, `Character`, and make both `Human` and `Droid` implement it. Once we 140 | have that, we can add the `friends` field, that returns a list of `Character`s. 141 | 142 | Our type system so far is: 143 | 144 | ```graphql 145 | enum Episode { 146 | NEWHOPE 147 | EMPIRE 148 | JEDI 149 | } 150 | 151 | interface Character { 152 | id: String 153 | name: String 154 | friends: [Character] 155 | appearsIn: [Episode] 156 | } 157 | 158 | type Human implements Character { 159 | id: String 160 | name: String 161 | friends: [Character] 162 | appearsIn: [Episode] 163 | homePlanet: String 164 | } 165 | 166 | type Droid implements Character { 167 | id: String 168 | name: String 169 | friends: [Character] 170 | appearsIn: [Episode] 171 | primaryFunction: String 172 | } 173 | ``` 174 | 175 | One question we might ask, though, is whether any of those fields can return 176 | `null`. By default, `null` is a permitted value for any type in GraphQL, since 177 | fetching data to fulfill a GraphQL query often requires talking to different 178 | services that may or may not be available. However, if the type system can 179 | guarantee that a type is never null, then we can mark it as Non Null in the type 180 | system. We indicate that in our shorthand by adding an "!" after the type. We 181 | can update our type system to note that the `id` is never null. 182 | 183 | Note that while in our current implementation, we can guarantee that more fields 184 | are non-null (since our current implementation has hard-coded data), we didn't 185 | mark them as non-null. One can imagine we would eventually replace our hardcoded 186 | data with a backend service, which might not be perfectly reliable; by leaving 187 | these fields as nullable, we allow ourselves the flexibility to eventually 188 | return null to indicate a backend error, while also telling the client that the 189 | error occurred. 190 | 191 | ```graphql 192 | enum Episode { 193 | NEWHOPE 194 | EMPIRE 195 | JEDI 196 | } 197 | 198 | interface Character { 199 | id: String! 200 | name: String 201 | friends: [Character] 202 | appearsIn: [Episode] 203 | } 204 | 205 | type Human implements Character { 206 | id: String! 207 | name: String 208 | friends: [Character] 209 | appearsIn: [Episode] 210 | homePlanet: String 211 | } 212 | 213 | type Droid implements Character { 214 | id: String! 215 | name: String 216 | friends: [Character] 217 | appearsIn: [Episode] 218 | primaryFunction: String 219 | } 220 | ``` 221 | 222 | We're missing one last piece: an entry point into the type system. 223 | 224 | When we define a schema, we define an object type that is the basis for all 225 | query operations. The name of this type is `Query` by convention, and it 226 | describes our public, top-level API. Our `Query` type for this example will look 227 | like this: 228 | 229 | ```graphql 230 | type Query { 231 | hero(episode: Episode): Character 232 | human(id: String!): Human 233 | droid(id: String!): Droid 234 | } 235 | ``` 236 | 237 | In this example, there are three top-level operations that can be done on our 238 | schema: 239 | 240 | - `hero` returns the `Character` who is the hero of the Star Wars trilogy; it 241 | takes an optional argument that allows us to fetch the hero of a specific 242 | episode instead. 243 | - `human` accepts a non-null string as a query argument, a human's ID, and 244 | returns the human with that ID. 245 | - `droid` does the same for droids. 246 | 247 | These fields demonstrate another feature of the type system, the ability for a 248 | field to specify arguments that configure their behavior. 249 | 250 | When we package the whole type system together, defining the `Query` type above 251 | as our entry point for queries, this creates a GraphQL Schema. 252 | 253 | This example just scratched the surface of the type system. The specification 254 | goes into more detail about this topic in the "Type System" section, and the 255 | [type](https://github.com/graphql/graphql-js/blob/main/src/type) directory in 256 | GraphQL.js contains code implementing a specification-compliant GraphQL type 257 | system. 258 | 259 | ### Query Syntax 260 | 261 | GraphQL queries declaratively describe what data the issuer wishes to fetch from 262 | whoever is fulfilling the GraphQL query. 263 | 264 | For our Star Wars example, the 265 | [starWarsQueryTests.js](https://github.com/graphql/graphql-js/blob/main/src/__tests__/starWarsQuery-test.ts) 266 | file in the GraphQL.js repository contains a number of queries and responses. 267 | That file is a test file that uses the schema discussed above and a set of 268 | sample data, located in 269 | [starWarsData.js](https://github.com/graphql/graphql-js/blob/main/src/__tests__/starWarsData.ts). 270 | This test file can be run to exercise the reference implementation. 271 | 272 | An example query on the above schema would be: 273 | 274 | ```graphql 275 | query HeroNameQuery { 276 | hero { 277 | name 278 | } 279 | } 280 | ``` 281 | 282 | The initial line, `query HeroNameQuery`, defines a query with the operation name 283 | `HeroNameQuery` that starts with the schema's root query type; in this case, 284 | `Query`. As defined above, `Query` has a `hero` field that returns a 285 | `Character`, so we'll query for that. `Character` then has a `name` field that 286 | returns a `String`, so we query for that, completing our query. The result of 287 | this query would then be: 288 | 289 | ```json 290 | { 291 | "hero": { 292 | "name": "R2-D2" 293 | } 294 | } 295 | ``` 296 | 297 | Specifying the `query` keyword and an operation name is only required when a 298 | GraphQL document defines multiple operations. We therefore could have written 299 | the previous query with the query shorthand: 300 | 301 | ```graphql 302 | { 303 | hero { 304 | name 305 | } 306 | } 307 | ``` 308 | 309 | Assuming that the backing data for the GraphQL server identified R2-D2 as the 310 | hero. The response continues to vary based on the request; if we asked for 311 | R2-D2's ID and friends with this query: 312 | 313 | ```graphql 314 | query HeroNameAndFriendsQuery { 315 | hero { 316 | id 317 | name 318 | friends { 319 | id 320 | name 321 | } 322 | } 323 | } 324 | ``` 325 | 326 | then we'll get back a response like this: 327 | 328 | ```json 329 | { 330 | "hero": { 331 | "id": "2001", 332 | "name": "R2-D2", 333 | "friends": [ 334 | { 335 | "id": "1000", 336 | "name": "Luke Skywalker" 337 | }, 338 | { 339 | "id": "1002", 340 | "name": "Han Solo" 341 | }, 342 | { 343 | "id": "1003", 344 | "name": "Leia Organa" 345 | } 346 | ] 347 | } 348 | } 349 | ``` 350 | 351 | One of the key aspects of GraphQL is its ability to nest queries. In the above 352 | query, we asked for R2-D2's friends, but we can ask for more information about 353 | each of those objects. So let's construct a query that asks for R2-D2's friends, 354 | gets their name and episode appearances, then asks for each of _their_ friends. 355 | 356 | ```graphql 357 | query NestedQuery { 358 | hero { 359 | name 360 | friends { 361 | name 362 | appearsIn 363 | friends { 364 | name 365 | } 366 | } 367 | } 368 | } 369 | ``` 370 | 371 | which will give us the nested response 372 | 373 | ```json 374 | { 375 | "hero": { 376 | "name": "R2-D2", 377 | "friends": [ 378 | { 379 | "name": "Luke Skywalker", 380 | "appearsIn": ["NEWHOPE", "EMPIRE", "JEDI"], 381 | "friends": [ 382 | { "name": "Han Solo" }, 383 | { "name": "Leia Organa" }, 384 | { "name": "C-3PO" }, 385 | { "name": "R2-D2" } 386 | ] 387 | }, 388 | { 389 | "name": "Han Solo", 390 | "appearsIn": ["NEWHOPE", "EMPIRE", "JEDI"], 391 | "friends": [ 392 | { "name": "Luke Skywalker" }, 393 | { "name": "Leia Organa" }, 394 | { "name": "R2-D2" } 395 | ] 396 | }, 397 | { 398 | "name": "Leia Organa", 399 | "appearsIn": ["NEWHOPE", "EMPIRE", "JEDI"], 400 | "friends": [ 401 | { "name": "Luke Skywalker" }, 402 | { "name": "Han Solo" }, 403 | { "name": "C-3PO" }, 404 | { "name": "R2-D2" } 405 | ] 406 | } 407 | ] 408 | } 409 | } 410 | ``` 411 | 412 | The `Query` type above defined a way to fetch a human given their ID. We can use 413 | it by hard-coding the ID in the query: 414 | 415 | ```graphql 416 | query FetchLukeQuery { 417 | human(id: "1000") { 418 | name 419 | } 420 | } 421 | ``` 422 | 423 | to get 424 | 425 | ```json 426 | { 427 | "human": { 428 | "name": "Luke Skywalker" 429 | } 430 | } 431 | ``` 432 | 433 | Alternately, we could have defined the query to have a query parameter: 434 | 435 | ```graphql 436 | query FetchSomeIDQuery($someId: String!) { 437 | human(id: $someId) { 438 | name 439 | } 440 | } 441 | ``` 442 | 443 | This query is now parameterized by `$someId`; to run it, we must provide that 444 | ID. If we ran it with `$someId` set to "1000", we would get Luke; set to "1002", 445 | we would get Han. If we passed an invalid ID here, we would get `null` back for 446 | the `human`, indicating that no such object exists. 447 | 448 | Notice that the key in the response is the name of the field, by default. It is 449 | sometimes useful to change this key, for clarity or to avoid key collisions when 450 | fetching the same field with different arguments. 451 | 452 | We can do that with field aliases, as demonstrated in this query: 453 | 454 | ```graphql 455 | query FetchLukeAliased { 456 | luke: human(id: "1000") { 457 | name 458 | } 459 | } 460 | ``` 461 | 462 | We aliased the result of the `human` field to the key `luke`. Now the response 463 | is: 464 | 465 | ```json 466 | { 467 | "luke": { 468 | "name": "Luke Skywalker" 469 | } 470 | } 471 | ``` 472 | 473 | Notice the key is "luke" and not "human", as it was in our previous example 474 | where we did not use the alias. 475 | 476 | This is particularly useful if we want to use the same field twice with 477 | different arguments, as in the following query: 478 | 479 | ```graphql 480 | query FetchLukeAndLeiaAliased { 481 | luke: human(id: "1000") { 482 | name 483 | } 484 | leia: human(id: "1003") { 485 | name 486 | } 487 | } 488 | ``` 489 | 490 | We aliased the result of the first `human` field to the key `luke`, and the 491 | second to `leia`. So the result will be: 492 | 493 | ```json 494 | { 495 | "luke": { 496 | "name": "Luke Skywalker" 497 | }, 498 | "leia": { 499 | "name": "Leia Organa" 500 | } 501 | } 502 | ``` 503 | 504 | Now imagine we wanted to ask for Luke and Leia's home planets. We could do so 505 | with this query: 506 | 507 | ```graphql 508 | query DuplicateFields { 509 | luke: human(id: "1000") { 510 | name 511 | homePlanet 512 | } 513 | leia: human(id: "1003") { 514 | name 515 | homePlanet 516 | } 517 | } 518 | ``` 519 | 520 | but we can already see that this could get unwieldy, since we have to add new 521 | fields to both parts of the query. Instead, we can extract out the common fields 522 | into a fragment, and include the fragment in the query, like this: 523 | 524 | ```graphql 525 | query UseFragment { 526 | luke: human(id: "1000") { 527 | ...HumanFragment 528 | } 529 | leia: human(id: "1003") { 530 | ...HumanFragment 531 | } 532 | } 533 | 534 | fragment HumanFragment on Human { 535 | name 536 | homePlanet 537 | } 538 | ``` 539 | 540 | Both of those queries give this result: 541 | 542 | ```json 543 | { 544 | "luke": { 545 | "name": "Luke Skywalker", 546 | "homePlanet": "Tatooine" 547 | }, 548 | "leia": { 549 | "name": "Leia Organa", 550 | "homePlanet": "Alderaan" 551 | } 552 | } 553 | ``` 554 | 555 | The `UseFragment` and `DuplicateFields` queries will both get the same result, 556 | but `UseFragment` is less verbose; if we wanted to add more fields, we could add 557 | it to the common fragment rather than copying it into multiple places. 558 | 559 | We defined the type system above, so we know the type of each object in the 560 | output; the query can ask for that type using the special field `__typename`, 561 | defined on every object. 562 | 563 | ```graphql 564 | query CheckTypeOfR2 { 565 | hero { 566 | __typename 567 | name 568 | } 569 | } 570 | ``` 571 | 572 | Since R2-D2 is a droid, this will return 573 | 574 | ```json 575 | { 576 | "hero": { 577 | "__typename": "Droid", 578 | "name": "R2-D2" 579 | } 580 | } 581 | ``` 582 | 583 | This was particularly useful because `hero` was defined to return a `Character`, 584 | which is an interface; we might want to know what concrete type was actually 585 | returned. If we instead asked for the hero of Episode V: 586 | 587 | ```graphql 588 | query CheckTypeOfLuke { 589 | hero(episode: EMPIRE) { 590 | __typename 591 | name 592 | } 593 | } 594 | ``` 595 | 596 | We would find that it was Luke, who is a Human: 597 | 598 | ```json 599 | { 600 | "hero": { 601 | "__typename": "Human", 602 | "name": "Luke Skywalker" 603 | } 604 | } 605 | ``` 606 | 607 | As with the type system, this example just scratched the surface of the query 608 | language. The specification goes into more detail about this topic in the 609 | "Language" section, and the 610 | [language](https://github.com/graphql/graphql-js/blob/main/src/language) 611 | directory in GraphQL.js contains code implementing a specification-compliant 612 | GraphQL query language parser and lexer. 613 | 614 | ### Validation 615 | 616 | By using the type system, it can be predetermined whether a GraphQL query is 617 | valid or not. This allows servers and clients to effectively inform developers 618 | when an invalid query has been created, without having to rely on runtime 619 | checks. 620 | 621 | For our Star Wars example, the file 622 | [starWarsValidationTests.js](https://github.com/graphql/graphql-js/blob/main/src/__tests__/starWarsValidation-test.ts) 623 | contains a number of demonstrations of invalid operations, and is a test file 624 | that can be run to exercise the reference implementation's validator. 625 | 626 | To start, let's take a complex valid query. This is the `NestedQuery` example 627 | from the above section, but with the duplicated fields factored out into a 628 | fragment: 629 | 630 | ```graphql 631 | query NestedQueryWithFragment { 632 | hero { 633 | ...NameAndAppearances 634 | friends { 635 | ...NameAndAppearances 636 | friends { 637 | ...NameAndAppearances 638 | } 639 | } 640 | } 641 | } 642 | 643 | fragment NameAndAppearances on Character { 644 | name 645 | appearsIn 646 | } 647 | ``` 648 | 649 | And this query is valid. Let's take a look at some invalid queries! 650 | 651 | When we query for fields, we have to query for a field that exists on the given 652 | type. So as `hero` returns a `Character`, we have to query for a field on 653 | `Character`. That type does not have a `favoriteSpaceship` field, so this query: 654 | 655 | ```graphql 656 | # INVALID: favoriteSpaceship does not exist on Character 657 | query HeroSpaceshipQuery { 658 | hero { 659 | favoriteSpaceship 660 | } 661 | } 662 | ``` 663 | 664 | is invalid. 665 | 666 | Whenever we query for a field and it returns something other than a scalar or an 667 | enum, we need to specify what data we want to get back from the field. Hero 668 | returns a `Character`, and we've been requesting fields like `name` and 669 | `appearsIn` on it; if we omit that, the query will not be valid: 670 | 671 | ```graphql 672 | # INVALID: hero is not a scalar, so fields are needed 673 | query HeroNoFieldsQuery { 674 | hero 675 | } 676 | ``` 677 | 678 | Similarly, if a field is a scalar, it doesn't make sense to query for additional 679 | fields on it, and doing so will make the query invalid: 680 | 681 | ```graphql 682 | # INVALID: name is a scalar, so fields are not permitted 683 | query HeroFieldsOnScalarQuery { 684 | hero { 685 | name { 686 | firstCharacterOfName 687 | } 688 | } 689 | } 690 | ``` 691 | 692 | Earlier, it was noted that a query can only query for fields on the type in 693 | question; when we query for `hero` which returns a `Character`, we can only 694 | query for fields that exist on `Character`. What happens if we want to query for 695 | R2-D2s primary function, though? 696 | 697 | ```graphql 698 | # INVALID: primaryFunction does not exist on Character 699 | query DroidFieldOnCharacter { 700 | hero { 701 | name 702 | primaryFunction 703 | } 704 | } 705 | ``` 706 | 707 | That query is invalid, because `primaryFunction` is not a field on `Character`. 708 | We want some way of indicating that we wish to fetch `primaryFunction` if the 709 | `Character` is a `Droid`, and to ignore that field otherwise. We can use the 710 | fragments we introduced earlier to do this. By setting up a fragment defined on 711 | `Droid` and including it, we ensure that we only query for `primaryFunction` 712 | where it is defined. 713 | 714 | ```graphql 715 | query DroidFieldInFragment { 716 | hero { 717 | name 718 | ...DroidFields 719 | } 720 | } 721 | 722 | fragment DroidFields on Droid { 723 | primaryFunction 724 | } 725 | ``` 726 | 727 | This query is valid, but it's a bit verbose; named fragments were valuable above 728 | when we used them multiple times, but we're only using this one once. Instead of 729 | using a named fragment, we can use an inline fragment; this still allows us to 730 | indicate the type we are querying on, but without naming a separate fragment: 731 | 732 | ```graphql 733 | query DroidFieldInInlineFragment { 734 | hero { 735 | name 736 | ... on Droid { 737 | primaryFunction 738 | } 739 | } 740 | } 741 | ``` 742 | 743 | This has just scratched the surface of the validation system; there are a number 744 | of validation rules in place to ensure that a GraphQL query is semantically 745 | meaningful. The specification goes into more detail about this topic in the 746 | "Validation" section, and the 747 | [validation](https://github.com/graphql/graphql-js/blob/main/src/validation) 748 | directory in GraphQL.js contains code implementing a specification-compliant 749 | GraphQL validator. 750 | 751 | ### Introspection 752 | 753 | It's often useful to ask a GraphQL schema for information about what queries it 754 | supports. GraphQL allows us to do so using the introspection system! 755 | 756 | For our Star Wars example, the file 757 | [starWarsIntrospectionTests.js](https://github.com/graphql/graphql-js/blob/main/src/__tests__/starWarsIntrospection-test.ts) 758 | contains a number of queries demonstrating the introspection system, and is a 759 | test file that can be run to exercise the reference implementation's 760 | introspection system. 761 | 762 | We designed the type system, so we know what types are available, but if we 763 | didn't, we can ask GraphQL, by querying the `__schema` field, always available 764 | on the root type of a Query. Let's do so now, and ask what types are available. 765 | 766 | ```graphql 767 | query IntrospectionTypeQuery { 768 | __schema { 769 | types { 770 | name 771 | } 772 | } 773 | } 774 | ``` 775 | 776 | and we get back: 777 | 778 | ```json 779 | { 780 | "__schema": { 781 | "types": [ 782 | { 783 | "name": "Query" 784 | }, 785 | { 786 | "name": "Character" 787 | }, 788 | { 789 | "name": "Human" 790 | }, 791 | { 792 | "name": "String" 793 | }, 794 | { 795 | "name": "Episode" 796 | }, 797 | { 798 | "name": "Droid" 799 | }, 800 | { 801 | "name": "__Schema" 802 | }, 803 | { 804 | "name": "__Type" 805 | }, 806 | { 807 | "name": "__TypeKind" 808 | }, 809 | { 810 | "name": "Boolean" 811 | }, 812 | { 813 | "name": "__Field" 814 | }, 815 | { 816 | "name": "__InputValue" 817 | }, 818 | { 819 | "name": "__EnumValue" 820 | }, 821 | { 822 | "name": "__Directive" 823 | } 824 | ] 825 | } 826 | } 827 | ``` 828 | 829 | Wow, that's a lot of types! What are they? Let's group them: 830 | 831 | - **Query, Character, Human, Episode, Droid** - These are the ones that we 832 | defined in our type system. 833 | - **String, Boolean** - These are built-in scalars that the type system 834 | provided. 835 | - **`__Schema`, `__Type`, `__TypeKind`, `__Field`, `__InputValue`, 836 | `__EnumValue`, `__Directive`** - These all are preceded with a double 837 | underscore, indicating that they are part of the introspection system. 838 | 839 | Now, let's try and figure out a good place to start exploring what queries are 840 | available. When we designed our type system, we specified what type all queries 841 | would start at; let's ask the introspection system about that! 842 | 843 | ```graphql 844 | query IntrospectionQueryTypeQuery { 845 | __schema { 846 | queryType { 847 | name 848 | } 849 | } 850 | } 851 | ``` 852 | 853 | and we get back: 854 | 855 | ```json 856 | { 857 | "__schema": { 858 | "queryType": { 859 | "name": "Query" 860 | } 861 | } 862 | } 863 | ``` 864 | 865 | And that matches what we said in the type system section, that the `Query` type 866 | is where we will start! Note that the naming here was just by convention; we 867 | could have named our `Query` type anything else, and it still would have been 868 | returned here if we had specified it as the starting type for queries. Naming it 869 | `Query`, though, is a useful convention. 870 | 871 | It is often useful to examine one specific type. Let's take a look at the 872 | `Droid` type: 873 | 874 | ```graphql 875 | query IntrospectionDroidTypeQuery { 876 | __type(name: "Droid") { 877 | name 878 | } 879 | } 880 | ``` 881 | 882 | and we get back: 883 | 884 | ```json 885 | { 886 | "__type": { 887 | "name": "Droid" 888 | } 889 | } 890 | ``` 891 | 892 | What if we want to know more about Droid, though? For example, is it an 893 | interface or an object? 894 | 895 | ```graphql 896 | query IntrospectionDroidKindQuery { 897 | __type(name: "Droid") { 898 | name 899 | kind 900 | } 901 | } 902 | ``` 903 | 904 | and we get back: 905 | 906 | ```json 907 | { 908 | "__type": { 909 | "name": "Droid", 910 | "kind": "OBJECT" 911 | } 912 | } 913 | ``` 914 | 915 | `kind` returns a `__TypeKind` enum, one of whose values is `OBJECT`. If we asked 916 | about `Character` instead: 917 | 918 | ```graphql 919 | query IntrospectionCharacterKindQuery { 920 | __type(name: "Character") { 921 | name 922 | kind 923 | } 924 | } 925 | ``` 926 | 927 | and we get back: 928 | 929 | ```json 930 | { 931 | "__type": { 932 | "name": "Character", 933 | "kind": "INTERFACE" 934 | } 935 | } 936 | ``` 937 | 938 | We'd find that it is an interface. 939 | 940 | It's useful for an object to know what fields are available, so let's ask the 941 | introspection system about `Droid`: 942 | 943 | ```graphql 944 | query IntrospectionDroidFieldsQuery { 945 | __type(name: "Droid") { 946 | name 947 | fields { 948 | name 949 | type { 950 | name 951 | kind 952 | } 953 | } 954 | } 955 | } 956 | ``` 957 | 958 | and we get back: 959 | 960 | ```json 961 | { 962 | "__type": { 963 | "name": "Droid", 964 | "fields": [ 965 | { 966 | "name": "id", 967 | "type": { 968 | "name": null, 969 | "kind": "NON_NULL" 970 | } 971 | }, 972 | { 973 | "name": "name", 974 | "type": { 975 | "name": "String", 976 | "kind": "SCALAR" 977 | } 978 | }, 979 | { 980 | "name": "friends", 981 | "type": { 982 | "name": null, 983 | "kind": "LIST" 984 | } 985 | }, 986 | { 987 | "name": "appearsIn", 988 | "type": { 989 | "name": null, 990 | "kind": "LIST" 991 | } 992 | }, 993 | { 994 | "name": "primaryFunction", 995 | "type": { 996 | "name": "String", 997 | "kind": "SCALAR" 998 | } 999 | } 1000 | ] 1001 | } 1002 | } 1003 | ``` 1004 | 1005 | Those are our fields that we defined on `Droid`! 1006 | 1007 | `id` looks a bit weird there, it has no name for the type. That's because it's a 1008 | "wrapper" type of kind `NON_NULL`. If we queried for `ofType` on that field's 1009 | type, we would find the `String` type there, telling us that this is a non-null 1010 | String. 1011 | 1012 | Similarly, both `friends` and `appearsIn` have no name, since they are the 1013 | `LIST` wrapper type. We can query for `ofType` on those types, which will tell 1014 | us what these are lists of. 1015 | 1016 | ```graphql 1017 | query IntrospectionDroidWrappedFieldsQuery { 1018 | __type(name: "Droid") { 1019 | name 1020 | fields { 1021 | name 1022 | type { 1023 | name 1024 | kind 1025 | ofType { 1026 | name 1027 | kind 1028 | } 1029 | } 1030 | } 1031 | } 1032 | } 1033 | ``` 1034 | 1035 | and we get back: 1036 | 1037 | ```json 1038 | { 1039 | "__type": { 1040 | "name": "Droid", 1041 | "fields": [ 1042 | { 1043 | "name": "id", 1044 | "type": { 1045 | "name": null, 1046 | "kind": "NON_NULL", 1047 | "ofType": { 1048 | "name": "String", 1049 | "kind": "SCALAR" 1050 | } 1051 | } 1052 | }, 1053 | { 1054 | "name": "name", 1055 | "type": { 1056 | "name": "String", 1057 | "kind": "SCALAR", 1058 | "ofType": null 1059 | } 1060 | }, 1061 | { 1062 | "name": "friends", 1063 | "type": { 1064 | "name": null, 1065 | "kind": "LIST", 1066 | "ofType": { 1067 | "name": "Character", 1068 | "kind": "INTERFACE" 1069 | } 1070 | } 1071 | }, 1072 | { 1073 | "name": "appearsIn", 1074 | "type": { 1075 | "name": null, 1076 | "kind": "LIST", 1077 | "ofType": { 1078 | "name": "Episode", 1079 | "kind": "ENUM" 1080 | } 1081 | } 1082 | }, 1083 | { 1084 | "name": "primaryFunction", 1085 | "type": { 1086 | "name": "String", 1087 | "kind": "SCALAR", 1088 | "ofType": null 1089 | } 1090 | } 1091 | ] 1092 | } 1093 | } 1094 | ``` 1095 | 1096 | Let's end with a feature of the introspection system particularly useful for 1097 | tooling; let's ask the system for documentation! 1098 | 1099 | ```graphql 1100 | query IntrospectionDroidDescriptionQuery { 1101 | __type(name: "Droid") { 1102 | name 1103 | description 1104 | } 1105 | } 1106 | ``` 1107 | 1108 | yields 1109 | 1110 | ```json 1111 | { 1112 | "__type": { 1113 | "name": "Droid", 1114 | "description": "A mechanical creature in the Star Wars universe." 1115 | } 1116 | } 1117 | ``` 1118 | 1119 | So we can access the documentation about the type system using introspection, 1120 | and create documentation browsers, or rich IDE experiences. 1121 | 1122 | This has just scratched the surface of the introspection system; we can query 1123 | for enum values, what interfaces a type implements, and more. We can even 1124 | introspect on the introspection system itself. The specification goes into more 1125 | detail about this topic in the "Introspection" section, and the 1126 | [introspection](https://github.com/graphql/graphql-js/blob/main/src/type/introspection.ts) 1127 | file in GraphQL.js contains code implementing a specification-compliant GraphQL 1128 | query introspection system. 1129 | 1130 | ### Additional Content 1131 | 1132 | This README walked through the GraphQL.js reference implementation's type 1133 | system, query execution, validation, and introspection systems. There's more in 1134 | both [GraphQL.js](https://github.com/graphql/graphql-js/) and specification, 1135 | including a description and implementation for executing queries, how to format 1136 | a response, explaining how a type system maps to an underlying implementation, 1137 | and how to format a GraphQL response, as well as the grammar for GraphQL. 1138 | 1139 | ### Contributing to this repo 1140 | 1141 | This repository is managed by EasyCLA. Project participants must sign the free 1142 | ([GraphQL Specification Membership agreement](https://preview-spec-membership.graphql.org) 1143 | before making a contribution. You only need to do this one time, and it can be 1144 | signed by 1145 | [individual contributors](https://individual-spec-membership.graphql.org/) or 1146 | their [employers](https://corporate-spec-membership.graphql.org/). 1147 | 1148 | To initiate the signature process please open a PR against this repo. The 1149 | EasyCLA bot will block the merge if we still need a membership agreement from 1150 | you. 1151 | 1152 | You can find 1153 | [detailed information here](https://github.com/graphql/graphql-wg/tree/main/membership). 1154 | If you have issues, please email 1155 | [operations@graphql.org](mailto:operations@graphql.org). 1156 | 1157 | If your company benefits from GraphQL and you would like to provide essential 1158 | financial support for the systems and people that power our community, please 1159 | also consider membership in the 1160 | [GraphQL Foundation](https://foundation.graphql.org/join). 1161 | -------------------------------------------------------------------------------- /changelogs/September2025.md: -------------------------------------------------------------------------------- 1 | # September 2025 Changelog 2 | 3 | This describes the set of changes since the last edition of the GraphQL 4 | specification, [October2021](https://spec.graphql.org/October2021/) (see 5 | [prior changelog](./October2021.md)). It's intended to ease the review of 6 | changes since the last edition for reviewers or curious readers, but is not 7 | normative. Please read the 8 | [specification document](https://spec.graphql.org/September2025/) itself for 9 | full detail and context. 10 | 11 | ## Thank you, contributors! 12 | 13 | The last few years have seen GraphQL reach a wide breath of use, powering 14 | internal and external APIs at startups and enterprises, and integrating with 15 | various platforms and tools. Work contributed to GraphQL has fit into two 16 | priorities: 17 | 18 | 1. **Maintain a stable base.** With a huge ecosystem built atop GraphQL, it's 19 | our responsibility to put stability above all else. The vast majority of work 20 | has fixed inconsistencies, improved behavior in edge and corner cases, 21 | improve security, and avoid performance pitfalls. 22 | 23 | 2. **Provide a productive expressive query language.** GraphQL was designed with 24 | API consumers in mind, and this spec release includes significant 25 | improvements to the GraphQL query engine and language. 26 | 27 | Significant contributions have been made since the last edition of the spec, and 28 | both of these priories remain active areas of investment with many exciting RFCs 29 | still in the works. 30 | 31 | Over 100 commits made to the GraphQL spec since the last edition, most of which 32 | have dozens or hundreds of comments! It's a huge amount of work to champion 33 | these changes, and a great responsibility to evolve the technical foundations 34 | for this community and ecosystem. 35 | 36 | Thank you! 37 | 38 | - [@leebyron](https://github.com/leebyron), Editor 39 | 40 | ## Contributors 41 | 42 | Anyone is welcome to join working group meetings and contribute to GraphQL. See 43 | [Contributing.md](https://github.com/graphql/graphql-spec/blob/main/CONTRIBUTING.md) 44 | for more information. Thank you to these community members for their technical 45 | contribution to this edition of the GraphQL specification. 46 | 47 | | Author | Github | 48 | | ------------------ | -------------------------------------------------------- | 49 | | Alex Reilly | [@twof](https://github.com/twof) | 50 | | Andreas Marek | [@andimarek](https://github.com/andimarek) | 51 | | Ben Kraft | [@benjaminjkraft](https://github.com/benjaminjkraft) | 52 | | Benedikt Franke | [@spawnia](https://github.com/spawnia) | 53 | | Benjie | [@benjie](https://github.com/benjie) | 54 | | Benoit 'BoD' Lubek | [@BoD](https://github.com/BoD) | 55 | | dondonz | [@dondonz](https://github.com/dondonz) | 56 | | dugenkui | [@dugenkui03](https://github.com/dugenkui03) | 57 | | Glen | [@glen-84](https://github.com/glen-84) | 58 | | Ivan Goncharov | [@IvanGoncharov](https://github.com/IvanGoncharov) | 59 | | Ivan Maximov | [@sungam3r](https://github.com/sungam3r) | 60 | | James Bellenger | [@jbellenger](https://github.com/jbellenger) | 61 | | Jan Melcher | [@Yogu](https://github.com/Yogu) | 62 | | Jason Dent | [@Jason3S](https://github.com/Jason3S) | 63 | | Jeff Auriemma | [@bignimbus](https://github.com/bignimbus) | 64 | | Jovi De Croock | [@JoviDeCroock](https://github.com/JoviDeCroock) | 65 | | Kevin Smithson | [@smitt04](https://github.com/smitt04) | 66 | | Lee Byron | [@leebyron](https://github.com/leebyron) | 67 | | Mark Larah | [@magicmark](https://github.com/magicmark) | 68 | | Martin Bonnin | [@martinbonnin](https://github.com/martinbonnin) | 69 | | Michael Staib | [@michaelstaib](https://github.com/michaelstaib) | 70 | | Mike Solomon | [@msolomon](https://github.com/msolomon) | 71 | | PascalSenn | [@PascalSenn](https://github.com/PascalSenn) | 72 | | Renée | [@goto-bus-stop](https://github.com/goto-bus-stop) | 73 | | Rob Richard | [@robrichard](https://github.com/robrichard) | 74 | | Roman Ivantsov | [@rivantsov](https://github.com/rivantsov) | 75 | | Shane Krueger | [@Shane32](https://github.com/Shane32) | 76 | | Stephen Spalding | [@fotoetienne](https://github.com/fotoetienne) | 77 | | Thomas Heyenbrock | [@thomasheyenbrock](https://github.com/thomasheyenbrock) | 78 | | Yaacov Rydzinski | [@yaacovCR](https://github.com/yaacovCR) | 79 | 80 | Generated with: 81 | 82 | ```sh 83 | node scripts/generate-contributor-list.mjs October2021..HEAD 84 | ``` 85 | 86 | ## Notable contributions 87 | 88 | A few notable changes in this edition: 89 | 90 | - OneOf input objects, aka "input unions" 91 | ([#825](https://github.com/graphql/graphql-spec/pull/825)) 92 | - Schema coordinates as a standard for GraphQL tooling and reporting 93 | ([#794](https://github.com/graphql/graphql-spec/pull/794)) 94 | - Descriptions on documents, in motivation for AI-consumers 95 | ([#1170](https://github.com/graphql/graphql-spec/pull/1170)) 96 | - Broader support for deprecation across a GraphQL Schema 97 | ([#805](https://github.com/graphql/graphql-spec/pull/805) 98 | [#1040](https://github.com/graphql/graphql-spec/pull/1040) 99 | [#1053](https://github.com/graphql/graphql-spec/pull/1053) 100 | [#1142](https://github.com/graphql/graphql-spec/pull/1142)) 101 | - GraphQL language has been updated to support the full Unicode range 102 | ([#849](https://github.com/graphql/graphql-spec/pull/849)) 103 | - Countless editorial improvements! The spec is much easier to read and 104 | contribute to, with fewer ambiguities. 105 | 106 | ## Changeset 107 | 108 | - [Github: all Accepted RFC PRs merged since last spec cut](https://github.com/graphql/graphql-spec/pulls?q=is%3Apr+is%3Amerged+base%3Amain+merged%3A2021-10-01..2025-09-03+label%3A%22%F0%9F%8F%81+Accepted+%28RFC+3%29%22) 109 | - [Github: all Editorial PRs merged since last spec cut](https://github.com/graphql/graphql-spec/pulls?page=1&q=is%3Apr+is%3Amerged+base%3Amain+merged%3A2021-10-01..2025-09-03+label%3A%22%E2%9C%8F%EF%B8%8F+Editorial%22) 110 | - [Github: all changes since last spec cut](https://github.com/graphql/graphql-spec/compare/October2021...f29fbcd2ab5af763fce7ad62896eb62465a669b3) 111 | 112 | Listed in reverse-chronological order (latest commit on top). 113 | 114 | | Hash | Change | Authors | 115 | | -------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | 116 | | [f29fbcd](https://github.com/graphql/graphql-spec/commit/f29fbcd2ab5af763fce7ad62896eb62465a669b3) | gpt guided style guide improvements (#1190) | Lee Byron | 117 | | [0157a79](https://github.com/graphql/graphql-spec/commit/0157a79b8873f0f575d254270ee700f205b0f7b2) | Fix link format for input coercion rules (#1189) | Yaacov Rydzinski | 118 | | [f70abe2](https://github.com/graphql/graphql-spec/commit/f70abe24469d0c8bd374211c8eb621cd421b69f9) | Recommend that order of unordered collections is maintained where possible (#1092) | Benjie Lee Byron | 119 | | [11c6664](https://github.com/graphql/graphql-spec/commit/11c6664e2ea65eddd812bac73b9e7341b4610292) | condense the spec defs appendix (#1186) | Lee Byron | 120 | | [10331b0](https://github.com/graphql/graphql-spec/commit/10331b0f303a1df76d465f153704bc106ed449e6) | RFC: OneOf Input Objects (#825) | Benjie Michael Staib Shane Krueger Yaacov Rydzinski Glen Lee Byron | 121 | | [cd0b8bd](https://github.com/graphql/graphql-spec/commit/cd0b8bd14c0a741ee2ea92d24b97985c6522e5c9) | Pull copyright and license into repo-level LICENSE.md (#1172) | Lee Byron | 122 | | [1e29b8a](https://github.com/graphql/graphql-spec/commit/1e29b8aea0e098663e43dba4693e88c6b033f6f8) | Schema Coordinates (#794) | Mark Larah Benjie Gillam Lee Byron Lee Byron Martin Bonnin Benoit 'BoD' Lubek | 123 | | [bc4ddea](https://github.com/graphql/graphql-spec/commit/bc4ddea0c9121a3e4effd4bbdcc0ebdfaae6e79a) | Fix CoerceArgumentValues() hasValue (#1056) | Benjie | 124 | | [b1a23de](https://github.com/graphql/graphql-spec/commit/b1a23de96f86865b2bc7f8bd613900d4afd10cc0) | Fix typo in merged "executable documents" PR (#1176) | Benjie Lee Byron | 125 | | [9939469](https://github.com/graphql/graphql-spec/commit/9939469d1315dc2f7458c885699996e2a78516f1) | Minor editorial tweaks following the merge of #1039 (#1175) | Benjie | 126 | | [468d848](https://github.com/graphql/graphql-spec/commit/468d84881646b9da00511c7ce68febdfc9a1875b) | editorial: move normative clause above example in descriptions (#1173) | Lee Byron | 127 | | [7eb8983](https://github.com/graphql/graphql-spec/commit/7eb8983955fbbc047da301d6a58c450a175cea5b) | [RFC] Default value coercion rules (#793) | Benjie Lee Byron | 128 | | [fca6653](https://github.com/graphql/graphql-spec/commit/fca66537c5e1f0743eb67de76d520cde0892e6dc) | Add descriptions to executable documents 2025 Update (#1170) | Stephen Spalding Ivan Goncharov Glen Lee Byron | 129 | | [17e2a47](https://github.com/graphql/graphql-spec/commit/17e2a4739c2189b653de3f7c721bf1fad7ac721a) | Replace `ExecuteSelectionSet` with `ExecuteCollectedFields` (#1039) | Benjie Yaacov Rydzinski Lee Byron | 130 | | [e71805e](https://github.com/graphql/graphql-spec/commit/e71805e0745b61239824475fdfff8f0fd116b83f) | Fixed unclear wording in the validation section (#1096) | PascalSenn Benjie Lee Byron | 131 | | [ccf23e3](https://github.com/graphql/graphql-spec/commit/ccf23e304bc4314511cb0712b0787d2528783337) | Define Data Collections used in the spec (#1102) | Benjie Lee Byron | 132 | | [ac483bd](https://github.com/graphql/graphql-spec/commit/ac483bdda45b8fe09fabaa50940e4cdfa24a0372) | Add validation rule that operation types exist (#955) | Ben Kraft Benjie Gillam Shane Krueger | 133 | | [883c759](https://github.com/graphql/graphql-spec/commit/883c7592d88579fbd13070d5c17f25f621abb8d7) | Do not exclude schema keyword if schema has description (#1167) | Benjie | 134 | | [df9f4f8](https://github.com/graphql/graphql-spec/commit/df9f4f8330109e1aca06af27b78ac1055a27e3a0) | Define "execution result" and "request error result" (#1159) | Rob Richard Benjie | 135 | | [9d0710e](https://github.com/graphql/graphql-spec/commit/9d0710e050f10c1ff5d0c659ec289713a6ebe8b9) | Add Appendix C - Specified Type System Definitions (#1037) | Martin Bonnin Benjie Lee Byron | 136 | | [a44d4ec](https://github.com/graphql/graphql-spec/commit/a44d4ec24e4c1263ab984a201cf9207c5a4dd549) | [RFC] Prevent @skip and @include on root subscription selection set (#860) | Benjie | 137 | | [3b0d8e6](https://github.com/graphql/graphql-spec/commit/3b0d8e606609b196d9ae643f4e0f0707700d46cc) | Add 'Assert' consistency to algorithm format check (#1168) | Benjie | 138 | | [646f937](https://github.com/graphql/graphql-spec/commit/646f937c5cf005fec43a4a3749e0c5b5406cb601) | make `includeDeprecated` non nullable (#1142) | Martin Bonnin | 139 | | [73d8b26](https://github.com/graphql/graphql-spec/commit/73d8b2624270b3cc22255125479ad10a7591f6d3) | Implementations may not deprecate a field that the interface hasn't deprecated (#1053) | Benjie Lee Byron | 140 | | [1f690d4](https://github.com/graphql/graphql-spec/commit/1f690d48149505c8a0fa94f2f9a525b69d876ace) | Clarify 'Values of Correct Type' rule relates to literals (#1118) | Benjie | 141 | | [a1884bb](https://github.com/graphql/graphql-spec/commit/a1884bb9386b6105ff81ad628a08b57e1237ccd5) | 3.13 Directive validation edits (#1089) | James Bellenger Benjie | 142 | | [c855454](https://github.com/graphql/graphql-spec/commit/c855454d518ecd7fd2eaf8e7d696f0c94104709a) | 3.10 Input Objects - clarify lists are permitted as Input fields (#1068) | Mike Solomon Benjie | 143 | | [586cbed](https://github.com/graphql/graphql-spec/commit/586cbedc4e38d27512965bd641a0588658dd6d99) | Add 'extensions' to request (#976) | Benjie Lee Byron | 144 | | [4390617](https://github.com/graphql/graphql-spec/commit/43906173238470b76173948053bfcb2a2bfc2e99) | Consistently use 'response name' not 'response key' (#1147) | Benjie Lee Byron | 145 | | [521ef5b](https://github.com/graphql/graphql-spec/commit/521ef5b200e61db7edc6c72dd4619af15eaa872a) | Rename field error to execution error; define response position (#1152) | Benjie Lee Byron | 146 | | [4abd86e](https://github.com/graphql/graphql-spec/commit/4abd86e33c70bd880e6f5605422c59343f3aa30c) | Consistently use result map when referring to objectTypes selection set result (#1148) | Rob Richard | 147 | | [0ab3d4b](https://github.com/graphql/graphql-spec/commit/0ab3d4b80103beb265777f95d202312a7dd7d63d) | Ensure algorithm steps are always wrapped in braces (#1146) | Benjie | 148 | | [b7c57ea](https://github.com/graphql/graphql-spec/commit/b7c57ea7f218474701c52fd9d1ee383600414343) | Fix choice of language used in algorithm (#1134) | Benjie | 149 | | [b41339a](https://github.com/graphql/graphql-spec/commit/b41339a0fd22fb3ca9a1a6110334a7094f1f7643) | Editorial: Add response stream to Response Section (#1135) | Rob Richard | 150 | | [a1c025f](https://github.com/graphql/graphql-spec/commit/a1c025f3b2d9c69ad208dfc5a28639746c60ee09) | Field merging validation: clarify pair members are distinct (#1136) | Andreas Marek | 151 | | [e9ac8c8](https://github.com/graphql/graphql-spec/commit/e9ac8c8ce46fda6759a29adc61949b9b9356344a) | Editorial: move "Path" to it's own section (#1129) | Rob Richard Benjie | 152 | | [2073bc8](https://github.com/graphql/graphql-spec/commit/2073bc888d92692cd465db47cc544109db9c4181) | Change 'original' to 'previous' to clarify multiple extensions (#1123) | Benjie | 153 | | [5bf400e](https://github.com/graphql/graphql-spec/commit/5bf400e3b2867e6366fc27616b777ccd3388bbfd) | "data" and "errors" appear in the "response", not the "result" (#1130) | Benjie | 154 | | [c37a4a4](https://github.com/graphql/graphql-spec/commit/c37a4a400e2ff61ade66c1c5947e0845a6b85c9f) | Editorial changes for Event Streams (#1099) | Lee Byron | 155 | | [34730e8](https://github.com/graphql/graphql-spec/commit/34730e86a151643f51106ac1a1f35985d3da8caa) | Make the reason argument in `@deprecated` non-nullable (#1040) | Martin Bonnin | 156 | | [df1acea](https://github.com/graphql/graphql-spec/commit/df1acea882d28df22184a7c12449864b239b9dd7) | Fix coercion table for list (#1057) | Benjie | 157 | | [7073e3a](https://github.com/graphql/graphql-spec/commit/7073e3a096c0a3fea9e605079a885d988a59d79f) | enhance(ResolveFieldValue): note that list items may be async (#1066) | Yaacov Rydzinski | 158 | | [e5bddd9](https://github.com/graphql/graphql-spec/commit/e5bddd9c31fcd6796698e4fd059514a5a035bf20) | Fix punctuation in grammar rule (#1084) | Benjie | 159 | | [a80f9ff](https://github.com/graphql/graphql-spec/commit/a80f9ff13b7ef9957d93ebe09e2dc4f2c93aede4) | Consistently spell 'implementers' (#1087) | Benjie | 160 | | [497e333](https://github.com/graphql/graphql-spec/commit/497e333c35a29dbe1ab3d1f24c31a59789843fb6) | Fix reference mistake in subscription execution (#994) | Jan Melcher | 161 | | [7485a34](https://github.com/graphql/graphql-spec/commit/7485a342b1c5f0ba4dbbe270d1f6863f55f7180b) | Reformat the parts of an execution request (#1090) | Benjie | 162 | | [8076f1e](https://github.com/graphql/graphql-spec/commit/8076f1e32a305188b41a71c2fec382b72186b424) | chore: add clarifying note for composite and expand term (#1078) | Jovi De Croock Benjie | 163 | | [b5ecff0](https://github.com/graphql/graphql-spec/commit/b5ecff0b7dfd1ebe8bb8a3de7e9180b93da73c53) | Add definition of "selection set" and clarify serial execution examples (#1032) | Benjie | 164 | | [32d24f6](https://github.com/graphql/graphql-spec/commit/32d24f6fda912253d395639561a88deae0863a8e) | Be strict about error paths format (#1073) | Martin Bonnin Benjie | 165 | | [4ab71e3](https://github.com/graphql/graphql-spec/commit/4ab71e330a41742d0b169be94d42055fad26b130) | Add missing . (#1088) | Benjie | 166 | | [a5da8bb](https://github.com/graphql/graphql-spec/commit/a5da8bb39e3ae44e38e7744e0b7bcb2dba453f97) | ID must always serialize as String would (#1086) | Benjie | 167 | | [0ba7cdf](https://github.com/graphql/graphql-spec/commit/0ba7cdf781125779498df3b45a5b97a697a439ba) | Enforce consistent punctuation in algorithms (#1069) | Benjie | 168 | | [8682a86](https://github.com/graphql/graphql-spec/commit/8682a86cd66cdc6d054c678a3f3ef7a32457e5fc) | Fix 'response error' -> 'request error' (#1016) | Benjie | 169 | | [feac5a5](https://github.com/graphql/graphql-spec/commit/feac5a54c6a95c1d4f7804bfaeb268c8bd206f2c) | Fix punctuation in some algorithms (#1067) | Yaacov Rydzinski | 170 | | [56d6107](https://github.com/graphql/graphql-spec/commit/56d61073137caac3dbea6ec8c3652cc3c8b90d86) | Fix heading level for Required Arguments validation rule (#1055) | Renée | 171 | | [3adfcca](https://github.com/graphql/graphql-spec/commit/3adfcca73644234fbbbb062a5cec9e7703419a9f) | Add explicit definition for BlockString (#1042) | Benjie | 172 | | [6b7c2c4](https://github.com/graphql/graphql-spec/commit/6b7c2c45d7136f7fa727cd64b994d2573d4e8014) | Remove "subscriptions is a significant change" sentence (#983) | Roman Ivantsov Benjie Roman Ivantsov | 173 | | [a5cc6ea](https://github.com/graphql/graphql-spec/commit/a5cc6ea0c9f3850f58ef1947d8eda8c6e593b95a) | Clarify that selection sets cannot be empty (#1025) | Benjie | 174 | | [afc0a35](https://github.com/graphql/graphql-spec/commit/afc0a35d271ba9502c3c68aeda6e6c6fbc223774) | Add links to contributed custom scalar specs at scalars.graphql.org (#1009) | dondonz <13839920+dondonz@users.noreply.github.com> Benjie | 175 | | [4e93488](https://github.com/graphql/graphql-spec/commit/4e93488096479c3fcfcc905126c8d157ad2e8c4c) | Fix ambiguity around when schema definition may be omitted (#987) | Benjie Lee Byron | 176 | | [12b7ad7](https://github.com/graphql/graphql-spec/commit/12b7ad7f0fe6ac3996fd5a2bc564357cd2dcb0bc) | add explanation about argument name uniqueness. (#891) | dugenkui Benjie Gillam | 177 | | [559063c](https://github.com/graphql/graphql-spec/commit/559063cb37c14ed74050f73efd3971ee13ff134d) | Change 'server' to 'service' (#1005) | Benjie | 178 | | [cbb8354](https://github.com/graphql/graphql-spec/commit/cbb83545cf8eeb5106856dda8f9d0b750f553124) | Fix broken license link (#1007) | Lee Byron | 179 | | [e736f78](https://github.com/graphql/graphql-spec/commit/e736f78b3cb5c8abb1d6b2ec5e5102de455f98ed) | Add a style guide to the specification (#1003) | Benjie | 180 | | [193fba3](https://github.com/graphql/graphql-spec/commit/193fba3912a43a5e2c9741f4269d279a018e2829) | field merging - field TYPES must not differ (#979) | Roman Ivantsov Roman Ivantsov Benjie Lee Byron | 181 | | [3d03cab](https://github.com/graphql/graphql-spec/commit/3d03cab7a8ffc455387f486fbab5155c2a7c7f3e) | P30: Fixed the explanatory text for algorithm checking uniqueness of non-repeatable directives (#975) | Roman Ivantsov Roman Ivantsov Lee Byron | 182 | | [342b838](https://github.com/graphql/graphql-spec/commit/342b8381ee0ebd25071697e2cc7e784d539700c7) | P34: implementing field type is either exact match or of covariant type (#974) | Roman Ivantsov Roman Ivantsov Lee Byron | 183 | | [ab865f9](https://github.com/graphql/graphql-spec/commit/ab865f95c000b48bdbe9134c4e53573f1996a5c1) | Provide explicit ref to Value Completion section (#982) | Roman Ivantsov Benjie Gillam Roman Ivantsov | 184 | | [edda836](https://github.com/graphql/graphql-spec/commit/edda83613a999c562afbfec6fba2accb96f058a4) | Changed 'must NOT BE' to 'must not be' (#980) | Roman Ivantsov Roman Ivantsov | 185 | | [3aa021f](https://github.com/graphql/graphql-spec/commit/3aa021fb3651710508a37e13c71b7268189982f9) | separate out IsSubType from IsValidImplementationFieldType (#977) | Yaacov Rydzinski | 186 | | [47a6bfd](https://github.com/graphql/graphql-spec/commit/47a6bfdba35ad9b96cba501a52593d3f04c8c5e9) | Editorial: Clarify intro for inline fragments (#969) | Lee Byron | 187 | | [3885a64](https://github.com/graphql/graphql-spec/commit/3885a64f3dc0f9cb64b43aaf1f77e661d98f4dca) | Editorial: Error Terminology (#966) | Lee Byron Roman Ivantsov Benjie Gillam | 188 | | [9a96fc4](https://github.com/graphql/graphql-spec/commit/9a96fc40f2307af15eecc3a257f85ec49adf50d9) | Editorial: Clarity about subject being a GraphQL service or system (#965) | Lee Byron Roman Ivantsov | 189 | | [57bd86d](https://github.com/graphql/graphql-spec/commit/57bd86d779482e9167d2113a9ba926e2ecb74dcc) | Editorial: Fix reference to object in interface introspection (#964) | Lee Byron Roman Ivantsov | 190 | | [299ce69](https://github.com/graphql/graphql-spec/commit/299ce69388aa7fb0012246e377950cf3fd41439d) | Editorial: Remove inaccurate statement about line terminator within tokens (#963) | Lee Byron Roman Ivantsov | 191 | | [1b8fe7a](https://github.com/graphql/graphql-spec/commit/1b8fe7a68f3552a614ab467ea1313947e9f7b1fc) | Leaf field selections clarification (#958) | Benjie Gillam Roman Ivantsov Lee Byron | 192 | | [a91e158](https://github.com/graphql/graphql-spec/commit/a91e15832682931585b8dad46fc8996df1d29735) | Light editorial around delivery agnostic subscriptions (#959) | Benjie Gillam Roman Ivantsov | 193 | | [bb95060](https://github.com/graphql/graphql-spec/commit/bb950608a161af5fc255835bcce10bc160ae1bc8) | Move punctuation outside quotation marks (#962) | Benedikt Franke | 194 | | [4de8782](https://github.com/graphql/graphql-spec/commit/4de87822d2bc807b746c6a37f6a99bb54d705185) | Clarify query shorthand relationship with directives (#873) | Benjie Gillam Lee Byron | 195 | | [94f73f4](https://github.com/graphql/graphql-spec/commit/94f73f48c12a6bdafa9dc729a89482aa7917303f) | Allow deprecation of input values (field args, directive args, input fields) (#805) | Ivan Goncharov Kevin Smithson Lee Byron Ivan Maximov Stephen Spalding | 196 | | [6b69577](https://github.com/graphql/graphql-spec/commit/6b69577b6e854099ce2595849e0b887c13fe300c) | use `findDog` query from example schema only after defining it (#927) | Thomas Heyenbrock | 197 | | [7dd73e7](https://github.com/graphql/graphql-spec/commit/7dd73e7607665bc84dbac504ae83058c996cffcf) | Define request, note it is transport independent (#949) | Benjie Gillam | 198 | | [84ec339](https://github.com/graphql/graphql-spec/commit/84ec33914393bb46e49e5d7a7fb05e0626daa7a8) | RFC: Allow full unicode range (#849) | Lee Byron Andreas Marek | 199 | | [00b88f0](https://github.com/graphql/graphql-spec/commit/00b88f05c4ae049f649e163a4914c94e58a784bf) | Fix formatting | Lee Byron | 200 | | [a61e35d](https://github.com/graphql/graphql-spec/commit/a61e35d301229c494b8bbd69ab0140b33884a95a) | consistent indentation and punctuation (#925) | Thomas Heyenbrock | 201 | | [266fcca](https://github.com/graphql/graphql-spec/commit/266fcca386518d4b05ed58f2d8f57f1fdaaad7f1) | Rename VariableDefinitions to VariablesDefinition (#916) | Ivan Maximov | 202 | | [7908822](https://github.com/graphql/graphql-spec/commit/7908822d4cbae5ad7136437ca577e8bc56f7efab) | Format the spec with prettier (#727) | Benjie Gillam | 203 | | [c18590c](https://github.com/graphql/graphql-spec/commit/c18590c477d6817d73e19b6c248c9fcc62b03017) | Fix typo in Type System section (#905) | Benoit Lubek | 204 | | [60323c9](https://github.com/graphql/graphql-spec/commit/60323c90dc2699266be7da7f0d4ab293953cd733) | fix typo (#896) | Alex Reilly | 205 | | [357bb72](https://github.com/graphql/graphql-spec/commit/357bb727b5a9dc5b1ed132cc4ffa27c309fb8258) | Start next working draft | Lee Byron | 206 | 207 | Generated with: 208 | 209 | ```sh 210 | git log October2021..f29fbcd2ab5af763fce7ad62896eb62465a669b3 --format="| [%h](https://github.com/graphql/graphql-spec/commit/%H) | %s | %an <%ae> %(trailers:key=Co-authored-by,valueonly,separator=%x20)" -- spec 211 | ``` 212 | 213 | ## Diff 214 | 215 | [Github: diff from last spec cut](https://github.com/graphql/graphql-spec/compare/October2021...f29fbcd2ab5af763fce7ad62896eb62465a669b3?w=1) 216 | --------------------------------------------------------------------------------