【问题标题】:Why is GraphQL Variable Mutation Syntax So Redundant?为什么 GraphQL 变量突变语法如此冗余?
【发布时间】:2020-02-07 07:10:33
【问题描述】:

GraphQL 查询/突变非常简洁:它们只需要它们实际需要的东西,没有别的。或者至少是基本的。

但是,如果您将变量与其中任何一个一起使用,那么您的语法不可避免地会出现冗余:

query HeroNameAndFriends($episode: Episode) {
  hero(episode: $episode) {
    name
    friends {
      name
    }
  }
}

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

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

为什么不直接写语法:

query HeroNameAndFriends() {
  hero($episode: Episode) {
    name
    friends {
      name
    }
  }
}

或者如果你真的需要允许不同的变量名,允许一个可选的第三部分:

query HeroNameAndFriends() {
  hero(episode: Episode : $episode) {
    name
    friends {
      name
    }
  }
}

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

看起来如此......不干燥!我肯定错过了为什么这种重复是必要的一个重要原因?

【问题讨论】:

    标签: graphql


    【解决方案1】:

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

    const getFullName = () => firstname + ' ' + lastname;
    

    接受两个参数,一个名为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
        }
      }
    }
    

    所以变量可以在很多地方使用,也可以多次使用。 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 静态代码分析来检测中断查询:再次假设我们将 showAll 的类型更改为 Int。在这种情况下,查询可能会被检测为错误,而如果没有显式类型声明,查询可能会在运行时中断。

    【讨论】:

    • 这个答案非常有帮助,我很欣赏以其他方式使用的变量示例。但我仍然不清楚的部分是:重复的价值是什么?当您列出参数时,您正在添加有意义的信息(它们的顺序),否则这些信息将不存在:没有它就无法使用 args。但是当你重复 $foo 时,你并没有添加任何新信息,你只是在重复已经呈现的信息,这似乎不是 DRY 可读 不太可能导致错误。我只是想了解重复所带来的(对我来说不直观)价值。
    • 是否只是 GraphQL 语法针对重用变量的查询进行了优化(例如您的 WithDirective 如何重用 $long),而牺牲了不使用变量的查询?跨度>
    • 那么您是在争论声明是重复的,对吧?我在答案中添加了显式语法的一些好处。
    • 这里没有冗余。您定义了一些与请求一起传递的值以及类型。然后将该值传递给字段或指令上的一个或多个参数。如果变量和参数碰巧同名,那是巧合。这实际上与在编程语言中定义一个变量然后通过将其传递给某个函数来使用该变量没有什么不同。 let x: number; function doWork(x: number): number { ... }; doWork(x); 我们不会说这是多余的,因为我们已经输入了 3 次 x
    • 我们可以问“为什么我们必须定义变量的类型,为什么我不能只在操作中引用变量并且它们的类型被传递给它们的参数所暗示”。我认为 Herku 谈到了我们这样做的许多原因——需要强调的是,定义变量类型允许我们在在任何执行发生之前验证这些类型。这意味着错误的客户端输入只会破坏整个查询,而不是导致潜在的部分响应。
    猜你喜欢
    • 2020-04-23
    • 1970-01-01
    • 2019-07-11
    • 1970-01-01
    • 2011-05-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-06
    相关资源
    最近更新 更多