你能让一个 graphql 类型既是输入类型又是输出类型吗?

Can you make a graphql type both an input and output type?

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

如何定义我的模式以具有同时支持输入和输出的类型 - 如果不需要,我不想复制代码。我也不希望创建重复的输入类型,例如货币和状态枚举。

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 规范中,对象和输入对象是不同的东西。引用 the spec for input objects:

Fields can define arguments that the client passes up with the query, to configure their behavior. These inputs can be Strings or Enums, but they sometimes need to be more complex than this.

The Object type... is inappropriate for re‐use here, because Objects can contain fields that express circular references or references to interfaces and unions, neither of which is appropriate for use as an input argument. For this reason, input objects have a separate type in the system.

An Input Object defines a set of input fields; the input fields are either scalars, enums, or other input objects. This allows arguments to accept arbitrarily complex structs.

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

你可以这样做:

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

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

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

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

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

const UserType = `
    name: String!,
    surname: String!
`;

const schema = graphql.buildSchema(`
    type User {
        ${UserType}
    }
    input InputUser {
        ${UserType}
    }
`)