GraphQL how to avoid duplicate code between input and output types

纵饮孤独 提交于 2019-11-30 19:31:09

There's a handful of things you could do. For example, if you were to declare your schema programatically, you can get away with something like this:

const getPizzaFields = (isInput = false) => {
  const fields = {
    type: { type: GraphQLString }
    pizzaType: { type: GraphQLString }
    toppings: { type: new GraphQLList(GraphQLString) }
    size: { type: GraphQLString }
    composition: {
      type: isInput ? new GraphQLList(IngredientInput) : new GraphQLList(Ingredient)
    }
  }
  if (!isInput) fields.id = { type: GraphQLString }
  return fields
}

const Pizza = new GraphQLObjectType({
  name: 'Pizza',
  fields: () => getFields()
})

const PizzaInput = new GraphQLObjectType({
  name: 'Pizza',
  fields: () => getFields(true)
})

Or if your objects/inputs follow a similar pattern, you could even write a function for generating inputs from types:

const transformObject = (type) => {
  const input = Object.assign({}, type)
  input.fields.composition.type = new GraphQLList(IngredientInput)
  delete input.fields.id
  return input
}

Alternatively, when defining your schema using makeExecutableSchema, you could do:

const commonPizzaFields = `
    type: String
    pizzaType: String
    toppings: [String]
    size: String
`

const schema = `
  type Pizza {
    id: String
    ${commonPizzaFields}
    composition: [Ingredient]
  }

  input PizzaInput {
    ${commonPizzaFields}
    composition: [IngredientInput]
  }
`

The problem with all of these approaches is that while they technically may make your code more DRY, they also reduce your schema's readability, which in my opinion makes it even more error-prone than the duplication itself.

It's also important to understand that while syntactically, a Type and an Input type may appear the same, functionally they are not. For example, a field on a type may have arguments:

type Pizza {
  toppings(filter: ToppingTypeEnum): [String]
}

Input Type fields do not have arguments, so you would not be able to utilize the same syntax for a toppings field in both a Pizza Type and its counterpart PizzaInput Input Type.

Personally, I would bite the bullet and just write out both the types and the inputs like you've already done. The only thing I would do differently is grouping them together (listing your type than your input), so that any differences between the two are easy to spot. But your mileage may very :)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!