验证
¥Validation
通过使用类型系统,可以预先确定 GraphQL 查询是否有效。这使得服务器和客户端能够在创建无效查询时有效地通知开发者,而无需依赖运行时检查。
¥By using the type system, it can be predetermined whether a GraphQL query is valid or not. This allows servers and clients to effectively inform developers when an invalid query has been created, without having to rely on runtime checks.
对于我们的星球大战示例,文件 starWarsValidation-test.ts 包含许多演示各种无效性的查询,并且是一个测试文件,可以运行该文件来练习参考实现的验证器。
¥For our Star Wars example, the file starWarsValidation-test.ts contains a number of queries demonstrating various invalidities, and is a test file that can be run to exercise the reference implementation’s validator.
首先,让我们进行一个复杂的有效查询。这是一个嵌套查询,类似于上一节中的示例,但将重复的字段分解为片段:
¥To start, let’s take a complex valid query. This is a nested query, similar to an example from the previous section, but with the duplicated fields factored out into a fragment:
并且这个查询是有效的。让我们看一下一些无效的查询…
¥And this query is valid. Let’s take a look at some invalid queries…
片段不能引用自身或创建循环,因为这可能会导致无限的结果!这是与上面相同的查询,但没有显式的三层嵌套:
¥A fragment cannot refer to itself or create a cycle, as this could result in an unbounded result! Here’s the same query above but without the explicit three levels of nesting:
当我们查询字段时,我们必须查询给定类型上存在的字段。因此,当 hero
返回 Character
时,我们必须查询 Character
上的字段。该类型没有 favoriteSpaceship
字段,因此此查询无效:
¥When we query for fields, we have to query for a field that exists on the
given type. So as hero
returns a Character
, we have to query for a field
on Character
. That type does not have a favoriteSpaceship
field, so this
query is invalid:
每当我们查询一个字段并且它返回除标量或枚举之外的其他内容时,我们需要指定要从该字段返回的数据。Hero 返回 Character
,我们一直在请求 name
和 appearsIn
等字段;如果我们省略它,查询将无效:
¥Whenever we query for a field and it returns something other than a scalar
or an enum, we need to specify what data we want to get back from the field.
Hero returns a Character
, and we’ve been requesting fields like name
and
appearsIn
on it; if we omit that, the query will not be valid:
类似地,如果一个字段是标量,则查询其上的其他字段是没有意义的,这样做会使查询无效:
¥Similarly, if a field is a scalar, it doesn’t make sense to query for additional fields on it, and doing so will make the query invalid:
早些时候,我们注意到查询只能查询相关类型的字段;当我们查询 hero
并返回 Character
时,我们只能查询 Character
上存在的字段。但是,如果我们想要查询 R2-D2 的主要函数,会发生什么情况呢?
¥Earlier, it was noted that a query can only query for fields on the type
in question; when we query for hero
which returns a Character
, we
can only query for fields that exist on Character
. What happens if we
want to query for R2-D2s primary function, though?
该查询无效,因为 primaryFunction
不是 Character
上的字段。我们需要某种方式来表明,如果 Character
是 Droid
,我们希望获取 primaryFunction
,否则忽略该字段。我们可以使用之前介绍的片段来做到这一点。通过设置在 Droid
上定义的片段并包含它,我们确保只查询定义它的 primaryFunction
。
¥That query is invalid, because primaryFunction
is not a field on Character
.
We want some way of indicating that we wish to fetch primaryFunction
if the
Character
is a Droid
, and to ignore that field otherwise. We can use
the fragments we introduced earlier to do this. By setting up a fragment defined
on Droid
and including it, we ensure that we only query for primaryFunction
where it is defined.
这个查询是有效的,但是有点冗长;当我们多次使用命名片段时,上面的命名片段很有价值,但我们只使用了一次。我们可以使用内联片段,而不是使用命名片段;这仍然允许我们指示我们正在查询的类型,但无需命名单独的片段:
¥This query is valid, but it’s a bit verbose; named fragments were valuable above when we used them multiple times, but we’re only using this one once. Instead of using a named fragment, we can use an inline fragment; this still allows us to indicate the type we are querying on, but without naming a separate fragment:
这只是验证系统的表面;有许多验证规则可以确保 GraphQL 查询在语义上有意义。该规范在 “验证” 部分详细介绍了该主题,GraphQL.js 中的 validation 目录包含实现符合规范的 GraphQL 验证器的代码。
¥This has just scratched the surface of the validation system; there are a number of validation rules in place to ensure that a GraphQL query is semantically meaningful. The specification goes into more detail about this topic in the “Validation” section, and the validation directory in GraphQL.js contains code implementing a specification-compliant GraphQL validator.