为什么 GraphQL 变量突变语法如此冗余?

mac*_*ost 6 graphql

GraphQL 查询/突变非常干净:它们只需要它们实际需要的东西,不需要其他东西。或者至少是基本的。

但是,如果您将变量与任一变量一起使用,那么您的语法将不可避免地存在冗余:

query HeroNameAndFriends($episode: Episode) {
  hero(episode: $episode) {
    name
    friends {
      name
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

请注意$episode: Episodeepisode: $episode。问题是每个 GraphQL 突变都需要同样的冗余:如果您使用变量,则每个参数都必须定义两次(如果您进行编程查询,则无疑正在使用变量)。

我的问题是,为什么?似乎没有必要让每个使用 GraphQL 的人都重复一遍他们的论点。

为什么不直接编写语法:

query HeroNameAndFriends() {
  hero($episode: Episode) {
    name
    friends {
      name
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

或者如果您确实需要允许不同的变量名称,请允许可选的第三部分:

query HeroNameAndFriends() {
  hero(episode: Episode : $episode) {
    name
    friends {
      name
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

需要明确的是,我知道使用变量的查询与非变量查询不同,但我要问的是,为什么要为这些查询选择一种迫使每个人重复自己的语法?

看起来就是这样……不干!我肯定错过了为什么需要重复的一个重要原因

Her*_*rku 3

为什么我必须在 JavaScript 函数中列出我的参数?函数不是很明显吗

const getFullName = () => firstname + ' ' + lastname;
Run Code Online (Sandbox Code Playgroud)

接受两个参数,一个firstname名为lastname? 嗯,我认为这里很容易看穿,但还有更复杂的情况,它不是那么明显。现在上面的例子看起来很奇怪,但有一些函数式编程语言,其中的表达式如(_ + 2)_.concat(_)的表达式是有效的函数表达式。你可以创建一些非常令人讨厌的代码(看看你,点免费的 Haskell)。但很多语言似乎认为显式声明一段代码的输入是一个好主意。

回到 GraphQL:让我们看看变量的一些更复杂的用法,因为变量实际上是一个完整的变量实现。你可以用它们做更多的事情,然后将它们应用到一个论证中:

query NestedInput($name: String) {
  user(where: { name: { contains: $name } }) { ... }
}

query WithDirective($long: Boolean) {
  users {
    name
    bio @include(if: $long)
    friends(showAll: $long) {
      name
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

所以变量可以在很多地方使用,也可以多次使用。GraphQL 查询变得非常大的情况并不罕见。这可以与您提出的第二种语法一起使用吗?是的,但我认为可读性会受到影响。DRY 并不是要减少您必须键入的字符数量,而是要减少错误。但经常明确地表达事物也可以减少错误(例如,现在很多类型系统都明确地表达了输入参数及其类型)。

所以我想这只是 GraphQL 开发人员做出的权衡决定,他们选择了显式版本。不要忘记上下文:GraphQL 是由 Facebook 创建的,Facebook 是世界上最大的网络应用程序之一。

由于明确性的好处并不明显,这里列出了一些编辑:

  • 该声明允许开发人员快速了解查询中的所有变量及其相应类型。
  • GraphQL 开发人员工具不必从模式中昂贵地推断变量的类型,而可以简单地查找输入类型。
  • 错误消息变得更容易理解,想象一下参数showAll不采用布尔值而是整数。有了宣言我们就可以说mismatching types for variable $long. $long is Boolean but expected Int。如果没有宣布,我们就不得不说$long is sometimes used as Boolean, sometimes as Int。如果我们将它用作三种不同的类型怎么办?
  • 仅通过 GraphQL 静态代码分析就可以检测到中断查询:再次想象我们将 的类型更改showAllInt。在这种情况下,查询可能会被检测为错误,而如果没有显式类型声明,查询可能会在运行时中断。

  • 我们可能会问“为什么我们必须定义变量的类型,为什么我不能只在操作中引用变量,并且它们的类型由它们传递给的参数隐含”。我认为 Herku 谈到了我们这样做的许多原因——要强调的是,定义变量类型允许我们*在任何执行发生之前*对这些类型进行验证。这意味着错误的客户端输入只会破坏整个查询,而不是导致可能的部分响应。 (2认同)