内省 (Introspection)
了解如何查询 GraphQL Schema 的信息
向 GraphQL Schema 查询其支持的功能信息通常非常有用。GraphQL 允许我们通过 内省系统 来实现这一点。
内省查询是一种特殊的查询,允许你了解 GraphQL API 的 Schema,它们还有助于驱动 GraphQL 开发工具。在此页面中,我们将学习如何运行不同的查询,以详细了解底层 Schema 的类型、字段和描述。
类型名称内省
我们已经在 Schema 和类型页面 中看过内省的示例。当查询返回联合(Union)类型的字段时,我们在选择集中直接包含了 __typename 元字段,以获取搜索查询返回的不同类型名称的字符串值。让我们再次查看这个例子:
我们并没有显式地将 __typename 字段添加到我们的 GraphQL API 中——GraphQL 规范规定,GraphQL 实现必须向客户端提供该字段。对于任何以对象(Object)、接口(Interface)或联合(Union)作为底层输出类型的字段,都可以查询此字段。
Schema 内省
内省的作用不仅仅是在查询中提供类型名称。如果你是为一个 GraphQL API 设计的类型系统,那么你可能已经知道有哪些可用类型。但如果你不是设计者,你可以通过查询 __schema 字段来询问 GraphQL,该字段在 query 根操作类型上始终可用。
现在我们就来试一下,询问 Star Wars Schema 中有哪些可用类型:
哇,类型真多!它们是什么?让我们把它们分组:
- 我们在类型系统中定义的类型:
Query,Mutation,Character,Human,Episode,Droid,LengthUnit,FriendsConnection,FriendsEdge,PageInfo,Review,ReviewInput,Starship, 和SearchResult - 类型系统提供的内置标量:
Boolean,Float,ID,Int, 和String - 以内省系统特有的双下划线开头的类型:
__Schema,__Type,__TypeKind,__Field,__InputValue,__EnumValue,__Directive, 和__DirectiveLocation
现在,让我们试着找一个开始探索可用查询的好地方。当我们设计类型系统时,我们指定了所有查询的起始类型;让我们就此询问内省系统:
结果与我们在 类型系统章节 中所说的一致——Query 类型是我们开始的地方。请注意,这里的命名只是约定俗成;我们可以将 Query 类型命名为任何其他名称,只要我们将其指定为查询的起始类型,它仍会在此处返回。不过,将其命名为 Query 是一个非常有用的约定。
检查某个特定类型通常很有用。让我们看看 Droid 类型:
但如果我们想了解更多关于 Droid 的信息呢?例如,它是接口还是对象类型?
kind 返回一个 __TypeKind 枚举类型,其值之一是 OBJECT。如果我们改为询问 Character,我们会发现它是一个接口类型:
对于对象类型,了解哪些字段可用很有用,所以让我们向内省系统询问 Droid:
这些正是我们在 Droid 上定义的字段!
id 在那里看起来有点奇怪,它没有类型名称。那是因为它是一个类型为 NON_NULL 的包装类型 (wrapper type)。如果我们查询该字段类型的 ofType,我们会在那里找到 ID 类型,告诉我们这是一个非空 ID。
类似地,friends 和 appearsIn 也没有名称,因为它们是 LIST 包装类型。我们可以查询这些类型的 ofType,它会告诉我们列表里是什么类型:
让我们以内省系统的一个对工具开发特别有用的功能结束:向系统请求文档:
如上所述,我们可以使用内省访问有关类型系统的文档,并创建文档浏览器或丰富的 IDE 体验。
这仅仅触及了内省系统的表面;我们还可以查询枚举类型的值、一个类型实现了哪些接口类型等等。我们甚至可以对内省系统本身进行内省。
要查看代码中实现的符合规范的 GraphQL 查询内省系统示例,你可以在参考实现中查看 src/type/introspection.ts。
生产环境中的内省
内省是 GraphQL 的一个有用功能,特别是对于客户端开发人员和工具而言。然而,对于仅供你自己的应用程序使用的 API,生产环境中通常不需要它——所需的操作通常在构建时就已经固化在这些应用程序中,这使得运行时内省变得不再必要。
在生产环境中禁用内省是很常见的做法,以减少 API 的受攻击面。这通常是更广泛的 API 安全策略的一部分,该策略还可能包括身份验证和授权、操作白名单(或一系列替代保护措施,如深度限制、广度限制、别名限制、循环拒绝、成本分析等)、执行超时等。
后续步骤
回顾一下我们学到的关于内省的内容:
- 可以在对象、接口或联合类型的字段选择集中使用
__typename元字段查询类型名称 - 可以使用
query根操作类型上的__schema字段查询有关 GraphQL Schema 元素的信息 - 生产环境中通常会禁用内省
既然你已经探索了 GraphQL 类型系统、如何从 API 查询数据以及请求的生命周期,请前往 最佳实践 章节,详细了解如何在生产环境中运行 GraphQL。
简介
了解 GraphQL 最佳实践课程背后的背景。