'How can we introspect a GraphQL schema recursively?
If a customer does not know the schema and would like to introspect and understand a GraphQL API, it seems that GraphQL may not be able to support the recursive introspection. See the following example about my point
First of all, the following is my schema definition at high level:
// schema.js
...
...
const AuthorType = new GraphQLObjectType({
name: "Author",
description: "This represent an author",
fields: () => ({
id: {type: new GraphQLNonNull(GraphQLString)},
name: {type: new GraphQLNonNull(GraphQLString)},
twitterHandle: {type: GraphQLString}
})
});
const PostType = new GraphQLObjectType({
name: "Post",
description: "This represent a Post",
fields: () => ({
id: {type: new GraphQLNonNull(GraphQLString)},
title: {type: new GraphQLNonNull(GraphQLString)},
body: {type: GraphQLString},
author: {
type: AuthorType,
resolve: function(post) {
return _.find(Authors, a => a.id == post.author_id);
}
}
})
});
// This is the Root Query
const BlogQueryRootType = new GraphQLObjectType({
name: 'BlogAppSchema',
description: "Blog Application Schema Query Root",
fields: () => ({
authors: {
type: new GraphQLList(AuthorType),
description: "List of all Authors",
resolve: function() {
return Authors
}
},
posts: {
type: new GraphQLList(PostType),
description: "List of all Posts",
resolve: function() {
return Posts
}
}
})
});
When someone queries the schema using the following query clause:
{
__type(name: "BlogAppSchema") {
name
fields {
name
description
type {
name
}
}
}
}
She gets the following result:
{
"data": {
"__type": {
"name": "BlogAppSchema",
"fields": [
{
"name": "authors",
"description": "List of all Authors",
"type": {
"name": null
}
},
{
"name": "posts",
"description": "List of all Posts",
"type": {
"name": null
}
}
]
}
}
}
Reading the source code, we know that authors are a list of AuthorType. But how can a user, not having access the source code, further introspect the field of 'authors' from the results she got above (the type field shows "null" here)? She does not seem to be able to know authors
is a list of Author
from the above result. Is there a way for her to further introspect?
Solution 1:[1]
The name
field returns null because your AuthorType
is wrapped with the GraphQLList wrapper. That means the field is returning information about the wrapper, not the underlying type. To get to the type, you have modify your request:
{
__type(name: "BlogAppSchema") {
name
fields {
name
description
type {
name
kind # this will show NON_NULL, LIST, SCALAR or OBJECT
ofType { # if NON_NULL or LIST what is it a non-null or list *of*
name
kind
# other fields, like "fields" which will be populated for an OBJECT
}
}
}
}
}
If you utilize multiple wrappers (i.e. [Author]! or [Author!]!), you will need to "go deeper" and request the nested ofType
fields:
{
__type(name: "BlogAppSchema") {
name
fields {
name
description
type {
name
kind
ofType {
name
kind
ofType {
name
kind
ofType {
name
kind
ofType {
name
kind
}
}
}
}
}
}
}
}
If the kind
is OBJECT
, its fields
field will be populated appropriately. You can then request details for each field as in above. Of course, if there are any OBJECTs returned from those fields, you'll have to specify what information you want to get from those.
You can read more about introspection here.
Introspection can be very messy. If you need a way for the consumer of your GraphQL endpoint to explore the schema, GraphiQL is a much more user-friendly way of doing that. There's also ways of dynamically generating documentation (like this).
Solution 2:[2]
Is there any way of querying it recursively automatically, instead of like Daniel Rearden mentioned it with
{
__type(name: "BlogAppSchema") {
name
fields {
name
description
type {
name
kind
ofType {
name
kind
ofType {
name
kind
ofType {
name
kind
ofType {
name
kind
}
}
}
}
}
}
}
}
Meaning that we don't have to specify all these deep nested ofType
queries?
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Daniel Rearden |
Solution 2 | rexloxrix |