如何将JSON的HTTP发布简化为GraphQL突变解析器 [英] How to simplify HTTP post of JSON to GraphQL mutation resolver

查看:122
本文介绍了如何将JSON的HTTP发布简化为GraphQL突变解析器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想直接将JSON的JSON值直接HTTP POST到我的GraphQL Mutation中已经声明的addBook解析器.

I would like to HTTP POST values directly as JSON to an addBook resolver already declared in my GraphQL Mutation.

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

However, the examples I've seen (and proven) use serialisation of parameters from JSON to SDL or re-declaration of variables in SDL to bind from a Query Variable.

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

Neither approach makes sense because the addBook mutation already has all parameters and validation declared. Using these approaches would lead to unnecessary query serialisation logic having to be created, debugged and maintained.

我在浏览器中构造了格式良好(经过模式编辑和验证的)JSON,该JSON与声明的GraphQLObjectType的数据一致.

I have well-formed (schema- edited and -validated) JSON being constructed in the browser which conforms to the data of a declared GraphQLObjectType.

任何人都可以解释在针对突变解析器发布时如何避免这种不必要的重新序列化或重复吗?

Can anyone explain how to avoid this unnecessary reserialisation or duplication when posting against a mutation resolver?

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

I've been experimenting with multiple ways of mapping a JSON data structure against the addBook mutation but can't find an example of simply sending the JSON so that property names are be bound against addBook parameter names without apparently pointless reserialisation or boilerplate.

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

The source code at https://github.com/cefn/graphql-gist/tree/master/mutation-map is a minimal reproducible example which demonstrates the problem. It has an addBook resolver which already has parameter names, types and nullability defined. I can't find a way to use JSON to simply POST parameters against addBook.

我将GraphiQL用作HTTP POST值的参考实现.

I'm using GraphiQL as a reference implementation to HTTP POST values.

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

I could write code to serialise JSON to SDL. It would end up looking like this which works through GraphiQL:

mutation {addBook(id:"4", name:"Education Course Guide", genre: "Education"){
    id
}}

或者,我可以编写代码以将addBook的每个参数显式地别名到另一个查询,然后允许我将值作为JSON查询变量发布,这也通过GraphiQL进行了验证:

Alternatively I can write code to explicitly alias each parameter of addBook to a different query which then allows me to post values as a JSON query variable, also proven through GraphiQL:

mutation doAdd($id: String, $name: String!, $genre: String){
  addBook(id:$id, name:$name, genre:$genre){
    id
  }
}

...带有查询变量...

...with the query variable...

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

但是,我确定有某种方法可以将这个JSON直接发布到addBook上,告诉它从查询变量中获取参数.我在想像...

However, I am sure there's some way to directly post this JSON against addBook, telling it to take parameters from a Query Variable. I'm imagining something like...

mutation {addBook($*){
    id
}}

我希望对addBook的突变调用能够成功,它从JSON查询变量中获取命名值,但无需重新序列化或将属性重新声明为参数名.

I would like a mutation call against addBook to succeed, taking named values from a JSON Query Variable, but without reserialisation or redeclaration of the properties to parameter names.

推荐答案

这可以归结为模式设计.而不是在您的字段上输入三个参数

This boils down to schema design. Instead of having three arguments on your field

type Mutation {
  addBook(id: ID, name: String!, genre: String!): Book
}

您可以有一个采用输入对象类型的参数

you can have a single argument that takes an input object type

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

input AddBookInput {
  id: ID
  name: String!
  genre: String!
}

然后,您的查询只需提供一个变量:

Then your query only has to provide a single variable:

mutation AddBook($input: AddBookInput!) {
  addBook(input: $input) {
    id
  }
}

和您的变量看起来像:

{
  "input": {
    "name": "Jonathan Livingstone Seagull",
    "genre": "Fable"
  }
}

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

Variables have to be explicitly defining as part of the operation definition because GraphQL and JSON are not interchangeable. A JSON string value could be a String, an ID or some custom scalar (like DateTime) in GraphQL. The variable definitions tell GraphQL how to correctly serialize and validate the provided JSON values. Because variables can be used multiple times throughout a document, their types likewise cannot simply be inferred from the types of the arguments they are used with.

每个文档中变量仅声明一次.声明后,可以在整个文档中多次引用它们.想象一下像

Variables are only declared once per document. Once declared, they may be referred to any number of times throughout the document. Imagine a query like

mutation MyMutation ($id: ID!) {
  flagSomething(somethingId: $id)
  addPropertyToSomething(id: $id, property: "WOW")
}

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

We declare the variable once and tell GraphQL it's an ID scalar and it's non-nullable (i.e. required). We then use the variable twice -- once as the value of somethingId on flagSomething and again as the value of id on addPropertyToSomething. The same variable could also be used as the value to a directive's argument too -- it's not limited to just field arguments. Notice also that nothing says the variable name has to match the field name -- this is typically only done out of convenience.

这里另一个值得注意的是,这里有两个验证步骤.

The other notable thing here is that there's two validation steps happening here.

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

First, GraphQL will check if the provided variable (i.e. the JSON value) can be serialized into the type specified. Since we declared the variable as non-null (using !), GraphQL will also verify the variable actually exists and is not equal to null.

GraphQL还将验证您为变量指定的类型是否与实际使用的参数类型匹配.因此,如果将Int变量传递给String参数,则将引发该变量,依此类推.此外,此处也检查了可空性.因此,作为Int!(非空整数)的参数将仅接受也是Int!的变量.但是,Int(即可为空)的参数将接受IntInt!变量.

GraphQL will also verify that the type you specified for the variable matches the types of the arguments where it's actually used. So an Int variable will throw if it's passed to a String argument and so on. Moreover, nullability is checked here too. So an argument that is an Int! (non-null integer) will only accept variables that are also Int!. However, an argument that is Int (i.e. nullable) will accept either Int or Int! variables.

存在该语法是有原因的.您想象的那种语法仅在特定情况下才有意义,在这种情况下,您仅使用所有变量作为该字段. em>变量名与参数名匹配,您无需动态设置任何指令参数.

The syntax that exists is there for a reason. The kind of syntax you're imagining would only make sense in a specific scenario where you're only querying a single root field and using all the variables as arguments to that one field and the variable names match the argument names and you don't need to dynamically set any directive arguments.

这篇关于如何将JSON的HTTP发布简化为GraphQL突变解析器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