w3resource

Integrating with Meteor


Apollo can be used in a meteor app in two main ways:

  1. meteor add swydo:ddp-apollo provides a network Link that supports Meteor user accounts and subscriptions, all over DDP
  2. meteor add apollo supports Meteor user accounts over HTTP.

Compatibility: The table below outlines Apollo compatibility with meteor

METEOR/APOLLO APOLLO CLIENT APOLLO SERVER
3.* 2.* 2.*
2.* 2.* 1.*
1.* 1.* 1.*
.

Usage

meteor add apollo
meteor npm install graphql apollo-server-express apollo-boost

Client

Create your ApolloClient instance:

import { Accounts } from 'meteor/accounts-base'
import ApolloClient from 'apollo-boost'

const client = new ApolloClient({
  uri: '/graphql',
  request: operation =>
    operation.setContext(() => ({
      headers: {
        authorization: Accounts._storedLoginToken()
      }
    }))
})

Or if you're using apollo-client instead of apollo-boost, use MeteorAccountsLink():

import { ApolloClient } from 'apollo-client'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { ApolloLink } from 'apollo-link'
import { HttpLink } from 'apollo-link-http'
import { MeteorAccountsLink } from 'meteor/apollo'

const client = new ApolloClient({
  link: ApolloLink.from([
    new MeteorAccountsLink(),
    new HttpLink({
      uri: '/graphql'
    })
  ]),
  cache: new InMemoryCache()
})

If you want to change which header the token is stored in:

MeteorAccountsLink({ headerName: 'meteor-login-token' })

Normally, the default header location for storing login-tokens is authorization.

Server

Set up the Apollo server:

import { ApolloServer, gql } from 'apollo-server-express'
import { WebApp } from 'meteor/webapp'
import { getUser } from 'meteor/apollo'
import typeDefs from './schema'
import resolvers from './resolvers'

const server = new ApolloServer({
  typeDefs,
  resolvers,
  context: async ({req}) => ({
    user: await getUser(req.headers.authorization)
  })
})

server.applyMiddleware({
  app: WebApp.connectHandlers,
  path: '/graphql'
})

WebApp.connectHandlers.use('/graphql', (req, res) => {
  if (req.method === 'GET') {
    res.end()
  }
})

Now when the client is logged in (that is has an unexpired Meteor login token in localStorage), your resolvers will have a context.user property with the user doc.

Accounts

The above solutions assume you're using Meteor's client-side accounts functions like Accounts.createUser and Accounts.loginWith*, which use Meteor DDP messages.

If you want to instead only use GraphQL in your app, you can use nicolaslopezj:apollo-accounts. This package uses the Meteor Accounts methods in GraphQL, and it's compatible with the accounts you have saved in your database (and you could use nicolaslopezj:apollo-accounts and Meteor's DDP accounts at the same time).

If you are relying on the current user in your queries, you'll want to clear the store when the current user state changes. To do so, use client.resetStore() in the Meteor.logout callback:

// The `client` variable refers to your `ApolloClient` instance.
// It would be imported in your template,
// or passed via props thanks to `withApollo` in React for example.

Meteor.logout(function() {
  return client.resetStore(); // make all active queries re-run when the log-out process completed
});

SSR

There are two additional configurations that you need to keep in mind when using React Server Side Rendering with Meteor.

  1. Use isomorphic-fetch to polyfill fetch server-side (used by Apollo Client's network interface).
  2. Connect your express server to Meteor's existing server with WebApp.connectHandlers.use
  3. Do not end the connection with res.send() and res.end() use req.dynamicBody and req.dynamicHead instead and call next().

The idea is that you need to let Meteor to finally render the html you can just provide it extra body and or head for the html and Meteor will append it, otherwise CSS/JS and or other merged html content that Meteor serve by default (including your application main .js file) will be missing.

Importing .graphql files

An easy way to work with GraphQL is by importing .graphql files directly using the import syntax.

meteor add swydo:graphql

Instead of the /imports/api/schema.js file, create a /imports/api/schema.graphql file with the same content as before:

type Query {
  say: String
}

One of the benefits you'll get right away is good highlighting by GitHub and your IDE!

Now we can import the schema:

import typeDefs from '/imports/api/schema.graphql';

Use typeDefs as before in the above examples. You can pass it directly to makeExecutableSchema like before.

The import syntax will also work for any other .graphql file besides your main schema. So you'll be able to import query, mutation and subscription files without needing to manually parse them with the graphql-tag.

Previous: Integrating with React Native
Next: Loading queries with Webpack