简体   繁体   中英

type graphql union type in a field

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?

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM