0
0
GraphQLquery~5 mins

Abstract type resolution in GraphQL

Choose your learning style9 modes available
Introduction

Abstract type resolution helps GraphQL know which specific type to use when a query asks for a general type. It makes sure you get the right data shape.

When you have a query that returns different types under one general category.
When you want to ask for common fields but also get type-specific fields.
When your data has different shapes but shares some common parts.
When you use interfaces or unions in your GraphQL schema.
When you want to handle multiple object types in one query response.
Syntax
GraphQL
interface Animal {
  id: ID!
  name: String!
}

type Dog implements Animal {
  id: ID!
  name: String!
  barkVolume: Int
}

type Cat implements Animal {
  id: ID!
  name: String!
  livesLeft: Int
}

union Pet = Dog | Cat

# Resolver example for interface or union
const resolvers = {
  Animal: {
    __resolveType(obj) {
      if (obj.barkVolume !== undefined) {
        return 'Dog';
      }
      if (obj.livesLeft !== undefined) {
        return 'Cat';
      }
      return null; // GraphQL will error if null
    }
  },
  Pet: {
    __resolveType(obj) {
      if (obj.barkVolume !== undefined) {
        return 'Dog';
      }
      if (obj.livesLeft !== undefined) {
        return 'Cat';
      }
      return null; // GraphQL will error if null
    }
  }
};

The __resolveType function tells GraphQL which concrete type to use.

This is needed for interfaces and unions because they can represent multiple types.

Examples
This example shows how to resolve between Car and Bike when querying Vehicle.
GraphQL
interface Vehicle {
  id: ID!
  make: String!
}

type Car implements Vehicle {
  id: ID!
  make: String!
  doors: Int
}

type Bike implements Vehicle {
  id: ID!
  make: String!
  hasPedals: Boolean
}

const resolvers = {
  Vehicle: {
    __resolveType(obj) {
      if (obj.doors !== undefined) {
        return 'Car';
      }
      if (obj.hasPedals !== undefined) {
        return 'Bike';
      }
      return null; // GraphQL will error if null
    }
  }
};
Here, the union SearchResult can be either Photo or Person, and the resolver picks the right one.
GraphQL
union SearchResult = Photo | Person

const resolvers = {
  SearchResult: {
    __resolveType(obj) {
      if (obj.url) {
        return 'Photo';
      }
      if (obj.name) {
        return 'Person';
      }
      return null; // GraphQL will error if null
    }
  }
};
Sample Program

This program sets up a GraphQL server with an Animal interface. It returns a list of animals that can be Dogs or Cats. The __resolveType function tells GraphQL which type each animal is.

GraphQL
const { ApolloServer, gql } = require('apollo-server');

const typeDefs = gql`
  interface Animal {
    id: ID!
    name: String!
  }

  type Dog implements Animal {
    id: ID!
    name: String!
    barkVolume: Int
  }

  type Cat implements Animal {
    id: ID!
    name: String!
    livesLeft: Int
  }

  type Query {
    animals: [Animal]
  }
`;

const animalsData = [
  { id: '1', name: 'Rex', barkVolume: 5 },
  { id: '2', name: 'Whiskers', livesLeft: 7 }
];

const resolvers = {
  Query: {
    animals: () => animalsData
  },
  Animal: {
    __resolveType(obj) {
      if (obj.barkVolume !== undefined) {
        return 'Dog';
      }
      if (obj.livesLeft !== undefined) {
        return 'Cat';
      }
      return null; // GraphQL will error if null
    }
  }
};

const server = new ApolloServer({ typeDefs, resolvers });

server.listen().then(({ url }) => {
  console.log(`Server ready at ${url}`);
});
OutputSuccess
Important Notes

The __resolveType function runs every time GraphQL needs to know the exact type.

If you forget to implement __resolveType, GraphQL will give an error when querying interfaces or unions.

Use abstract type resolution to keep your schema flexible and clean when dealing with multiple related types.

Summary

Abstract type resolution helps GraphQL pick the right type when you use interfaces or unions.

You write a __resolveType function that checks your data and returns the correct type name.

This makes your queries return the right fields for each specific type.