gqlparser

repository·master·Indexed 20 days ago

https://github.com/vektah/gqlparser

A high-performance, spec-compliant GraphQL parser for Go. Designed as a stable, server-agnostic tool that closely follows the graphql-js reference implementation, it serves as the core parsing engine for projects like gqlgen. It supports Schema Definition Language (SDL), block strings as descriptions, and error paths & extensions, targeting the September 2025 GraphQL specification.

Tokens
2.2K
Snippets
9
Records
15
Agent score
68%

What's inside gqlparser

  1. Overview of gqlparser

    master

    gqlparser is a GraphQL parser written in Go. It is designed to mirror the graphql-js reference implementation closely while remaining idiomatic, fast, and easy to use. It is the underlying parser used by gqlgen and is intended to be server-agnostic, making it suitable for both GraphQL server implementations and client-side tooling.

    Key characteristics include:

    • Spec Compliance: Targets the September 2025 GraphQL specification and select portions of the Draft, based on graphql-js v16.13.2. It supports Schema Definition Language (SDL), block strings as descriptions, and error paths & extensions.
    • Design Principles: Focuses on maintainability, high test coverage (self-contained tests without requiring a server), stability, and performance (minimizing allocations in hot paths).
  2. Redeclaring builtin directives

    master

    In gqlparser, redeclaring the six builtin directives—include, skip, deprecated, specifiedBy, defer, and oneOf—is silently accepted, and the first definition encountered is kept. This is an intentional design choice to allow servers to handle divergent or older spec versions without error.

    Note: This only applies to builtins. Redeclaring non-builtin directives will correctly return an error.

  3. Extend undefined types (Ghost Types)

    master

    Unlike graphql-js, gqlparser allows you to extend types that are not defined within the current document. This is an intentional divergence designed to support federation-style schemas where types are extended without a local base definition.

    Consequences:

    • gqlparser creates a synthetic Definition for the missing type.
    • If the extension provides at least one field and all types referenced within that extension exist, the "ghost type" becomes a valid Object type in the compiled schema.
    • Warning: A typo in an extension's type name will not trigger an error; instead, it will create a new, unexpected "ghost" type.
  4. Understand the validation behavior of `ValidateSchemaDocument`

    master

    When using gqlparser to validate a schema document, be aware of two fundamental architectural behaviors that differ from graphql-js:

    1. Fail-fast vs. Accumulate: gqlparser returns on the first error encountered. Unlike graphql-js, which collects all errors in a single pass, gqlparser will only surface one violation at a time. A schema with multiple errors will require multiple validation passes to identify all of them.

    2. Isolated Validation: gqlparser validates a single SchemaDocument in isolation. It does not carry a pre-existing schema context (like SDLValidationContext in graphql-js). Therefore, it cannot perform checks that require knowledge of a schema outside the current document (e.g., checking if a type being extended already exists in a separate, previously loaded schema).

  5. Update the graphql.js spec importer

    master

    The validator/imported directory contains GraphQL specifications generated from the graphql/graphql-js testsuite. To update these specs to the latest version, you must run the export script.

    Warning: Do not make direct modifications to most files in this directory. Instead, use the exporter to ensure consistency with the source graphql-js testsuite.

    To update to the latest version, clear the existing log and run the export script:

    rm graphql-js-commit.log && ./export.sh

    To re-generate using the specific revision recorded in graphql-js-commit.log:

    ./export.sh
    # update to latest
    $ rm graphql-js-commit.log && ./export.sh
    
    # re-generate with known revision set in graphql-js-commit.log
    $ ./export.sh
  6. Manual steps after updating graphql.js specs

    master

    After running the export script to update the imported specs, you must manually synchronize the following files to reflect the changes:

    1. validator/prelude.graphql
    2. validator/schema.go
    3. Any relevant files in ./validator/rules/ that are affected by the specific changes.

    When submitting a Pull Request (PR) for these updates, ensure you include the git release tag from graphql-js that corresponds to the commit used for the update.

  7. Be aware of duplicate argument names in fields and directives

    master

    Currently, gqlparser does not check for duplicate argument names within the same list. Both field arguments and directive arguments are unprotected. If you define multiple arguments with the same name in a single field or directive, gqlparser will not return an error, whereas graphql-js would reject it.

    Example of unsupported validation (will not error in gqlparser):

    type Query {
      field(id: ID, id: String): Boolean
    }
  8. Handle silent overwrites of operation types in `schema` blocks

    master

    In gqlparser, specifying the same operation type (query, mutation, or subscription) multiple times results in a silent overwrite rather than a validation error. The last definition provided will be the one used in the compiled schema. This occurs in three scenarios:

    1. Duplicate within one schema {} block: schema { query: A query: B } results in query being B.
    2. Multiple extend schema blocks: If two different extend schema blocks specify the same operation, the second one overwrites the first.
    3. Redefining a base operation: If an extend schema block re-specifies an operation already defined in the base schema {} block, the base operation is overwritten.

    Example of silent overwrite (Case C):

    schema { query: Query }
    extend schema { query: Other }

    Result: schema.Query will point to Other.

  9. Reference: Supported Unique Constraints in gqlparser

    master

    The following uniqueness constraints are fully covered and validated by gqlparser:

    • UniqueTypeNames: Catches duplicate type definitions in the document.
    • UniqueFieldDefinitionNames: Catches duplicate fields within a definition, across extensions, and across multiple extensions.
    • UniqueEnumValueNames: Catches duplicate enum values within a definition and across extensions.
    • UniqueDirectivesPerLocation (SDL): Rejects repeated non-repeatable directives at single-authored locations (fields, enum values, arguments, and schema/extend schema lists).
    • LoneSchemaDefinition: Ensures only one schema definition exists within a single document.
  10. Load a GraphQL schema with MustLoadSchema

    master

    Use MustLoadSchema when you want to load a schema and expect it to succeed. If the schema is invalid or cannot be parsed, this function will panic. This is typically used during application initialization with hardcoded or trusted schema files.

    schema := gqlparser.MustLoadSchema(&ast.Source{Input: "type Query { hello: String }"})
  11. Deprecated: Load a query with MustLoadQuery

    master

    ⚠️ Deprecated: Use MustLoadQueryWithRules instead. MustLoadQuery parses and validates a query, panicking on failure.

    // Deprecated
    query := gqlparser.MustLoadQuery(schema, "query { hello }")
  12. Load and validate a query with MustLoadQueryWithRules

    master

    Use MustLoadQueryWithRules to parse and validate a query with specific rules, panicking if the query is invalid. This is useful for testing or when working with trusted queries where failure is considered a programmer error.

    query := gqlparser.MustLoadQueryWithRules(schema, "query { hello }", rules)