[译] GraphQL - 学习 - 内省

原文地址: Introspection

请求一个 GraphQL 语法获取关于它所支持的查询的信息通常是很有用的。GraphQL 允许我们使用内省系统来实现这一功能!

对于我们的星球大战例子来说,starWarsIntrospection-test.js包含大量的查询,演示了自省系统,并且是一个测试文件,可以运行这个文件来执行引用实现的内省系统。

我们设计了类型系统,因此我们知道可用的类型,但是如果没有,我们可以通过查询 __schema 字段来查询GraphQL,它总是在查询的根类型上可用。现在让我们查询可用的类型。

{
  __schema {
    types {
      name
    }
  }
}
{
  "data": {
    "__schema": {
      "types": [
        {
          "name": "Query"
        },
        {
          "name": "Episode"
        },
        {
          "name": "Character"
        },
        {
          "name": "ID"
        },
        {
          "name": "String"
        },
        {
          "name": "Int"
        },
        {
          "name": "FriendsConnection"
        },
        {
          "name": "FriendsEdge"
        },
        {
          "name": "PageInfo"
        },
        {
          "name": "Boolean"
        },
        {
          "name": "Review"
        },
        {
          "name": "SearchResult"
        },
        {
          "name": "Human"
        },
        {
          "name": "LengthUnit"
        },
        {
          "name": "Float"
        },
        {
          "name": "Starship"
        },
        {
          "name": "Droid"
        },
        {
          "name": "Mutation"
        },
        {
          "name": "ReviewInput"
        },
        {
          "name": "__Schema"
        },
        {
          "name": "__Type"
        },
        {
          "name": "__TypeKind"
        },
        {
          "name": "__Field"
        },
        {
          "name": "__InputValue"
        },
        {
          "name": "__EnumValue"
        },
        {
          "name": "__Directive"
        },
        {
          "name": "__DirectiveLocation"
        }
      ]
    }
  }
}

哇~~~,这么多类型!他们是什么? 让我们分组查看下:

  • Query, Character, Human, Episode, Droid - 这些是我们在类型系统中定义的。
  • String,Boolean - 这些是类型系统提供的内建的标量。
  • __Schema, __Type, __TypeKind, __Field, __InputValue, __EnumValue, __Directive - 这些都在前面有一个双下划线,表示它们是自省系统的一部分。

现在,让我们试着找出一个好地方来开始探索哪些查询是可用的。当我们设计我们的类型系统时,我们指定了所有查询的类型;让我们问一下关于这个的内省系统!

{
  __schema {
    queryType {
      name
    }
  }
}
{
  "data": {
    "__schema": {
      "queryType": {
        "name": "Query"
      }
    }
  }
}

这与我们在类型系统部分中所讲的内容相匹配,Query 类型是我们将要开始的地方!注意这里的命名只是按照惯例;我们可以将 Query 类型命名为其他任何东西,如果我们指定它是查询的开始类型,它仍然会在这里返回。不过,命名 Query 是一种常用的约定。

检查一个特定的类型通常是有用的。让我们来看看 Droid 的类型:

{
  __type(name: "Droid") {
    name
  }
}
{
  "data": {
    "__type": {
      "name": "Droid"
    }
  }
}

如果我们想知道更多关于Droid的信息呢? 例如,它是一个接口还是一个对象?

{
  __type(name: "Droid") {
    name
    kind
  }
}
{
  "data": {
    "__type": {
      "name": "Droid",
      "kind": "OBJECT"
    }
  }
}

kind 类型返回一个 __TypeKind 的枚举,其中一个值是 OBJECT。如果我们查询 Character,我们会发现它是一个接口:

{
  __type(name: "Character") {
    name
    kind
  }
}
{
  "data": {
    "__type": {
      "name": "Character",
      "kind": "INTERFACE"
    }
  }
}

