By using the type system, it can be predetermined whether a GraphQL query is valid or not. This allows servers and clients to effectively inform developers when an invalid query has been created, without having to rely on runtime checks.
For our Star Wars example, the file starWarsValidation-test.ts contains a number of queries demonstrating various invalidities, and is a test file that can be run to exercise the reference implementation's validator.
To start, let's take a complex valid query. This is a nested query, similar to an example from the previous section, but with the duplicated fields factored out into a fragment:
And this query is valid. Let's take a look at some invalid queries...
A fragment cannot refer to itself or create a cycle, as this could result in an unbounded result! Here's the same query above but without the explicit three levels of nesting:
When we query for fields, we have to query for a field that exists on the
given type. So as hero
returns a Character
, we have to query for a field
on Character
. That type does not have a favoriteSpaceship
field, so this
query is invalid:
Whenever we query for a field and it returns something other than a scalar
or an enum, we need to specify what data we want to get back from the field.
Hero returns a Character
, and we've been requesting fields like name
and
appearsIn
on it; if we omit that, the query will not be valid:
Similarly, if a field is a scalar, it doesn't make sense to query for additional fields on it, and doing so will make the query invalid:
Earlier, it was noted that a query can only query for fields on the type
in question; when we query for hero
which returns a Character
, we
can only query for fields that exist on Character
. What happens if we
want to query for R2-D2s primary function, though?
That query is invalid, because primaryFunction
is not a field on Character
.
We want some way of indicating that we wish to fetch primaryFunction
if the
Character
is a Droid
, and to ignore that field otherwise. We can use
the fragments we introduced earlier to do this. By setting up a fragment defined
on Droid
and including it, we ensure that we only query for primaryFunction
where it is defined.
This query is valid, but it's a bit verbose; named fragments were valuable above when we used them multiple times, but we're only using this one once. Instead of using a named fragment, we can use an inline fragment; this still allows us to indicate the type we are querying on, but without naming a separate fragment:
This has just scratched the surface of the validation system; there are a number of validation rules in place to ensure that a GraphQL query is semantically meaningful. The specification goes into more detail about this topic in the "Validation" section, and the validation directory in GraphQL.js contains code implementing a specification-compliant GraphQL validator.