Skip to content
Cory Cook edited this page Sep 2, 2018 · 2 revisions

GraphQL Schema Bindings uses decorators to expose native JavaScript and TypeScript classes via a GraphQL endpoint as GraphQL types. This is similar to other libraries that use decorators to define your GraphQL schema; however, GraphQL Schema Bindings does not attempt to provide functionality for all GraphQL concepts. Instead, this library attempts to expose some of the native concepts associated with JavaScript prototypes and object oriented classes through your GraphQL schema, such as inheritance and polymorphism.

GraphQL Schema Bindings was created due to the difficulties encountered while implementing the standard typeDefs and resolvers format for GraphQL server definition. In a typeDefs and resolvers structure a schema is defined using GraphQL schema language. A separate object is then provided with a set of functions that act as the resolver methods for the schema. Here is a simple example of this structure:

const typeDefs = gql`
  type Resource {
    id: ID
    name: String
  }

  type Query {
    getResource(id: ID!): Resource
  }
`;

const resolvers = {
  Resource: {
    id: data => data.id,
    name: data => data.name,
  },
  Query: {
    getResource: (root, args, context) => {
      return context.model.getResource(args.id);
    },
  },
};

const schema = createExecuteableSchema({ typeDefs, resolvers });

This presents a few difficulties for large applications:

  • GraphQL schema language is introduced and, while the language is straight-forward, it presents additional learning and cognitive overhead to the developers.
  • Any changes to the schema need to happen in two places: the schema language and the resolver methods.
  • Sharing code between the resolvers is not straight forward and results in additional methods being created to share logic across the implementation.
  • When implementing the resolver methods you need to reference the schema language in order to determine the argument name and types and return types.

GraphQL Schema Bindings helps alleviate some of these concerns:

  • There is no new schema language introduced. Decorators are introduced, but they are simple and follow a consistent format.
  • Schema definitions are bound to their resolver methods so the implementation need only be updated in a single place.
  • Resolver methods exist as methods of their native type so sharing implementation between fields is as easy as calling the method or accessing the property that defines that field.
  • The schema bindings exist as part of the resolver method so the reference is always immediately available.

This is the GraphQL Schema Bindings implementation of the above example:

@type
class Resource {
  @field(ID)
  get id() {
    return this.data.id;
  }

  @field(String)
  get name() {
    return this.data.name;
  }

  constructor(data) {
    this.data = data;
  }
}

@type
class Query {
  @context context;

  @field(Resource)
  getResource(@arg(ID) @required id) {
    return new Resource(this.context.model.getResource(id));
  }
}

const schema = createSchema(Query);
Clone this wiki locally