Advanced GraphQL: Query Validation and Introspection #11

Deep dive into the GraphQL Query Validation and Schema Introspection and how to work with them


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.
. . .

Query Validation

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.

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:
{
empireHero: person(id: 1) {
...PersonFields
mass
}
}

fragment PersonFields on Person {
name
gender
birth_year
}

Run the below sandbox to see the query in action

. . .
When we query for fields, we have to query for a field that exists on the given type. So as person returns a Person, we have to query for a field on Person. we are querying password field which is not part of Person, so this query is invalid:
{
empireHero: person(id: 1) {
...PersonFields
mass
}
}

fragment PersonFields on Person {
name
gender
birth_year
password #field that does not exists
}

Run the below sandbox to see the query in action
It will give the following error:
{
"errors": [
{
"message": "Cannot query field \"password\" on type \"Person\".",
"locations": [
{
"line": 4,
"column": 5
}
]
}
]
}
. . .
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.

Person returns a Person, and we've been requesting fields like name and age, etc. on it; if we omit that, the query will not be valid:
# INVALID: person is not a scalar, so fields are needed
{
person(id: 1)
}

Run the below sandbox to see the query in action
It will give the following error:
{
"errors": [
{
"message": "Field \"person\" of type \"Person\" must have a selection of subfields. Did you mean \"person { ... }\"?"
"locations": [
{
"line": 3,
"column": 3
}
]
}
]
}

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.
. . .

Schema Introspection

It's often useful to ask a GraphQL schema for information about what queries it supports. GraphQL allows us to do so using the introspection system!
We can ask GraphQL, by querying the __schema field, always available on the root type of a Query. Let's do so now, and ask what types are available.
{
__schema {
types {
name
}
}
}

Below sandbox lists the types it has with their names:
Wow, that's a lot of types! What are they? Let's group them:
  • Person, Planet, Film, Starship, Vehicle- These are the ones that we defined in our type system.
  • String, Boolean - These are built-in scalars that the type system provided.
  • __Schema, __Type, __TypeKind, __Field, __InputValue, __EnumValue, __Directive - These all are preceded with a double underscore, indicating that they are part of the introspection system.
. . .
Now, let's try and figure out a good place to start exploring what queries are available. When we designed our type system, we specified what type all queries would start at; let's ask the introspection system about that!
{
__schema {
queryType {
name
}
}
}

And that matches what we said in the type system section, that the Query type is where we will start! Note that the naming here was just by convention.

We could have named our Query type anything else, and it still would have been returned here had we specified it was the starting type for queries. Naming it Query, though, is a useful convention.
. . .
It's useful for an object to know what fields are available, so let's ask the introspection system about Person:

Those are the fields that we defined on Person!

This has just scratched the surface of the introspection system; we can query for enum values, what interfaces a type implements, and more. We can even introspect on the introspection system itself.

The specification goes into more detail about this topic in the "Introspection" section, and the introspection file in GraphQL.js contains code implementing a specification-compliant GraphQL query introspection system.
. . .
In the next tutorial, we will look into the advanced GraphQL concepts such as Query execution and resolvers


On a mission to build Next-Gen Community Platform for Developers