Interfaces and unions

GraphQL · Practical · 12 min

Search results, feeds and node lookups are all polymorphic.

An interface declares fields that several object types share; each type implements it and must include those fields:

interface Node { id: ID! }
type User implements Node { id: ID!  name: String! }
type Post implements Node { id: ID!  title: String! }

A union says a value is one of several object types that need not share any fields: union SearchResult = User | Post | Tag.

Querying polymorphic fields:

  • Fields declared on an interface can be selected directly.
  • Type-specific fields need an inline fragment ... on Post { title }.
  • For a union you can only select __typename directly; everything else goes through fragments.

On the server, the runtime must know each value's concrete type. In graphql-tools style resolver maps you add __resolveType(obj) on the interface or union, returning the type name; alternatively types can define isTypeOf.

Choose an interface when types truly share a contract you will query generically; choose a union for "one of these unrelated things" such as search results or a mutation result that is either a success or one of several error types. Interfaces can also implement other interfaces.

Example

const typeDefs = `
  interface Node { id: ID! }
  type User implements Node { id: ID!  name: String! }
  type Post implements Node { id: ID!  title: String! }
  union SearchResult = User | Post
  type Query { search(text: String!): [SearchResult!]! }
`;
const resolvers = {
  SearchResult: {
    __resolveType: (obj) => (obj.title ? "Post" : "User"),
  },
};
// Query:
// { search(text: "graph") {
//     __typename
//     ... on User { name }
//     ... on Post { title } } }
// -> [{"__typename":"Post","title":"Graph theory"},
//     {"__typename":"User","name":"Grace"}]

Remember

  • Interface = shared fields; union = one of unrelated types
  • Use ... on Type for type-specific fields
  • Servers need __resolveType (or isTypeOf) for abstract types

Watch out for

  • Forgetting __resolveType, which makes every polymorphic field fail at runtime.

Check yourself

  1. On a union field, what can you select without an inline fragment?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: graphql.org/learn/schema/#interfaces