GraphQL - Introspection 内省系统

官方文档

1. 概述

通过内省系统(Introspection System,也叫自检系统),我们可以知道服务端支持哪些查询,有哪些字段及字段类型等信息。
__Schema, __Type, __TypeKind, __Field, __InputValue, __EnumValue, __Directive 这些用两个下划线开头的类型是内省系统的一部分。

// 查询 GitHub 中的 queryType 类型(查询入口)的字段类型、字段名和描述信息
query{
  __schema {
    queryType {
      kind
      name
      description
    }
  }
}
// 返回
{
  "data": {
    "__schema": {
      "queryType": {
        "kind": "OBJECT",
        "name": "Query",
        "description": "The query root of GitHub's GraphQL interface."
      }
    }
  }
}
// 查询 GitHub 中的 User 类型中的所有的字段名和字段类型
query {
  __type(name:"User") {
    name
    fields {
      name
      type {
        name
      }
    }
  }
}

// 返回
{
  "data": {
    "__type": {
      "name": "User",
      "fields": [
        {
          "name": "avatarUrl",
          "type": {
            "name": null
          }
        },
        // 省略了部分数据
        {
          "name": "watching",
          "type": {
            "name": null
          }
        },
        {
          "name": "websiteUrl",
          "type": {
            "name": "URI"
          }
        }
      ]
    }
  }
}

2. 原则

约定

内省系统所需的类型和字段以两个下划线作为前缀,避免了与用户定义的 GraphQL 类型的冲突。
内省系统中的所有类型都提供了一个 description 字段,类型是 String,可以对字段做简单的描述。

弃用

为了支持向后兼容性的管理,GraphQL 字段和枚举值可以指示它们是否被弃用(isDeprecated: Boolean),并说明它为什么被弃用(deprecationReason: String)。

类型名称自省

在查询任何对象,接口或联合时,GraphQL 支持在元字段的查询中的任何点处进行类型名称自省。它返回当前被查询的对象类型的名称。
类型名称自省,就是在查询对象中可以使用查询对象类型的名称,经常用在查询 Interface 或 Union 类型以确定返回哪些可能类型的实际类型。参考下面例子:

// 请求,查询时指定 __typename,返回数据会把这个字段填充为本次查询的对象名称。
{
  __type(name: "User") {
    __typename
    name
  }
}
// 响应
{
  "data": {
    "__type": {
      "__typename": "__Type",
      "name": "User"
    }
  }
}

3 服务端定义内省系统

3.1 入口字段

内省系统的元字段(内省系统的入口)是隐含的,不会出现在查询操作的根类型的字段列表中。元字段有两个:

  • __schema: __Schema!
  • __type(name: String!): __Type

3.2 GraphQL 内省系统定义的模式:

type __Schema {
  types: [__Type!]!
  queryType: __Type!
  mutationType: __Type
  directives: [__Directive!]!
}
type __Type {
  kind: __TypeKind!
  name: String
  description: String

  # OBJECT and INTERFACE only
  fields(includeDeprecated: Boolean = false): [__Field!]
  # OBJECT only
  interfaces: [__Type!]
  # INTERFACE and UNION only
  possibleTypes: [__Type!]
  # ENUM only
  enumValues(includeDeprecated: Boolean = false): [__EnumValue!]
  # INPUT_OBJECT only
  inputFields: [__InputValue!]
  # NON_NULL and LIST only
  ofType: __Type
}
type __Field {
  name: String!
  description: String
  args: [__InputValue!]!
  type: __Type!
  isDeprecated: Boolean!
  deprecationReason: String
}
type __InputValue {
  name: String!
  description: String
  type: __Type!
  defaultValue: String
}
type __EnumValue {
  name: String!
  description: String
  isDeprecated: Boolean!
  deprecationReason: String
}
enum __TypeKind {
  SCALAR
  OBJECT
  INTERFACE
  UNION
  ENUM
  INPUT_OBJECT
  LIST
  NON_NULL
}
type __Directive {
  name: String!
  description: String
  locations: [__DirectiveLocation!]!
  args: [__InputValue!]!
}
enum __DirectiveLocation {
  QUERY
  MUTATION
  FIELD
  FRAGMENT_DEFINITION
  FRAGMENT_SPREAD
  INLINE_FRAGMENT
}

3.3 __Type

