GraphQL如何避免输入和输出类型之间的重复代码

时间:2018-01-16 09:13:02

标签: interface graphql apollo

我是GraphQL的新手,但我非常喜欢它。现在我正在玩界面和工会,我正面临着突变问题。

假设我有这个架构:

interface FoodType {
    id: String
    type: String
    composition: [Ingredient]
  }

  type Pizza implements FoodType {
    id: String
    type: String
    pizzaType: String
    toppings: [String]
    size: String
    composition: [Ingredient]
  }

  type Salad implements FoodType {
    id: String
    type: String
    vegetarian: Boolean
    dressing: Boolean
    composition: [Ingredient]
  }

  type BasicFood implements FoodType {
    id: String
    type: String
    composition: [Ingredient]
  }

  type Ingredient {
      name: String
      qty: Float
      units: String
  }

现在,我想创造新的食品,所以我开始做这样的事情:

type Mutation {
    addPizza(input:Pizza):FoodType
    addSalad(input:Salad):FoodType
    addBasic(input:BasicFood):FoodType
}

这不起作用有两个原因:

  1. 如果我想传递一个对象作为参数,那么这个对象必须是"输入"类型。但是"比萨","沙拉"和" BasicFood"只是"键入"。
  2. 输入类型无法实现接口。
  3. 所以,我需要像这样修改我之前的架构:

    interface FoodType {
        id: String
        type: String
        composition: [Ingredient]
    }
    
    type Pizza implements FoodType {
        id: String
        type: String
        pizzaType: String
        toppings: [String]
        size: String
        composition: [Ingredient]
    }
    
    type Salad implements FoodType {
        id: String
        type: String
        vegetarian: Boolean
        dressing: Boolean
        composition: [Ingredient]
    }
    
    type BasicFood implements FoodType {
        id: String
        type: String
        composition: [Ingredient]
    }
    
    type Ingredient {
            name: String
            qty: Float
            units: String
    }
    
    type Mutation {
        addPizza(input: PizzaInput): FoodType
        addSalad(input: SaladInput): FoodType
        addBasic(input: BasicInput): FoodType    
    }
    
    input PizzaInput {
        type: String
        pizzaType: String
        toppings: [String]
        size: String
        composition: [IngredientInput]
    }
    
    input SaladInput {
        type: String
        vegetarian: Boolean
        dressing: Boolean
        composition: [IngredientInput]
    }
    
    input BasicFoodInput {
        type: String
        composition: [IngredientInput]
    }
    
    input IngredientInput {
            name: String
            qty: Float
            units: String
    }
    

    所以,在这里我为Pizza,Salad和Basic食物定义了我的3种创作方法。 我需要定义3种输入类型(每种食物一种) 我还需要为Ingredients定义一个新的输入类型。

    它造成很多重复。那样你觉得可以吗?或者有更好的方法来解决这个问题?

    谢谢

1 个答案:

答案 0 :(得分:1)

您可以做的一些事情。例如,如果您以编程方式声明架构,则可以使用以下内容:

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)
})

或者如果您的对象/输入遵循类似的模式,您甚至可以编写一个函数来生成类型的输入:

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

或者,在使用makeExecutableSchema定义架构时,您可以执行以下操作:

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

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

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

所有这些方法的问题在于,虽然它们在技术上可能会使您的代码更加干燥,但它们也会降低您的架构的可读性,我认为这比复制本身更容易出错。 / p>

理解在语法上,类型和输入类型可能看起来相同,但在功能上它们不是这样,这一点也很重要。例如,类型上的字段可能包含参数:

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

输入类型字段没有参数,因此您无法在toppings类型及其对应的Pizza输入类型中对PizzaInput字段使用相同的语法。

就个人而言,我会咬紧牙关,只写出你已经完成的类型和输入。我唯一要做的就是将它们组合在一起(列出你的类型而不是你的输入),这样两者之间的任何差异都很容易被发现。但你的里程可能非常:)

相关问题