对于对象来说,知道哪些字段可用是很有用的,所以让我们来询问一下关于 Droid 的内省系统:

{
  __type(name: "Droid") {
    name
    fields {
      name
      type {
        name
        kind
      }
    }
  }
}
{
  "data": {
    "__type": {
      "name": "Droid",
      "fields": [
        {
          "name": "id",
          "type": {
            "name": null,
            "kind": "NON_NULL"
          }
        },
        {
          "name": "name",
          "type": {
            "name": null,
            "kind": "NON_NULL"
          }
        },
        {
          "name": "friends",
          "type": {
            "name": null,
            "kind": "LIST"
          }
        },
        {
          "name": "friendsConnection",
          "type": {
            "name": null,
            "kind": "NON_NULL"
          }
        },
        {
          "name": "appearsIn",
          "type": {
            "name": null,
            "kind": "NON_NULL"
          }
        },
        {
          "name": "primaryFunction",
          "type": {
            "name": "String",
            "kind": "SCALAR"
          }
        }
      ]
    }
  }
}

这些是我们在 Droid 上定义的字段!

id 看起来有点奇怪,它没有类型的名称。这是因为它是一种 NON_NULL 类型的 "wrapper" 类型。如果我们在该字段的类型中查询 ofType,我们会在那里找到 ID 类型,告诉我们这是一个非空ID。

类似地,friendsappearsIn 都没有名字,因为它们是 LIST 包装器类型。我们可以查询这些类型的 ofType ,它会告诉我们这些是什么列表

{
  __type(name: "Droid") {
    name
    fields {
      name
      type {
        name
        kind
        ofType {
          name
          kind
        }
      }
    }
  }
}
{
  "data": {
    "__type": {
      "name": "Droid",
      "fields": [
        {
          "name": "id",
          "type": {
            "name": null,
            "kind": "NON_NULL",
            "ofType": {
              "name": "ID",
              "kind": "SCALAR"
            }
          }
        },
        {
          "name": "name",
          "type": {
            "name": null,
            "kind": "NON_NULL",
            "ofType": {
              "name": "String",
              "kind": "SCALAR"
            }
          }
        },
        {
          "name": "friends",
          "type": {
            "name": null,
            "kind": "LIST",
            "ofType": {
              "name": "Character",
              "kind": "INTERFACE"
            }
          }
        },
        {
          "name": "friendsConnection",
          "type": {
            "name": null,
            "kind": "NON_NULL",
            "ofType": {
              "name": "FriendsConnection",
              "kind": "OBJECT"
            }
          }
        },
        {
          "name": "appearsIn",
          "type": {
            "name": null,
            "kind": "NON_NULL",
            "ofType": {
              "name": null,
              "kind": "LIST"
            }
          }
        },
        {
          "name": "primaryFunction",
          "type": {
            "name": "String",
            "kind": "SCALAR",
            "ofType": null
          }
        }
      ]
    }
  }
}

让我们以自省系统的一个特性来结束,这对工具来说特别有用;让我们向系统询问文档!

{
  __type(name: "Droid") {
    name
    description
  }
}
{
  "data": {
    "__type": {
      "name": "Droid",
      "description": "An autonomous mechanical character in the Star Wars universe"
    }
  }
}

因此,我们可以使用内省来访问关于类型系统的文档,并创建文档浏览器,或者丰富的 IDE 体验。

这只是触及了自省系统的皮毛; 我们可以查询枚举值,类型实现的接口,等等。我们甚至可以对内省系统本身进行反思。规范在 "Introspection" 部分和 GraphQL 中的内省文件中详细讨论了这个主题。js包含实现符合规范的 GraphQL 查询内省系统的代码。

阅读 877

推荐阅读
酸柠檬
用户专栏

柠檬是苦的. 酸柠檬更不知道是什么味道这就是程序的味道个中滋味, 无法对外人道深思回味, 终得豁然

18 人关注
44 篇文章
专栏主页