__Type 是内省系统的核心,代表系统中的标量,接口,对象类型,联合,枚举。可以查询一个具体的对象的详细信息。
__Type 也代表类型修饰符,用于修改它引用的类型(ofType: __Type)。这就是我们如何表示列表,不可为空的类型及其组合。

3.4 __Field

__Field 类型表示对象或接口类型中的每个字段。

type __Field {
  name: String!
  description: String
  args: [__InputValue!]!
  type: __Type!
  isDeprecated: Boolean!
  deprecationReason: String
}

name:必须返回一个字符串
description:可能返回一个 String 或 null
args:返回 __InputValue 表示该字段接受的参数的列表。
type:必须返回一个 __Type 代表该字段返回值的类型。
isDeprecated:如果不再使用此字段,则返回 true,否则返回 false。
deprecationReason:可选地提供了为什么这个字段被弃用的原因。

3.5 __InputValue

__InputValue 类型表示字段和指令参数以及inputFields输入对象。

type __InputValue {
  name: String!
  description: String
  type: __Type!
  defaultValue: String
}

name:必须返回一个 String
description:可能返回一个 String 或 null
type:必须返回一个 __Type 表示此输入值所期望的类型。
defaultValue:可能会在运行时未提供值的情况下返回此输入值使用的默认值的字符串编码(使用GraphQL语言)。如果此输入值没有默认值,则返回 null。

3.6 __Directive

__Directive 类型表示服务器支持的指令。

type __Directive {
  name: String!
  description: String
  locations: [__DirectiveLocation!]!
  args: [__InputValue!]!
}

name:必须返回一个 String
description:返回一个 String 或 null
locations:返回一个 __DirectiveLocation,表示这个指令可能被放置的有效位置的列表。
args:返回 __InputValue 表示此指令接受的参数的列表。

3.7 __TypeKind

GraphQL 支持多种类型,每种类型所支持的字段是不一样的。__TypeKind枚举中列出了这些类型。

enum __TypeKind {
  SCALAR
  OBJECT
  INTERFACE
  UNION
  ENUM
  INPUT_OBJECT
  LIST
  NON_NULL
}

1. 标量 Scalar

标量类型包括:Int,String,Boolean,Float,ID。标量不能有字段。

GraphQL 类型的设计者应该在任何标量的描述字段中描述数据格式和标量强制规则。

kind:必须返回 __TypeKind.SCALAR
name:必须返回一个字符串。
description:可能返回一个 String 或 null。
所有其他字段必须返回 null。

2. Object

对象类型代表了由一组字段组成的类型。内省类型(例如 __Type__Field 等)都是对象。

kind:必须返回 __TypeKind.OBJECT
name:必须返回一个字符串。
description:可能返回一个 String 或 null。
fields:在这个类型上可以查询的字段集合。
接受 includeDeprecated 默认为 false 的参数。如果为 true,则也会返回已弃用的字段。
interfaces:对象实现的一组接口。
所有其他字段必须返回 null。

3. Union

联合类型是一种抽象类型,没有声明公共的字段。在possibleTypes 明确列出联合类型的可能类型。类型可以直接作为联合的一部分。

kind:必须返回__TypeKind.UNION。
name:必须返回一个字符串。
description:可能返回一个 String 或 null。
possibleTypes:返回此联合中可以表示的类型的列表。它们必须是对象类型。
所有其他字段必须返回 null。

4. Interface

接口是一个抽象类型,其中声明了通用字段。任何实现接口的类型都必须实现接口中定义的字段且类型一致。接口的所有实现需要在 possibleTypes 明确列出。

kind:必须返回__TypeKind.INTERFACE。
name:必须返回一个字符串。
description:可能返回一个 String 或 null。
fields:这个接口所需的一组字段。
接受 includeDeprecated 默认为false的参数。如果为 true,则也会返回已弃用的字段。
possibleTypes:返回实现此接口的类型的列表。它们必须是对象类型。
所有其他字段必须返回 null。

5. Enum

枚举是特殊的标量,只能有一组定义的值。

kind必须返回__TypeKind.ENUM。
name 必须返回一个字符串。
description可能返回一个String或null。
enumValues:的清单EnumValue。必须至少有一个,他们必须有独特的名字。
接受includeDeprecated默认为false的参数。如果为true,则也会返回不推荐使用的枚举值。
所有其他字段必须返回null。

6. Input Object

输入对象是用作查询输入的复合类型,定义为指定输入值的列表。

