首页 文章

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

提问于
浏览
1

假设我有一个查询定义喜欢这个:

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 回答

  • 3

    不幸的是, type 不能用来代替 input ,并且 input 不能用来代替 type . 这是设计的 . 来自official specification

    字段可以定义客户端使用查询传递的参数,以配置其行为 . 这些输入可以是字符串或枚举,但它们有时需要比这更复杂 . 上面定义的Object类型不适合在这里重用,因为Objects可以包含表示循环引用或对接口和联合的引用的字段,这两个字段都不适合用作输入参数 . 因此,输入对象在系统中具有单独的类型 .

    更重要的是, GraphQLObjectType 上的字段可以具有args和resolve函数,而 GraphQLInputObjectType 上的字段不具有(但它们具有默认值,前者无法使用) .

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

    它只是希望 some 字段用作输入(如果你发送了id;这应该是在添加用户时由db生成的) . 同样,您可能不希望将用作输入的每个字段公开给客户端,只显示他们实际需要的字段 .

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

    That said, there is something of a workaround. 至少在graphql-js中 . 如果以编程方式声明架构,则可以使用字段集分别定义Object,然后为 UserUserInput 对象设置 fields 属性 . 或者,如果您以声明方式定义模式(如示例中所示),则可以使用如下模板文字:

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

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

相关问题