12 分钟
GraphQL验证迁移指南
很快,“graph-节点”将支持GraphQL验证规范的100%覆盖率。
“graph-节点”的早期版本不支持所有验证,并提供了更优雅的响应——因此,在出现歧义的情况下,“graph-节点”会忽略无效的GraphQL操作组件。
GraphQL验证支持是即将推出的新功能和The Graph网络规模性能的支柱。
它还将确保查询响应的确定性,这是The Graph网络的一个关键要求。
启用GraphQL验证将中断发送到Graph API的一些现有查询。
为了符合这些验证,请遵循迁移指南。
⚠️ 如果您不在验证推出之前迁移查询,它们将返回错误,并可能破坏您的前端/客户端。
迁移指南
您可以使用CLI迁移工具查找GraphQL操作中的任何问题并进行修复。或者,您可以更新GraphQL客户端的端点,以使用https://api-next.thegraph.com/subgraphs/name/$GITHUB_USER/$SUBGRAPH_NAME
端点。针对此端点测试查询将帮助您发现查询中的问题。
如果您使用GraphQL ESlint,并不是所有的子图都需要迁移或GraphQL代码生成器,它们已经确保了您的查询是有效的。
迁移CLI工具
大多数GraphQL操作错误都可以提前在代码库中找到
因此,我们在开发过程中或在CI中为验证GraphQL操作提供了流畅的体验。
@graphql验证/cli
是一个简单的CLI工具,有助于根据给定的模式验证GraphQL操作。
入门
您可以按如下方式运行该工具:
1npx@graphql验证/cli-shttps://api-npx @graphql-validate/cli -s https://api-next.thegraph.com/subgraphs/name/$GITHUB_USER/$SUBGRAPH_NAME -o *.graphql
注意事项:
- -使用适当的值设置或替换$GITHUB_USER、$SUBGRAPH_NAME。类似:
artblocks/artblocks
- -预览架构URL(https://api-next.thegraph.com/)所提供的是速率严重受限,并且一旦所有用户都迁移到新版本,就将是逐步关闭期。**不要在生产中使用它**
- -操作在具有以下扩展名的文件中标识[
.graphql
,](https://www.graphql-tools.com/docs/schema-loading#graphql-文件加载器)[`.ts`,`.tsx`,`.js`,`jsx`](https://www.graphql-tools.com/docs/schema-loading#code-文件加载程序)(“-o”选项)。
CLI输出
[@graphql-validate/cli](https://github.com/saihaj/graphql-validate)
CLI工具将输出任何GraphQL操作错误,如下所示:

对于每个错误,您都会找到一个描述、文件路径和位置,以及到解决方案示例的链接(请参阅以下部分)。
根据预览模式运行本地查询
我们提供了一个端点https://api-next.thegraph.com/
它运行一个启用了验证的“graph-节点”版本。
您可以尝试将查询发送到:
https://api-next.thegraph.com/subgraphs/id<Qm...>
或者
https://api-next.thegraph.com/subgraphs/name/<GITHUB_USER>/<SUBGRAPH_NAME>
要处理标记为存在验证错误的查询,可以使用您最喜欢的GraphQL查询工具,如Altair或GraphiQL,然后尝试您的查询。这些工具还会在用户界面中标记这些错误,甚至在您运行之前。
如何解决问题
下面,您将发现现有GraphQL操作中可能发生的所有GraphQL验证错误。
GraphQL变量、操作、片段或参数必须是唯一的
我们应用了规则来确保操作包含一组唯一的GraphQL变量、操作、片段和参数。
GraphQL操作只有在不包含任何歧义的情况下才有效。
为了实现这一点,我们需要确保GraphQL操作中的某些组件必须是唯一的。
以下是一些违反这些规则的无效操作的示例:
重复查询名称(#UniqueOperationNamesRule)
1#以下操作违反了UniqueOperationName2#规则,因为我们有一个带有2个查询的单个操作3#具有相同的名称4query myData {5 id6}78query myData {9 name10}
解决方案:
1query myData {2 id3}45query myData2 {6 # 重新给第二个查询命名7 name8}
重复操作名称(#UniqueOperationNamesRule)
1#以下操作违反了UniqueOperationName2#规则。3query myData {4 id5 ...MyFields6}78fragment MyFields {9 metadata10}1112fragment MyFields {13 name14}
解决方案:
1query myData {2 id3 ...MyFieldsName4 ...MyFieldsMetadata5}67fragment MyFieldsMetadata { # assign a unique name to fragment8 metadata9}1011fragment MyFieldsName { # assign a unique name to fragment12 name13}
重复变量名称(#UniqueOperationNamesRule)
1#以下操作违反了UniqueVariables2query myData($id: String, $id: Int) {3 id4 ...MyFields5}
解决方案:
1query myData($id: String) {2 # 保持相关变量(这里是: `$id: String`)3 id4 ...MyFields5}
重复参数名称(#UniqueOperationNamesRule)
1#以下操作违反了UniqueArguments2query myData($id: ID!) {3 userById(id: $id, id: "1") {4 id5 }6}
解决方案:
1query myData($id: ID!) {2 userById(id: $id) {3 id4 }5}
重复的匿名查询(#LoneAnonymousOperationRule)
此外,由于响应结构中的冲突,使用两个匿名操作将违反“LoneAnonymousOperation”规则:
1#如果在中一起执行,则此操作将失败2#具有以下两个查询的单个操作:3query {4 someField5}67query {8 otherField9}
解决方案:
1query {2 someField3 otherField4}
或者命名两个查询:
1query FirstQuery {2 someField3}45query SecondQuery {6 otherField7}
重叠域
GraphQL选择集只有在正确解析最终结果集时才被视为有效。
如果特定的选择集或字段由于所选字段或使用的参数而产生歧义,GraphQL服务将无法验证该操作。
以下是一些违反这些规则的无效操作的示例:
字段别名冲突(#OverlappingFieldsCanBeMergedRule)
1#别名字段可能会导致冲突,或者2#存在的其他别名或其他字段3#在GraphQL模式上。4query {5 dogs {6 name: nickname7 name8 }9}
解决方案:
1query {2 dogs {3 name: nickname4 originalName: name # 是原名 `name` 的别名5 }6}
参数字段冲突(#OverlappingFieldsCanBeMergedRule)
1#不同的参数可能导致不同的数据,2#所以我们不能假设字段是相同的。3query {4 dogs {5 doesKnowCommand(dogCommand: SIT)6 doesKnowCommand(dogCommand: HEEL)7 }8}
解决方案:
1query {2 dogs {3 knowsHowToSit: doesKnowCommand(dogCommand: SIT)4 knowsHowToHeel: doesKnowCommand(dogCommand: HEEL)5 }6}
此外,在更复杂的用例中,您可能会使用两个片段来违反此规则,这两个片段可能会在最终预期的集合中引起冲突:
1query {2 # 最终,我们有两个"x"的定义,指向3 # 不同的域!4 ...A5 ...B6}78fragment A on Type {9 x: a10}1112fragment B on Type {13 x: b14}
除此之外,客户端GraphQL指令(如“@skip”和“@include”)可能会导致歧义,例如:
1fragment mergeSameFieldsWithSameDirectives on Dog {2 name @include(if: true)3 name @include(if: false)4}
[您可以在此处阅读有关算法的更多信息。](https://spec.graphql.org/June2018/#sec-字段选择合并)
未使用的变量或片段
只有当使用了所有操作定义的组件(变量、片段)时,GraphQL操作才被认为是有效的。
以下是一些违反这些规则的无效操作的示例:
未使用的变量(#NoUnusedVariablesRule)
1#无效,因为从未使用过$someVar。2查询某物($someVar: String){3某些数据4}56```
解决方案:
1query something {2 someData3}
未使用的片段(#NoUnusedFragmentsRule)
1#无效,因为片段AllFields从未使用过。2询问某事{3 someData4}5fragment AllFields { # unused :(6 name7 age8}
解决方案:
1#无效,因为片段AllFields从未使用过。2询问某事{3 someData4}56#删除`AllFields'片段
无效或缺少选择集(#ScalarLeafsRule)
此外,GraphQL字段选择只有在以下内容得到验证时才有效:
- 指定了对象字段的必备选择集。
- 边缘字段(标量、枚举)不能指定选择集。
以下是下列模式违反这些规则的几个示例:
1type Image {2 url: String!3}45type User {6 id: ID!7 avatar: Image!8}910type Query {11 user: User!12}
无效的选择集
1query {2 user {3 id { # 无效, 因为"id"是ID类型且没有子域45 }6 }7}
解决方案:
1query {2 user {3 id4 }5}
缺少选择集
1query {2 user {3 id4 image # `image`需要一个子域的选择集5 }6}
解决方案:
1query {2 user {3 id4 image {5 src6 }7 }8}
参数值不正确(#VariablesInAllowedPositionRule)
根据模式中定义的值,将硬编码值传递给参数的GraphQL操作必须有效。
以下是一些违反这些规则的无效操作的示例:
1query purposes {2 # 如果“name”在模式中被定义为“String”,3 #此查询将在验证过程中失败。4 purpose(name: 1) {5 id6 }7}89#当定义了不正确的变量时,也可能发生这种情况:1011query purposes($name: Int!) {12 #如果“name”在模式中被定义为“String”,13 #此查询将在验证期间失败,因为14 #使用的变量类型为`Int`15 purpose(name: $name) {16 id17 }18}
未知类型、变量、片段或指令(#UnknownX)
如果使用任何未知类型、变量、片段或指令,GraphQLAPI将引发错误。
必须修复这些未知引用:
- 如果是打字错误,请重命名
- 否则,请删除
片段:无效的排列或定义
无效的片段排列(#PossibleFragmentSpreadsRule)
片段不能在不适用的类型上展开。
例如,我们不能将“Cat”片段应用于“Dog”类型:
1query {2 dog {3 ...CatSimple4 }5}67fragment CatSimple on Cat {8 # ...9}
片段定义无效(#FragmentsOnCompositeTypesRule)
所有Fragment都必须在复合类型上定义(使用“on…”),简而言之:对象、接口或并集。
以下示例无效,因为在标量上定义fragment是无效的。
1fragment fragOnScalar on Int {2 # 不能在标量`int`上定义`fragment`3 something4}56fragment inlineFragOnScalar on Dog {7 ... on Boolean {8 # `Boolean` 不是`Dog`的子类型9 somethingElse10 }11}
指令使用
指令不能在此位置使用(#KnownDirectivesRule)
只能使用Graph API支持的GraphQL指令(@…
)。
以下是GraphQL支持的指令示例:
1query {2 dog {3 name @include(true)4 age @skip(true)5 }6}
注意:不支持“@stream”、“@live”和“@defer”
指令在此位置只能使用一次(#UniqueDirectivesPerLocationRule)
The Graph支持的指令在每个位置只能使用一次。
以下内容无效(并且是多余的):
1query {2 dog {3 name @include(true) @include(true)4 }5}