例如,输入对象Point可以被定义为:

type Point {
  x: Int
  y: Int
}

kind:必须返回__TypeKind.INPUT_OBJECT。
name:必须返回一个字符串。
description:可能返回一个String或null。
inputFields:清单InputValue。
所有其他字段必须返回null。

7. List

列表表示 GraphQL 中值的序列。List类型是一个类型修饰符:它在 ofType 字段中包含另一个类型实例,该实例定义了列表中每个项目的类型。

kind必须返回__TypeKind.LIST。
ofType: 任何类型。
所有其他字段必须返回null。

8. Non-Null

非 null 类型是一个类型修饰符:它在该ofType字段中包装另一个类型实例。非null类型不允许null作为响应,并指示参数和输入对象字段所需的输入。

kind:必须返回__TypeKind.NON_NULL。
ofType:除非空之外的任何类型。
所有其他字段必须返回null。

4. 客户端使用内省系统

4.1 入口字段

内省系统的元字段有两个:

  • __schema: __Schema!
  • __type(name: String!): __Type

4.2 查询服务端的入口(查询,变更,订阅)

// 查询
query{
  __schema {
    queryType {
      name
    }
    mutationType {
      name
    }
    subscriptionType {
      name
    }
  }
}

// 响应
{
  "data": {
    "__schema": {
      "queryType": {
        "name": "Query"
      },
      "mutationType": {
        "name": "Mutation"
      },
      "subscriptionType": null
    }
  }
}

4.3 查询所有可用的对象

// 请求
query{
  __schema {
    types {
      name
      description
      kind
    }
  }
}
// 响应
{
  "data": {
    "__schema": {
      "types": [
        {
          "name": "Boolean",
          "description": "Represents `true` or `false` values.",
          "kind": "SCALAR"
        },
        {
          "name": "String",
          "description": "Represents textual data as UTF-8 character sequences. This type is most often used by GraphQL to represent free-form human-readable text.",
          "kind": "SCALAR"
        },
        {
          "name": "Query",
          "description": "The query root of GitHub's GraphQL interface.",
          "kind": "OBJECT"
        },
        {
          "name": "Node",
          "description": "An object with an ID.",
          "kind": "INTERFACE"
        },
        // 后面的省略了
      ]
    }
  }
}

4.4 查询某个对象的所有字段

每个字段的名字,类型,描述,是否废弃。

// 请求
query{
  __type(name:"Topic") {
    name
    fields {
      name
      type {
        name
        kind
      }
      description
      isDeprecated
    }
  }
}
// 响应
{
  "data": {
    "__type": {
      "name": "Topic",
      "fields": [
        {
          "name": "id",
          "type": {
            "name": null,
            "kind": "NON_NULL"
          },
          "description": null,
          "isDeprecated": false
        },
        {
          "name": "name",
          "type": {
            "name": null,
            "kind": "NON_NULL"
          },
          "description": "The topic's name.",
          "isDeprecated": false
        },
        {
          "name": "relatedTopics",
          "type": {
            "name": null,
            "kind": "NON_NULL"
          },
          "description": "A list of related topics, including aliases of this topic, sorted with the most relevant\nfirst.\n",
          "isDeprecated": false
        }
      ]
    }
  }
}

对于 LIST 等包装类型,需要用 ofType 查看具体支持的类型

// 请求
{
  __type(name: "User") {
    name
    fields {
      name
      type {
        name
        kind
        ofType {
          name
          kind
        }
      }
    }
  }
}
// 响应
{
  "data": {
    "__type": {
      "name": "User",
      "fields": [
        {
          "name": "avatarUrl",
          "type": {
            "name": null,
            "kind": "NON_NULL",
            "ofType": {
              "name": "URI",
              "kind": "SCALAR"
            }
          }
        },
        {
          "name": "bio",
          "type": {
            "name": "String",
            "kind": "SCALAR",
            "ofType": null
          }
        },
        {"name": "bioHTML",
          "type": {
            "name": null,
            "kind": "NON_NULL",
            "ofType": {
              "name": "HTML",
              "kind": "SCALAR"
            }
          }
        },
        {
          "name": "commitComments",
          "type": {
            "name": null,
            "kind": "NON_NULL",
            "ofType": {
              "name": "CommitCommentConnection",
              "kind": "OBJECT"
            }
          }
        },
        // 下面省略
      ]
    }
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值