How to use unions with GraphQL buildSchema

Here is how I am using a GraphQL schema string to create a schema and attach it to my Express server:

var graphql = require('graphql');
var graphqlHTTP = require('express-graphql');
[...]
    return graphqlHTTP({
      schema: graphql.buildSchema(schemaText),
      rootValue: resolvers,
      graphiql: true,
    });

This is all very basic use of the modules. It works well and is quite convenient until I want to define a union:

union MediaContents = Photo|Youtube

type Media {
  Id: String
  Type: String
  Contents: MediaContents
}

I have found no way to make this work, querying Contents does what it has to do, returns the correct object but fails with the message Generated Schema cannot use Interface or Union types for execution.

Is it at all possible to use unions when using buildSchema ?

Upvotes: 4

Views: 2471

Answers (2)

Tahnik Mustasin
Tahnik Mustasin

Reputation: 2286

In case you are returning an object with all the information, you can add a __typename field in your object. Like this:

return {
  token: res.token,
  user: {
    __typename: 'YOUR_TYPE_HERE',
    ...res.user
  }
};

Upvotes: 3

stubailo
stubailo

Reputation: 6147

That's exactly why we created the graphql-tools package, which is like a production-ready, supercharged version of buildSchema: http://dev.apollodata.com/tools/graphql-tools/resolvers.html#Unions-and-interfaces

You can simply use unions by providing a __resolveType method on the union, as usual with GraphQL.js:

# Schema
union Vehicle = Airplane | Car

type Airplane {
  wingspan: Int
}

type Car {
  licensePlate: String
}

// Resolvers
const resolverMap = {
  Vehicle: {
    __resolveType(obj, context, info){
      if(obj.wingspan){
        return 'Airplane';
      }
      if(obj.licensePlate){
        return 'Car';
      }
      return null;
    },
  },
};

The only change is, instead of providing your resolvers as the root object, use makeExecutableSchema:

const graphqlTools = require('graphql-tools');
return graphqlHTTP({
  schema: graphqlTools.makeExecutableSchema({
    typeDefs: schemaText,
    resolvers: resolvers
  }),
  graphiql: true,
});

Also note that the signature of the resolvers will match the regular GraphQL.js style, so it's going to be (root, args, context) instead of just (args, context) which is what you get when you use the rootValue.

Upvotes: 8

Related Questions