DEV Community

loading...

Discussion on: Enhancing GraphQL Schemas with Interfaces

jaxolotl profile image
Javier Valderrama (Jax)

This is a really interesting question. I've been looking at the implementation and didn't find a viable solution so far. The problem seems to be related to the way the __resolveType method is implemented. It's designed to force you to return a type name as a String and just one. Clearly that's part of the GraphQL declarative nature

    __resolveType(obj, context, info) {

      const {
        certified,
        privateLessons
      } = obj;

      if (certified) {
        return 'SkiPatrol';
      }

      if (privateLessons) {
        return 'Instructor';
      }

      return 'WateverDefault';
    },

And depending on the order of the early returns you'll end up having the first match.

A possible workaround might be to have multiple interfaces:

interface Employee {
  id: ID!
  firstName: String!
  lastName: String!
  role: [Role!]!
}

interface InstructorInterface {
  level: Int!
  privateLessons: Boolean!
}

interface SkiPatrolInterface {
  certified: Boolean!
  aviLevel: Int!
}

type Instructor implements Employee & InstructorInterface {
  id: ID!
  firstName: String!
  lastName: String!
  role: [Role!]!
  ##
  level: Int!
  privateLessons: Boolean!
}

type SkiPatrol implements Employee & SkiPatrolInterface{
  id: ID!
  firstName: String!
  lastName: String!
  role: [Role!]!
  ##
  certified: Boolean!
  aviLevel: Int!
}

type SkiPatrolAndInstructor implements Employee & SkiPatrolInterface & InstructorInterface{
  id: ID!
  firstName: String!
  lastName: String!
  role: [Role!]!
  ##
  certified: Boolean!
  aviLevel: Int!
  ##
  level: Int!
  privateLessons: Boolean!
}

and resolve it like this

    __resolveType(obj, context, info) {

      const {
        certified,
        privateLessons
      } = obj;

      if (certified && privateLessons) {
        return 'SkiPatrolAndInstructor';
      }

      if (certified) {
        return 'SkiPatrol';
      }

      if (privateLessons) {
        return 'Instructor';
      }

      return 'WateverDefault';
    },

obviously this is just a hint and probably not the best practice for production quality code, but it might help you think something more elegant

Thread Thread
mikemeerschaert profile image
mikemeerschaert • Edited

Thanks for the reply! This is actually exactly how I ended up implementing my schema! I have a file called CombinationTypes that defines all the different permutations of combined interfaces. When new combos are needed it's as simple as adding them to the schema since the interfaces already have the resolvers mapped to them. I have a "base" interface (like you have here with employee) that every combination type implements, and then I have a json object that maps possible values of fields on the base interface to all the various combo types. It's not in production yet, but it actually works very well.

Thread Thread
jaxolotl profile image
Javier Valderrama (Jax)

Maybe I'm not getting it right, but it sounds to me as something you might achieve in a more GraphQL style by using Federation, Schema Composition and Apollo Gateway.

Here a link to the documentation and 2 excellent videos

apollographql.com/docs/apollo-serv...

youtube.com/watch?v=v_1bn2sHdk4

youtube.com/watch?v=OFT9bSv3aYA

I hope you find this useful.