GraphQL:如何重用相同的类型进行查询和变异?

Posted

技术标签:

【中文标题】GraphQL:如何重用相同的类型进行查询和变异?【英文标题】:GraphQL: How to reuse same type for query and mutation? 【发布时间】:2018-02-19 20:21:17 【问题描述】:

假设我有一个这样定义的查询:

type Query 
  # The basic me query
  getUser(id:Int): [User]


type User 
  id: ID!
  login: String!
  name: String    

但是现在我需要一个突变来添加一个用户。我的直觉是这样的:

type Mutation   
  addUser(newUser: User): [User]

但它不起作用,因为突变不能使用“查询类型”。它需要使用“输入类型”。我知道在这个例子中,做起来并不复杂,但是如果用户是一个非常复杂的类型,使用了许多子类型。我怎样才能做到这一点? 是否可以重用类型作为突变参数?

【问题讨论】:

【参考方案1】:

很遗憾,type 不能用来代替 inputinput 不能用来代替 type。这是设计使然。来自official specification:

字段可以定义客户端通过查询传递的参数, 配置他们的行为。这些输入可以是字符串或枚举,但 它们有时需要比这更复杂。

上面定义的 Object 类型不适合在这里重用, 因为对象可以包含表达循环引用的字段或 对接口和联合的引用,两者都不合适 用作输入参数。因此,输入对象具有 系统中的单独类型。

此外,GraphQLObjectType 上的字段可以有 args 和解析函数,而GraphQLInputObjectType 上的字段则没有(但它们确实有默认值,前者不可用)。

从实现的角度来看,将它们分开也是有意义的。简单模式可能只是将字段映射到某个表中的列。但是,在实际应用程序中,您更有可能拥有不映射到任何一列的派生字段(并且不适合在输入中使用)。

您也可能只希望将 一些 字段用作输入(例如,如果您要添加用户,则客户端不应向您发送 id;这可能应该添加用户时由数据库生成)。同样,您可能不想向客户端公开用作输入的每个字段,只公开他们实际需要的字段。

如果不出意外,您对non-null 的使用在输入类型和返回类型之间可能会有所不同。

也就是说,有一些解决方法。至少在 graphql-js 中。如果您以编程方式声明架构,您可以使用您的字段集单独定义一个对象,然后为您的 UserUserInput 对象设置您的 fields 属性。或者,如果您以声明方式定义架构(如在您的示例中),您可以使用这样的模板文字:

const userFields = `
  id: ID!
  login: String!
  name: String
`
const schema = `
  type User 
    $userFields
  
  type UserInput 
    $userFields
  
`

哎呀,如果您愿意,您甚至可以遍历每个定义的类型并以编程方式创建匹配的输入类型。但是,IMO,当您考虑灵活性成本时,实施任何这些变通办法的努力可能不值得。咬紧牙关,考虑一下您实际需要什么作为该突变的输入,并仅指定您需要的字段。

【讨论】:

以上是关于GraphQL:如何重用相同的类型进行查询和变异?的主要内容,如果未能解决你的问题,请参考以下文章

如何重用graphql查询中的字段

GraphQL SPQR 扩展输入对象的变异参数

为啥注册和我总是在变异和查询类型中?

在 GraphQL 中重用输入类型作为片段 [重复]

type-Graphql 中的嵌套查询和变异

GraphQL:在一次网络调用中查询和变异