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

半城伤御伤魂 提交于 2020-08-21 07:56:13

问题


I have some object types that I'd like to use as both input and output - for instance a currency type or a reservation type.

How do I define my schema to have a type that supports both input and output - I don't want to duplicate code if I don't have to. I'd also prefer not to create duplicate input types of things like currency and status enums.

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

回答1:


In the GraphQL spec, objects and input objects are distinct things. Quoting 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.

While an implementation might provide convenience code to create an object and a corresponding input object from a single definition, under the covers, the spec indicates that they'll have to be separate things (with separate names, such as Reservation and ReservationInput).




回答2:


You can do something like this:

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:


this is something that i did for my project (works good):

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:


While working on a project I had a similar problem with code duplication between input and type objects. I did not find the extend keyword very helpful as it only extended the fields of that specific type. So the fields in type objects cannot not be inherited in input objects.

In the end I found this pattern using literal expressions helpful:

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

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


来源:https://stackoverflow.com/questions/41515679/can-you-make-a-graphql-type-both-an-input-and-output-type

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