juniper
juniper copied to clipboard
GraphQL Union types on generic Rust enums
I've been struggling to figure out the best way to implement a generic rust enum as a GraphQL union.
Objective
My goal is to have a generic enum type in rust enum Thing<T>
and be able to export concrete types of this generic type to my GraphQL schema.
For example, having:
#[derive(GraphQLUnion)]
pub enum Thing<T> {
A(ThingA<T>),
B(ThingB<T>),
C(ThingC<T>),
}
where I can explicitly export types like
union IntThing = IntThingA | IntThingB | IntThingC
for Thing<i32>
.
My current solution is to create the entire enum and enum variant structs in a macro for each type, but it would be a significant improvement for me to be able to define a generic struct and just have some sort of implementation for each type I want to export. This will allow me to define more implementations like methods on the generic type without leaning so much into the macro (I would prefer not having to write all function methods in the macro definition).
We can export generic structs as GraphQL objects using the #[juniper::graphql_object]
on a concrete implementation like so:
struct Thing<T> {
something: T,
}
#[juniper::graphql_object(name = "IntThing")]
impl Thing<i32> {
fn something(&self) -> i32 {
self.something
}
}
But it's unclear to me how to do a similar thing for union types.
Attempt
My current best attempt looks similar to what I would do for enums with generic lifetimes:
#[derive(GraphQLUnion)]
#[graphql(
on ThingA<T> = Thing::resolve_a,
on ThingB<T> = Thing::resolve_b,
on ThingC<T> = Thing::resolve_c,
)]
enum Thing<T> {
#[graphql(skip)]
A(ThingA<T>),
#[grapqhl(skip)]
B(ThingB<T>),
#[graphql(skip)]
C(ThingC<T>),
}
This fails with:
error[E0401]: can't use generic parameters from outer item
|
13 | on ThingA<T> = Thing::resolve_a,
| ^ use of generic parameter from outer item
...
18 | enum Thing<T> {
| - type parameter from outer item
|
= note: a `const` is a separate item from the item that contains it
I can only implement #[graphql_union]
on traits, so that is not an option, and #[graphql_object]
isn't appropriate here either.