Description
Problem: There are a few issues one runs into when using the introspection of a schema to get the return types of fields.
- nested query required for each NonNull and List means never guaranteed to get the full return type of a field on the first query
- requires more effort than necessary to piece together the return type of a field
Example:
type StringTable {
values: [[String!]!]!
}
As seen, StringTable is a simple container for a string[][]. The query just to find that out would look like this:
{
__type(name:"StringTable") {
kind
name
fields {
name
type {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
}
}
}
}
}
}
}
}
}
The output of which is as follows:
{
"data": {
"__type": {
"kind": "OBJECT",
"name": "StringTable",
"fields": [
{
"name": "values",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String"
}
}
}
}
}
}
}
]
}
}
}
All that just for just one field is unnecessary. It's even worse when viewing several fields for several types. If there were another List added for some reason, the query would need to be modified to add another level and resent. To avoid the process of modifying and resending queries, the initial query usually includes several levels to start.
Solution: I'd like to propose adding two fields to __Type: namedType
and punctuatedName
.
extend type __Type {
namedType: __Type!
punctuatedName: String!
}
namedType
returns the underlying named type, found by continually unwrapping the type until a named type is found - i.e. the type with all non-null and list wrappers removed.
punctuatedName
returns the name of the (wrapped) type as it would be expressed in GraphQL's IDL; i.e. the underlying named types' name with additional punctuators from wrapping Lists and NonNulls.
Depending on the type's kind, namedType
would resolve to the following:
- Lists & NonNulls:
namedType := ofType.namedType
- All other types:
namedType
would yield a reference to itself.
Depending on the type's kind, punctuatedName
would resolve to the following:
- Lists:
punctuatedName := '[' + ofType.punctuatedName + ']'
- NonNulls:
punctuatedName := ofType.punctuatedName + '!'
- All other types:
punctuatedName := name
Adding namedType
and punctuatedName
to __Type would allow for the following query:
{
__type(name:"StringTable") {
kind
name
fields {
name
type {
name
namedType {
kind
name
}
punctuatedName
}
}
}
}
Which would yield the following output:
{
"data": {
"__type": {
"kind": "OBJECT",
"name": "StringTable",
"fields": [
{
"name": "values",
"type": {
"name": null,
"namedType": {
"kind": "SCALAR",
"name": "String"
},
"punctuatedName": "[[String!]!]!"
}
}
]
}
}
}
As seen, that is a much more compact query and response. It would also guarantee to provide a return information about the fields base type or punctuated name for any given field on the first request.