如何将 JSON 的 HTTP post 简化为 GraphQL 突变解析器

cef*_*efn 0 post json http mutation graphql

我想将 HTTP POST 值直接作为 JSON 发送到已在我的 GraphQL Mutation 中声明的 addBook 解析器。

但是,我见过(并证明)的示例使用从 JSON 到 SDL 的参数序列化或在 SDL 中重新声明变量以从查询变量进行绑定。

这两种方法都没有意义,因为 addBook 突变已经声明了所有参数和验证。使用这些方法将导致必须创建、调试和维护不必要的查询序列化逻辑。

我在浏览器中构造了格式良好(模式编辑和验证)的 JSON,它符合声明的 GraphQLObjectType 的数据。

谁能解释在针对突变解析器发布时如何避免这种不必要的重新序列化或重复?

我一直在尝试使用多种方法将 JSON 数据结构映射到 addBook 突变,但找不到简单发送 JSON 的示例,以便将属性名称绑定到 addBook 参数名称,而没有明显毫无意义的重新序列化或样板。

https://github.com/cefn/graphql-gist/tree/master/mutation-map 上的源代码是一个最小的可重现示例,它演示了该问题。它有一个 addBook 解析器,它已经定义了参数名称、类型和可空性。我找不到使用 JSON 来简单地针对 addBook POST 参数的方法。

我使用 GraphiQL 作为 HTTP POST 值的参考实现。

我可以编写代码将 JSON 序列化为 SDL。它最终看起来像这样,它通过 GraphiQL 工作:

mutation {addBook(id:"4", name:"Education Course Guide", genre: "Education"){
    id
}}
Run Code Online (Sandbox Code Playgroud)

或者,我可以编写代码将 addBook 的每个参数显式别名为不同的查询,然后允许我将值作为 JSON 查询变量发布,也通过 GraphiQL 证明:

mutation doAdd($id: String, $name: String!, $genre: String){
  addBook(id:$id, name:$name, genre:$genre){
    id
  }
}
Run Code Online (Sandbox Code Playgroud)

...使用查询变量...

{
  name: "Jonathan Livingstone Seagull",
  id: "6"
}

Run Code Online (Sandbox Code Playgroud)

但是,我确信有某种方法可以直接针对 addBook 发布此 JSON,告诉它从查询变量中获取参数。我在想象这样的事情......

mutation {addBook($*){
    id
}}

Run Code Online (Sandbox Code Playgroud)

我希望对 addBook 的突变调用成功,从 JSON 查询变量中获取命名值,但没有将属性重新序列化或重新声明为参数名称。

Dan*_*den 5

这归结为模式设计。而不是在你的领域有三个论点

type Mutation {
  addBook(id: ID, name: String!, genre: String!): Book
}
Run Code Online (Sandbox Code Playgroud)

你可以有一个接受输入对象类型的参数

type Mutation {
  addBook(input: AddBookInput!): Book
}

input AddBookInput {
  id: ID
  name: String!
  genre: String!
}
Run Code Online (Sandbox Code Playgroud)

那么您的查询只需要提供一个变量:

mutation AddBook($input: AddBookInput!) {
  addBook(input: $input) {
    id
  }
}
Run Code Online (Sandbox Code Playgroud)

你的变量看起来像:

{
  "input": {
    "name": "Jonathan Livingstone Seagull",
    "genre": "Fable"
  }
}
Run Code Online (Sandbox Code Playgroud)

变量必须明确定义为操作定义的一部分,因为 GraphQL 和 JSON 不可互换。JSON 字符串值可以是字符串、ID 或 GraphQL 中的一些自定义标量(如 DateTime)。变量定义告诉 GraphQL 如何正确序列化和验证提供的 JSON 值。因为变量可以在整个文档中多次使用,它们的类型同样不能简单地从它们使用的参数类型推断出来。

编辑:

每个文档只声明一次变量。一旦声明,它们可以在整个文档中被多次引用。想象一个像这样的查询

mutation MyMutation ($id: ID!) {
  flagSomething(somethingId: $id)
  addPropertyToSomething(id: $id, property: "WOW")
}
Run Code Online (Sandbox Code Playgroud)

我们声明变量一次并告诉 GraphQL 它是一个 ID 标量并且它是不可为空的(即必需的)。然后,我们使用可变两次-一次是价值somethingIdflagSomething,再次为价值idaddPropertyToSomething。相同的变量也可以用作指令参数的值——它不仅限于字段参数。还要注意,没有说变量名必须与字段名匹配——这通常只是为了方便。

另一个值得注意的事情是这里发生了两个验证步骤。

首先,GraphQL 将检查提供的变量(即 JSON 值)是否可以序列化为指定的类型。由于我们将变量声明为非空(使用!),GraphQL 还将验证变量是否实际存在且不等于空。

GraphQL 还将验证您为变量指定的类型是否与实际使用的参数类型相匹配。因此,如果将 Int 变量传递给 String 参数等,它会抛出异常。此外,这里也检查可空性。因此,作为Int!(非空整数)的参数将只接受也是Int!. 但是,Int(即可为空的)参数将接受IntInt!变量。

存在的语法是有原因的。您想象的那种语法仅在特定情况下才有意义,即您仅查询单个根字段使用所有变量作为该字段的参数,并且变量名称与参数名称匹配您不需要动态设置任何指令参数。