Blaze-Apollo, a first draft

The Goal.

There are a few things that the Blaze-Apollo integration should focus on. That is developer experience and familiarity for Blaze developers who have worked with Template subscriptions and ReactiveVars. This means automatic cleanup when a Template is removed and of course the Tracker reactivity we all know.

A discussion has already taken place about this subject in the Meteor forums and this article is partly based on the proposals in that thread.

We'll look into what the API should look like first and later focus on any technical implementations. (Disclaimer, I have a prototype working, but want to discuss further details first, before sharing it).

Something to query.

For the examples below we'll use the following Star Wars data:

import gql from 'graphql-tag';

const QUERY = gql`  
{
  human(id: "1000") {
    name
    height(unit: FOOT)
  }
}
`;

The result will look like this:

{
  "data": {
    "human": {
      "name": "Luke Skywalker",
      "height": 5.6430448
    }
  }
}

Directly copied from the awesome GraphQL examples.

Basic template example.

Template.myTemplate.helpers({  
  human() {
    Template.instance().gqlQuery({ query: QUERY }).get().human;
  }
});

Besides query, all other options for ApolloClient.watchQuery are available. Like pollInterval, forceFetch, noFetch and variables.

<template name="myTemplate">  
  <h1>{{human.name}}</h1>
  <p>The height of this human is {{human.height}} foot.</p>
</template>  

And done! GraphQL data in your templates!

Deep dive into the API

The example above is great for a quick setup, but sometimes you need more control. We can do that by catching the result of the query. This gives us an ApolloResult variable with a reactive get() method, just like any ReactiveVar:

Template.myTemplate.onCreated(function() {  
  const result = this.gqlQuery({ query: QUERY });

  // This is reactive
  result.get(); 

  // So this will rerun automatically when data in the cache changes
  // This includes updates from mutations and (GraphQL) subscriptions
  this.autorun(function() {
    result.get();
  });

  // Stop listening to updates
  // Note: This is automatically done when the template is destroyed
  result.unsubscribe();

  // You might need some control over the observer
  // It's simply available on the result
  result.observer.setVariables({});
});

Generic template helpers.

We can also supply subscription like template helpers that tell us if the queries are loaded:

<template name="myTemplate">  
  {{#if queriesReady}}
    <p>Loaded {{human.name}}</p>
  {{else}}
    <p>Loading...</p>
  {{/if}}
</template>  

Just like Template.subscribe it will mark the queries as ready when the data is loaded for the first time. We could also support partial data later by adding a parameter that defines if we should wait for those too: this.queriesReady({waitForPartials: true}).

Setup.

The setup should require only a single command, without losing any flexibility. The user should still be able to completely configure the Apollo client.

import ApolloClient from 'apollo-client';  
import { Blaze } from 'meteor/blaze';  
import { setup } from 'meteor/blaze-apollo';

// Create a client like you always would
const client = new ApolloClient({});

// This will setup the Apollo client to work with Blaze templates
setup(Blaze, { client });  

That's it! Up and running!

Information about how to get the ApolloClient configured can be found in the apollostack/meteor-integration repo.

Conclusion.

We might need to decide on API naming, but I believe this is a good basis for Blaze developers to get up and running with GraphQL, using Apollo.

Feedback is much appreciated!