内省

我们有时候会需要去问 GraphQL Schema 它支持哪些查询。GraphQL 通过内省系统让我们可以做到这点!

在我们的星战例子里,文件 starWarsIntrospection-test.js 包含了一系列展示了内省系统的查询,它也是一个测试文件,用来检验参考实现的内省系统。

如果是我们亲自设计了类型,那我们自然知道哪些类型是可用的。但如果类型不是我们设计的,我们也可以通过查询 __schema 字段来向 GraphQL 询问哪些类型是可用的。一个查询的根类型总是有 __schema 这个字段。现在来试试,查询一下有哪些可用的类型。

  1. # { "graphiql": true }
  2. {
  3. __schema {
  4. types {
  5. name
  6. }
  7. }
  8. }

哇,有好多类型!它们都是什么?我们来总结一下:

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

现在,来试试找到一个可以探索出有哪些可用查询的地方。当我们设计类型系统的时候,我们确定了一个所有查询开始的地方,来问问内省系统它是什么!

  1. # { "graphiql": true }
  2. {
  3. __schema {
  4. queryType {
  5. name
  6. }
  7. }
  8. }

这和我们在类型系统那章里说的一样,Query 类型是我们开始的地方!注意这里的命名只是一个惯例,我们也可以把 Query 取成别的名字,只要我们把它定义为所有查询出发的地方,它也依然会在这里被返回。尽管如此,还是把它命名为 Query 吧,这是一个有用的惯例。

有时候也需要检验一个特定的类型。来看看 Droid 类型:

  1. # { "graphiql": true }
  2. {
  3. __type(name: "Droid") {
  4. name
  5. }
  6. }

如果我们想要更了解 Droid 呢?例如,它是一个接口还是一个对象?

  1. # { "graphiql": true }
  2. {
  3. __type(name: "Droid") {
  4. name
  5. kind
  6. }
  7. }

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

  1. # { "graphiql": true }
  2. {
  3. __type(name: "Character") {
  4. name
  5. kind
  6. }
  7. }

对于一个对象来说,知道它有哪些字段是很有用的,所以来问问内省系统 Droid 有哪些字段:

  1. # { "graphiql": true }
  2. {
  3. __type(name: "Droid") {
  4. name
  5. fields {
  6. name
  7. type {
  8. name
  9. kind
  10. }
  11. }
  12. }
  13. }

这些正是我们为 Droid 定义的字段!

id 看起来有点儿奇怪,这个类型没有名字。这是因为它是一个 NON_NULL 类型的“包装” 。如果我们请求它的 ofType 字段,我们会发现它是 ID ,告诉我们这是一个非空的 ID。

相似地,friendsappearsIn 都没有名字,因为它们都是 LIST 包装类型。我们可以看看它们的 ofType,就能知道它们是装什么东西的列表。

  1. # { "graphiql": true }
  2. {
  3. __type(name: "Droid") {
  4. name
  5. fields {
  6. name
  7. type {
  8. name
  9. kind
  10. ofType {
  11. name
  12. kind
  13. }
  14. }
  15. }
  16. }
  17. }

最后我们来看看内省系统特别适合用来开发工具的特性,我们来向内省系统请求文档!

  1. # { "graphiql": true }
  2. {
  3. __type(name: "Droid") {
  4. name
  5. description
  6. }
  7. }

因此我们可以通过内省系统接触到类型系统的文档,并做出文档浏览器,或是提供丰富的 IDE 体验。

这些只是内省系统的浅浅一层。我们还可以查询枚举值、某个类型实现了什么接口等等,我们甚至可以对内省系统内省。关于这个主题的详细说明可以看规范的“Introspection”部分,以及 GraphQL.js 中的 introspection 文件,它包含了符合规范的一个内省系统的实现。