GraphQL Query Validator
Check if a GraphQL query/mutation/subscription is syntactically valid and show the operation tree.
GraphQL query validation: what really happens before execution
GraphQL is a query language and runtime for APIs designed by Facebook in 2012 and open-sourced in 2015. Unlike REST, where each endpoint hardcodes a payload, a GraphQL server exposes a single endpoint that accepts a typed query. Before the server runs the query, it goes through three deterministic phases — parsing, validation and execution — defined by the spec at spec.graphql.org.
Parsing turns the query string into an Abstract Syntax Tree (AST); validation type-checks the AST against the server schema; execution resolves each field against data sources. A valid query is one that succeeds at every step before resolvers run, which means errors are caught early and never charge the database.
Query syntax in one sample
query GetUser($id: ID!) {
user(id: $id) {
id
name
posts {
title
publishedAt
}
}
}
Elements at play: the operation type (query, mutation, subscription), an operation name (GetUser), variables ($id: ID!), fields, sub-selections and (optionally) directives, fragments and aliases.
The validation rules defined by the spec
The GraphQL specification defines roughly two dozen named validation rules. Highlights:
- ScalarLeafs — scalar fields (String, Int, Boolean) cannot carry sub-selections.
- FieldsOnCorrectType — every field must exist on its parent type.
- ArgumentsOfCorrectType + RequiredArguments — arguments must match declared types and non-null arguments must be supplied.
- UniqueFragmentNames, NoUnusedFragments, NoFragmentCycles — fragment hygiene.
- FragmentsOnCompositeTypes — fragments are only valid on object, interface and union types.
- KnownDirectives, UniqueDirectivesPerLocation — directives must exist and not collide.
- VariablesAreInputTypes, VariablesInAllowedPosition — variables are constrained to input types and proper positions.
Tooling: from graphql.js to Hasura
- graphql.js — the JavaScript reference implementation; ships the parser, validator and executor and is reused by virtually every Node server.
- Apollo Server and GraphQL Yoga — full-featured Node servers built on top of
graphql.js. - Hasura — instant GraphQL over Postgres, MySQL and SQL Server with auto-generated schema.
- Strawberry (Python), Async-graphql (Rust), JuniperGraphQL (Rust), gqlgen (Go) — strong implementations outside the Node world.
- graphql-codegen — generates TypeScript types and typed hooks from the schema and operations.
- graphql-tools/validate — pluggable validator used in custom pipelines.
Schema-first vs code-first design
Two opposing styles dominate:
- Schema-first — write SDL (
type Query { ... }) in.graphqlfiles and bind resolvers later. Documentation lives next to the contract. - Code-first — define types using decorators or builders in your language (NestJS, Strawberry, Pothos). The schema is derived from code, keeping TypeScript / Python types as the single source of truth.
Operational concerns: N+1, depth limits, persisted queries
Production GraphQL has a few classic pitfalls:
- N+1 problem — naive resolvers issue one DB query per child node. Solved with the DataLoader pattern (per-request batch + cache).
- Depth and complexity limits — public APIs must guard against deeply nested queries used as DoS. Plugins like
apollo-server-plugin-depth-limitandgraphql-cost-analysisreject queries above a threshold. - Introspection — clients can query
__schemato discover types; production deployments often disable introspection to slow down reconnaissance. - Persisted queries — clients send a hash instead of the full query string; server matches it against an allow-list, eliminating injection and shrinking payloads.
- Authorization — applied per-field via directives or middleware, never at the endpoint level (the endpoint is shared).
Federation, REST comparison and the wider ecosystem
Apollo Federation 2 and schema stitching let multiple services contribute to one super-graph, each owning a slice of the types — useful for micro-services. Compared to REST, GraphQL solves both over-fetching (clients ask only for fields they need) and under-fetching (one round-trip per screen rather than several). Compared to gRPC, GraphQL is HTTP-friendly and human-readable, while gRPC wins on binary efficiency for service-to-service traffic.
FAQ
Can I validate a query offline, without hitting the server?
Yes. As long as you have the schema (SDL or introspection JSON), graphql.js parses and validates queries locally — useful in CI to fail PRs that break the contract.
Should I enable a depth limit?
For any public API, yes. A common configuration caps depth at 8-10 and uses cost analysis for cross-field complexity. Without it, a single nested query can take down the database.
How is authorization handled?
At the field level, not at the endpoint. Patterns include directive-based (@auth), middleware in resolvers or graph-level wrappers like graphql-shield.
Does this tool require the schema?
No. It runs lightweight syntax-level validation on the query string: detects operation type, name, variables and the field tree. Full type checking requires the schema and is typically done in CI with graphql-codegen or graphql-eslint.
Can I disable introspection in production?
Yes — Apollo Server, Yoga and most frameworks expose a flag (introspection: false). It is a defense-in-depth measure rather than a security boundary; combine with authentication and persisted queries.
Related Tools
CPF Validator
Validate Brazilian CPF numbers instantly using the official algorithm. Useful for testing document validation in applications. No data sent to servers.
Batch CPF Validator
Validate a list of CPFs (one per line) and see which are valid and which are not. No data sent to servers.
Batch CNPJ Validator
Validate a list of CNPJs (one per line) with a summary of valid, invalid and total. No data sent to servers.