【问题标题】:Can you make a graphql type both an input and output type?你可以让一个graphql类型既是输入类型又是输出类型?
【发布时间】:2017-05-21 19:19:31
【问题描述】:

我想将一些对象类型用作输入和输出,例如货币类型或预订类型。

如何将我的架构定义为具有同时支持输入和输出的类型 - 如果不需要,我不想复制代码。我也不想创建重复的输入类型,比如货币和状态枚举。

export const ReservationInputType = new InputObjectType({
  name: 'Reservation',
  fields: {
    hotelId: { type: IntType },
    rooms: { type: new List(RoomType) },
    totalCost: { type: new NonNull(CurrencyType) },
    status: { type: new NonNull(ReservationStatusType) },
  },
});

export const ReservationType = new ObjectType({
  name: 'Reservation',
  fields: {
    hotelId: { type: IntType },
    rooms: { type: new List(RoomType) },
    totalCost: { type: new NonNull(CurrencyType) },
    status: { type: new NonNull(ReservationStatusType) },
  },
});

【问题讨论】:

    标签: graphql graphql-js


    【解决方案1】:

    在 GraphQL 规范中,对象和输入对象是不同的东西。引用the spec for input objects:

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

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

    一个输入对象定义了一组输入字段;输入字段可以是标量、枚举或其他输入对象。这允许参数接受任意复杂的结构。

    虽然实现可能会提供方便的代码来从单个定义创建对象和相应的输入对象,但实际上,规范表明它们必须是单独的事物(具有单独的名称,例如 ReservationReservationInput)。

    【讨论】:

    • 关于类型和输入的单独名称在哪里说明?
    • @4F2E4A2E:嗯,我引用的规范部分涵盖了这一点(对象与输入对象)。
    • @4F2E4A2E:“两个定义可以具有相同的名称但具有不同的类型,对吧?” ——据我所知,不是。符号在大多数编程语言中必须是唯一的。
    • 谢谢,我已经测试过了,这显然是不可能的。 @MonkeyBonkey:不要忘记将此标记为已回答。
    • 这是不可能的,从开发人员的角度来看是一个重大缺陷。我希望他们有充分的理由这样设置它。导致非常 WET 的代码。
    【解决方案2】:

    你可以这样做:

    export const createTypes = ({name, fields}) => {
      return {
        inputType: new InputObjectType({name: `${name}InputType`, fields}),
        objectType: new ObjectType({name: `${name}ObjectType`, fields})
      };
    };
    
    const reservation = createTypes({
      name: "Reservation",
      fields: () => ({
        hotelId: { type: IntType },
        rooms: { type: new List(RoomType) },
        totalCost: { type: new NonNull(CurrencyType) },
        status: { type: new NonNull(ReservationStatusType) }
      })
    });
    // now you can use:
    //  reservation.inputType
    //  reservation.objectType

    【讨论】:

    • 我赞成这个想法,但在我看来非常老套
    【解决方案3】:

    这是我为我的项目所做的事情(效果很好):

    const RelativeTemplate = name => {
      return {
        name: name,
        fields: () => ({
          name: { type: GraphQLString },
          reference: { type: GraphQLString }
        })
      };
    };
    const RelativeType = {
      input: new GraphQLInputObjectType(RelativeTemplate("RelativeInput")),
      output: new GraphQLObjectType(RelativeTemplate("RelativeOutput"))
    };
    

    【讨论】:

    • 如果共享字段是非标量字段将不起作用:(
    【解决方案4】:

    在处理一个项目时,我遇到了inputtype 对象之间的代码重复的类似问题。我没有发现 extend 关键字很有帮助,因为它只扩展了该特定类型的字段。所以type对象中的字段不能不被input对象继承。

    最后我发现这种使用文字表达式的模式很有帮助:

    const UserType = `
        name: String!,
        surname: String!
    `;
    
    const schema = graphql.buildSchema(`
        type User {
            ${UserType}
        }
        input InputUser {
            ${UserType}
        }
    `) 
    

    【讨论】:

    • 这是我认为最好的解决方案。虽然我个人更喜欢使用 file.graphql,因为它独特且消除了复杂性。我认为 graphql 的创建者应该致力于通过变量类型在类型和输入之间共享数据的解决方案。
    • @SteveTomlin 你知道如何在 .graphql 文件中解决它吗?我找不到任何参考
    • 当然。一个例子: import * as schemaGame from './_game.graphql';
    猜你喜欢
    • 2016-01-17
    • 2019-03-15
    • 2019-02-25
    • 1970-01-01
    • 2021-01-10
    • 2012-02-10
    • 1970-01-01
    • 2018-12-18
    相关资源
    最近更新 更多