Mapping GraphQL interfaces to Rust


#1

I’m working on a for-fun implementation of Facebook’s GraphQL specification in Rust. What I’m trying for is being able to take a GraphQL IDL file like this and compile it to Rust traits, you could then implement these with static type checking like this to ensure you get a compliant GraphQL API, which you can query like this.

So far this all actually (kinda) works. It’s all very proof-of-concept, with no sensible error handling, schema verification or anything, but it actually runs and generates the right output.

The problem I have is that I can’t figure out a good way to map GraphQL’s interfaces onto Rust’s type system. I’ve used associated types to represent GraphQL types returned by fields/selections in the query, but this doesn’t work for GraphQL interfaces. My first thought was to represent them as Trait objects, that is if I have a schema like:

interface Entity {
  name: String!
}

type Person implements Entity {
  name: String!,
  age: Int!
  entity: Entity!
}

This would compile to:

trait ResolveEntity {
   name(&self) -> String;
}

trait ResolvePerson {
  name(&self) -> String;
  age(&self) -> i32;
  entity(&self) -> Box<ResolveEntity>
}

The problem is that this doesn’t work due to how GraphQL can be queried. Since the type of the trait object is erased by being boxed as a trait objects, type information is lost. But GraphQL can be queried like this:

query {
  person {
    name,
    entity {
      name
      ... on Person { age }
    }
  }
}

In order to be able to extract the age, I need to preserve type information.

Since I know the entire GraphQL schema, one thing I could do is encode interfaces as enums instead. Unfortunately this would make using those interfaces highly unergonomic with my current representation of GraphQL types as traits. It’d looks something like:

impl ResolvePerson for Person {
  type Entity = ResolveEntity<Person, Book, Animal, ... etc ... >;

  // ...
}

Where I’d have to specify the concrete Rust type of every single GraphQL type which implements the interface.

Is there some other, more elegant, way of achieving this? I’d love to hear any ideas!


#2

sounds interesting, a Graph query interface is very friendly to the users.