Reputation: 2999
Alright I have what I believe is a pretty simple setup where I want to gather metrics. each metric can be of different types and thus have different points, that can be represented with inheritance. A slimmed down version can look like this:
@ObjectType()
@InputType("MetricInput")
export class Metric {
@Field({ nullable: false })
service: string;
@Field({ nullable: false })
name: string;
@Field({ nullable: false })
fill: FillMode;
@Field(type => [PointUnionType])
points: [Point | StatePoint];
constructor(metric: Metric) {
Object.assign(this, metric);
}
}
@ObjectType()
@InputType()
export class Point {
@Field({ nullable: false })
timestamp: number;
}
@ObjectType()
@InputType()
export class StatePoint extends Point {
@Field({ nullable: false })
state: string;
}
Note that StatePoint
extends Point
, and for this scenario, let's assume that both are valid in the Metric
class.
The question then becomes, how do I get type-graphql
to register and accept this?
As you can see I tried creating a union type which looks like this:
const PointUnionType = createUnionType({
name: "PointUnion",
types: () => [Point, StatePoint] as const,
resolveType: (value) => {
if ("state" in value) {
return StatePoint;
}
return Point;
},
});
But I am stuck with this errror
UnhandledPromiseRejectionWarning: Error: Cannot determine GraphQL input type for 'points' of 'Metric' class. Is the value, that is used as its TS type or explicit type, decorated with a proper decorator or is it a proper input value?
So I assume that I am missing something rather basic?
does it perhaps relate to me trying to use Metric
as both an output and an input object?
edit If I split the object I can get the return type to be a union, but then if I try something like this it will fail in the same way
@Mutation(() => Boolean)
addPoint(
@Arg("point", () => PointUnionType, { nullable: false }) point: Point
) {
return false;
}
So I assume that the issue is with union inputs. Is that something that is just straight up not supported, or how are you supposed to use it?
Upvotes: 1
Views: 2449
Reputation: 12077
In your example, you're trying to use union type as an argument (input) which is not supported by GraphQL spec. You need to use an other pattern (input with nullable nested fields) to have different types accepted as an argument.
Also, you're using the "double decorators" workaround syntax:
@ObjectType()
@InputType("MetricInput")
Which is not recommended and dangerous unless you know what you're doing. And in your case you're also breaking the GraphQL law by having an union field in input type, which is invalid.
You should split your input and object types definition - it's not duplication, they are totally separate elements in GraphQL as input can't contain interfaces, union types, object types and non-nullable cyclic references.
Upvotes: 1