GraphQL 验证


通过使用类型系统,你可以预判一个查询是否有效。这让服务器和客户端可以在无效查询创建时就有效地通知开发者,而不用依赖运行时检查。

对于我们的《星球大战》的案例,starWarsValidation-test.js 这个文件包含了若干对于各种无效查询的演示,它也是一个测试文件,用于检测参考实现的验证器。

# { "graphiql": true }
{
  hero {
    ...NameAndAppearances
    friends {
      ...NameAndAppearances
      friends {
        ...NameAndAppearances
      }
    }
  }
}

fragment NameAndAppearances on Character {
  name
  appearsIn
}

上面这个查询是有效的。我们来看看一些无效查询……

片段不能引用其自身或者创造回环,因为这会导致结果无边界。下面是一个相同的查询,但是没有显式的三层嵌套:

# { "graphiql": true }
{
  hero {
    ...NameAndAppearancesAndFriends
  }
}

fragment NameAndAppearancesAndFriends on Character {
  name
  appearsIn
  friends {
    ...NameAndAppearancesAndFriends
  }
}

查询字段的时候,我们只能查询给定类型上的字段。因此由于 hero 返回 Character 类型,我们只能查询 Character 上的字段。因为这个类型上没有 favoriteSpaceship 字段,所以这个查询是无效的:

# { "graphiql": true }
# 无效:favoriteSpaceship 不存在于 Character 之上
{
  hero {
    favoriteSpaceship
  }
}

当我们查询一个字段时,如果其返回值不是标量或者枚举型,那我们就需要指明想要从这个字段中获取的数据。hero 返回 Character 类型,我们也请求了其中像是 nameappearsIn 的字段;但如果将其省略,这个查询就变成无效的了:

# { "graphiql": true }
# 无效:hero 不是标量,需要指明下级字段
{
  hero
}

类似地,如果一个字段是标量,进一步查询它上面的字段也没有意义,这样做也会导致查询无效:

# { "graphiql": true }
# 无效:name 是标量,因此不允许下级字段查询
{
  hero {
    name {
      firstCharacterOfName
    }
  }
}

我们之前提到过,只有目标类型上的字段才可查询;当我们查询 hero 时,它会返回 Character,因此只有 Character 上的字段是可查询的。但如果我们要查的是 R2-D2 的 primary function 呢?

# { "graphiql": true }
# 无效:primaryFunction 不存在于 Character 之上
{
  hero {
    name
    primaryFunction
  }
}

这个查询是无效的,因为 primaryFunction 并不是 Character 的字段。我们需要某种方法来表示:如果对应的 CharacterDroid,我们希望获取 primaryFunction 字段,而在其他情况下,则忽略此字段。我们可以使用之前引入的“片段”来解决这个问题。先在 Droid 上定义一个片段,然后在查询中引入它,这样我们就能在定义了 primaryFunction 的地方查询它。

# { "graphiql": true }
{
  hero {
    name
    ...DroidFields
  }
}

fragment DroidFields on Droid {
  primaryFunction
}

这个查询是有效的,但是有点琐碎;具名片段在我们需要多次使用的时候更有价值,如果只使用一次,那么我们应该使用内联片段而不是具名片段;这同样能表示我们想要查询的类型,而不用单独命名一个片段:

# { "graphiql": true }
{
  hero {
    name
    ... on Droid {
      primaryFunction
    }
  }
}

这只是验证系统的冰山一角;事实上需要一大套验证规则才能保证 GraphQL 查询的语义意义。规范中的“验证”章节有关于本话题更详细的内容,GraphQL.js 的 validation 目录包含了规范兼容的 GraphQL 验证器实现代码。