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) }, }, });
No, the spec does not allow input types to implement interfaces. And GraphQL type system in general does not define any form of inheritance (the extends keyword adds fields to an existing type, and isn't for inheritance).
Types in GraphQL are grouped into output types and input types. Output types are types that may be returned as part of a response produced by a GraphQL service. Input types are types that are valid inputs for field or directive arguments.
There are three types of operations that GraphQL models: query – a read‐only fetch. mutation – a write followed by a fetch. subscription – a long‐lived request that fetches data in response to source events.
To make your schema simpler, you can use “input types” for this, by using the input keyword instead of the type keyword. id: ID! Here, the mutations return a Message type, so that the client can get more information about the newly-modified Message in the same request as the request that mutates it.
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
).
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} } `)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With