GraphQL Specification

repository·main·Indexed 12 days ago

https://github.com/graphql/graphql-spec

The formal rules, syntax, and type system for GraphQL. This specification serves as the authoritative reference for developers building GraphQL-compliant servers, clients, and tooling, covering lexical analysis, syntactic parsing, validation rules, and the GraphQL type system.

Tokens
56.9K
Snippets
150
Records
272
Agent score
96%

What's inside GraphQL

  1. What is GraphQL?

    main

    GraphQL is a query language designed for building client applications. It provides an intuitive and flexible syntax for describing data requirements and interactions.

    Key characteristics include:

    • Not a programming language: It is used to make requests to application services that have capabilities defined by the GraphQL specification.
    • Language/Storage Agnostic: It does not mandate specific programming languages or storage systems; instead, services map their capabilities to the GraphQL type system.
    • Hierarchical Structure: GraphQL requests are structured hierarchically, mirroring the shape of the data in the response.
    • Strong-typing: Every service defines an application-specific type system. This allows tools to validate requests for syntactic and type correctness before execution.
    • Client-specified responses: Clients specify exactly what data they need at field-level granularity. A response contains exactly what was requested and no more.
    • Self-describing: Through introspection, the GraphQL type system can be queried by the GraphQL language itself, allowing for the discovery of capabilities and documentation.
    {
      user(id: 4) {
        name
      }
    }
  2. What is Introspection in GraphQL?

    main
    Introspection is a feature that allows a GraphQL service to support queries over its own schema. By using GraphQL to query the schema itself, developers can build powerful tools like IDEs, documentation generators, and automated validation engines. The introspection system uses reserved names prefixed with __ (two underscores) to avoid collisions with user-defined types and fields.
  3. What is a Source Stream in subscriptions?

    main

    A Source Stream represents a sequence of events, where each event triggers a GraphQL execution. The logic to create a Source Stream is application-specific.

    To create a Source Stream, the service must:

    1. Assert the root Subscription type is an Object type.
    2. Collect the fields in the top-level selection set.
    3. Ensure there is exactly one entry in the grouped field set (otherwise, a request error is raised).
    4. Resolve the field event stream using the field name and argument values.
  4. Use List types to represent collections

    main

    A GraphQL List is a collection type that declares the type of each item within it (the item type). Lists are serialized as ordered sequences. You can denote a list by wrapping the item type in square brackets.

    Syntax

    • Single list: pets: [Pet]
    • Nested lists: matrix: [[Int]]

    Result Coercion (Server Behavior)

    • If the item type is nullable (e.g., [Int]), an error occurring during the coercion of an individual item results in a {null} value at that position in the list, accompanied by an execution error in the response.
    • If the item type is non-null (e.g., [Int!]), an error occurring at an individual item results in an execution error for the entire list.

    Input Coercion (Client Behavior)

    When providing input to a list, if the provided value is not a list and not {null}, GraphQL will coerce it into a list of size one containing that value. This allows clients to pass a single value to an argument that expects a list.

    # Examples of type declarations
    field: [String]
    matrix: [[Int]]
    nonNullList: [Int!]!
  5. Use Non-Null types to disallow null values

    main

    By default, all GraphQL types are nullable. To declare that a field or argument cannot be {null}, use the Non-Null type by appending an exclamation mark (!) to the type name.

    Key Distinctions

    • Selection Sets (Output): Fields are always optional in a selection set (they can be omitted), but if a field is marked Non-Null, it is guaranteed to never return {null} if queried.
    • Arguments (Input): Inputs are optional by default. However, a Non-Null input type is required; it cannot be omitted and it cannot be provided with the literal value {null}.

    Validation Rule

    • A Non-Null type must not wrap another Non-Null type (e.g., String!! is invalid).
    # A non-null String field
    name: String!
    
    # Invalid: Non-null wrapping a non-null
    # field: String!!
  6. What are Unions and how to query them

    main

    A GraphQL Union represents an object that could be one of a list of GraphQL Object types, but provides no guaranteed fields across those types. Unlike interfaces, unions do not define any fields themselves.

    Querying Unions: Because unions define no fields, you cannot query fields directly on a union type. You must use type refining fragments (such as inline fragments) or the __typename meta-field to access specific fields on the underlying object types.

    Constraints:

    • Union members must be Object base types. Scalar, Interface, and Union types cannot be members of a union.
    • All member types in a union must be unique.
    union SearchResult = Photo | Person
    
    type Person {
      name: String
    }
    
    type Photo {
      width: Int
    }
    
    # Valid query using inline fragments
    {
      firstSearchResult {
        ... on Person {
          name
        }
        ... on Photo {
          width
        }
      }
    }
  7. Coercing field arguments

    main

    Arguments provided in an operation must be coerced into the types defined by the schema.

    Rules for Coercion:

    • Variables: If an argument is a {Variable}, its value is retrieved from variableValues. Variables themselves are not coerced during field execution because they are expected to be validated during the initial operation coercion phase.
    • Literals: If an argument is a literal value, it is coerced according to the input coercion rules of the argument's type.
    • Default Values: If no value is provided for an argument, the schema's defaultValue is used. The default value is coerced according to the input coercion rules.
    • Non-Null Constraints: If an argument is a Non-Nullable type and no value is provided (and no default exists) or the value is null, an execution error is raised.

    Note: Any request error raised during argument coercion should be treated as an execution error.

  8. Use fragments to reuse field selections

    main

    Fragments allow you to extract repeated fields into a reusable unit that can be composed into a parent fragment or an operation using the spread operator (...).

    Fragment Definitions

    Fragments must specify a TypeCondition (the type they apply to). They can be specified on object types, interfaces, and unions, but cannot be used on input values (scalars, enumerations, or input objects).

    Fragment Spreads

    Fragments are consumed using the ... FragmentName syntax. Fields selected by the fragment are added to the selection set at the same level as the invocation.

    query withFragments {
      user(id: 4) {
        friends(first: 10) {
          ...friendFields
        }
        mutualFriends(first: 10) {
          ...friendFields
        }
      }
    }
    
    fragment friendFields on User {
      id
      name
      profilePic(size: 50)
    }
  9. Use OneOf Input Objects to represent mutually exclusive options

    main

    A OneOf Input Object is a special variant where exactly one field must be provided and it must be non-null. All other fields must be omitted. This is useful for representing inputs that can be one of several different options.

    To define a OneOf Input Object, use the @oneOf directive. In schema introspection, the __Type.isOneOf field will return true for these types.

    Validation Rules for @oneOf:

    • All fields in a OneOf Input Object must be nullable.
    • Fields must not have default values.
    • The input must contain exactly one entry, and that entry must not be null.
    • You cannot use the @oneOf directive on an Input Object extension.
    input UserUniqueCondition @oneOf {
      id: ID
      username: String
      organizationAndEmail: OrganizationAndEmailInput
    }
  10. Rules for Object type implementation of Interfaces

    main

    An Object type must be a super-set of all interfaces it implements. To be a valid implementation, the following rules apply via the IsValidImplementation(type, implementedType) logic:

    1. Interface Inheritance: If the implementedType (the interface) declares it implements other interfaces, the type (the object) must also declare it implements those same interfaces.
    2. Field Presence: The object type must include a field of the same name for every field defined in the interface.
    3. Argument Invariance: For every field in the interface, the implementing object field must include an argument of the same name, and that argument must accept the exact same type (invariant).
    4. Additional Arguments: An object field may include additional arguments not defined in the interface, but they must not be required (i.e., they must be nullable).
    5. Type Covariance: The return type of the object field must be equal to or a sub-type of the interface field's return type. Valid sub-types include:
      • The same type.
      • An Object type that is a possible type of a Union type defined in the interface.
      • An Object or Interface type that implements the interface type defined in the field.
      • A List type where the item type is a valid sub-type of the interface's item type.
      • A Non-Null variant of a valid sub-type.
  11. Validate directive definitions and locations

    main

    Directives used in a document must meet two criteria:

    1. Definition: The directive must be defined on the service being queried.
    2. Location: The directive must be placed in a valid location as specified by its definition (e.g., on a field, fragment, or argument).
  12. Directives must be used in declared locations

    main

    GraphQL services define which directives they support and the specific locations (e.g., QUERY, FIELD, FRAGMENT_SPREAD) where they can be applied. A document will fail validation if a directive is used in a location that the service has not declared support for.

    For example, using @skip on an operation definition (the query itself) is invalid because @skip does not provide QUERY as a valid location.

    ```graphql
     query @skip(if: $foo) {
       field
     }