Hi!
In many cases in my schema I have a situation where InputType and ObjectType have exactly the same shape.
So right now I am forced to write it like this:
@InputType()
export class ContactInput implements IContactSchema {
@Field({ nullable: true })
phone: string;
@Field({ nullable: true })
name: string;
@Field({ nullable: true })
email: string;
@Field({ nullable: true })
id?: string;
}
@ObjectType()
export class ContactResponse implements IContactSchema {
@Field({ nullable: true })
phone: string;
@Field({ nullable: true })
name: string;
@Field({ nullable: true })
email: string;
@Field({ nullable: true })
id?: string;
}
I've tried using @InterfaceType as follows:
@InterfaceType()
export abstract class IContactResource implements IContactSchema{
@Field({ nullable: true })
phone: string;
@Field({ nullable: true })
name: string;
@Field({ nullable: true })
email: string;
@Field({ nullable: true })
id?: string;
}
@InputType()
export class ContactInput extends IContactResource {
}
@ObjectType({implements: IContactResource})
export class ContactResponse extends IContactResource {
}
But this doesn't work since it requires me to add atleast one field to input (error is: Input Object type ContactInput must define one or more fields.)
What would be a better way to handle this?
Thanks in advance!
Already discussed in #62 😉
GraphQL distinguish InputType and ObjectType for a reason.
These are different things and shouldn't be mixed together - it makes more problems than the duplication introduce.
I've reviewed that discussion, and it's quite a shame that there is no way to reuse the interface. It could be helpful in alot of cases. Right now I have about 10 large ObjectTypes that look identical to InputTypes and I'll have to duplicate their definition due to this limitation. Partial
If they are identical, you can write it once:
@InputType("PersonInput")
@ObjectType("PersonType")
export class Person {
@Field()
name: string;
@Field()
dateOfBirth: Date;
}
Until the time when it will contain fields that express circular references or references to interfaces and unions, which will make Input side crash.
And please don't mix GraphQL interfaces, which are separate types existing in schema, with virtual TS interfaces and the inheritance. If you need your ObjectType match InputType to easily transfer input data to output, you can use pure interfaces:
interface IPerson {
name: string;
sex: SexEnum;
}
@InputType()
class PersonInput implements IPerson {
@Field()
name: string;
@Field(type => SexEnum)
sex: SexEnum;
@Field()
dateOfBirth: Date;
}
@ObjectType()
class Person implements IPerson {
@Field()
name: string;
@Field(type => SexEnum)
sex: SexEnum;
@Field()
age: number;
}
TypeGraphQL is sometimes opinionated for a reason. It's not my first project using decorators when there's discussion about code duplication as well as TypeGraphQL project arise based on experience from over a dozen months of developing GraphQL APIs in TypeScript.
It's technically possible to create virtual containers that are type (input, interface, object) agnostic just to get GQL field and TS properties types and then extend it in other classes. But as GraphQL spec puts a clear line separating input types from interfaces/object types, I won't contrive to create a inheritance workaround which will solve one problem and introduce plenty more weird bugs. Sorry 😉
I've tried combining the decorators, but got the following error:
[0] Error: Schema must contain unique named types but contains multiple
types named "ContactResponse".
This happens because I have two objects (one InputType and one ObjectType)
that have:
@Field(type => ContactResponse, { nullable: true })
So I guess in this case I am fresh out of luck?
On Thu, May 10, 2018 at 3:06 PM Michał Lytek notifications@github.com
wrote:
If they are identical, you can write it once:
@InputType("PersonInput")
@ObjectType("PersonType")export class Person {
@Field()
name: string;@Field()
dateOfBirth: Date;
}Until the time when it will contain fields that express circular
references or references to interfaces and unions, which will make Input
side crash.And please don't mix GraphQL interfaces, which are separate types existing
in schema, with virtual TS interfaces and the inheritance. If you need your
ObjectType match InputType to easily transfer input data to output, you can
use pure interfaces:interface IPerson {
name: string;
sex: SexEnum;
}@InputType()class PersonInput implements IPerson {
@Field()
name: string;@Field(type => SexEnum)
sex: SexEnum;@Field()
dateOfBirth: Date;
}@ObjectType()class Person implements IPerson {
@Field()
name: string;@Field(type => SexEnum)
sex: SexEnum;@Field()
age: number;
}TypeGraphQL is sometimes opinionated for a reason. It's not my first
project using decorators when there's discussion about code duplication
https://github.com/typestack/routing-controllers/issues/147 as well as
TypeGraphQL project arise based on experience from over a dozen months of
developing GraphQL APIs in TypeScript.It's technically possible to create virtual containers that are type
(input, interface, object) agnostic just to get GQL field and TS properties
types and then extend it in other classes. But as GraphQL spec puts a clear
line separating input types from interfaces/object types, I won't contrive
to create a inheritance workaround which will solve one problem and
introduce plenty more weird bugs. Sorry 😉—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/19majkel94/type-graphql/issues/76#issuecomment-388034666,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAGtNK33S0_YAocoi63b7amhEJV1FoIpks5txC0_gaJpZM4T5ixl
.
@InputType()
@ObjectType()
export class Person {}
By default the name of the type is the name of the class.
So in this case it would try to create both input and object type with the same Person name.
So you need to provide the name explicitly to avoid the conflict:
``ts
@InputType("PersonInput")
@ObjectType("PersonType")
export class Person {}
````
So yourContactResponsehas to have different names for input and object type side. Then you can use it in your objects (InputType and ObjectType one) that have@Field(type => ContactResponse, { nullable: true })`
Amazing. Works. Thank you so much!
On Thu, May 10, 2018 at 3:15 PM Michał Lytek notifications@github.com
wrote:
@InputType()
@ObjectType()export class Person {}By default the name of the type is the name of the class.
So in this case it would try to create both input and object type with the
same Person name.
So you need to provide the name explicitly to avoid the conflict:@InputType("PersonInput")
@ObjectType("PersonType")export class Person {}—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/19majkel94/type-graphql/issues/76#issuecomment-388036557,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAGtNIBz75x8XO6bRaZGX21vM58sKm6Fks5txC9_gaJpZM4T5ixl
.
Most helpful comment
By default the name of the type is the name of the class.
So in this case it would try to create both input and object type with the same
Personname.So you need to provide the name explicitly to avoid the conflict:
``
ts @InputType("PersonInput") @ObjectType("PersonType") export class Person {} ```` So yourContactResponsehas to have different names for input and object type side. Then you can use it in your objects (InputType and ObjectType one) that have@Field(type => ContactResponse, { nullable: true })`