meteor/meteor

View on GitHub
guide/source/apollo.md

Summary

Maintainability
Test Coverage
---
title: Apollo
order: 15
description: The Apollo data stack for Reactive GraphQL
discourseTopicId: TODO
---

<h2 id="introduction">Introduction</h2>

Apollo is a GraphQL client/server for transporting data. While it doesn't yet have all the features that Meteor's pub/sub system has, it provides a way to get data from any database – not just MongoDB.

- [Apollo docs](https://www.apollographql.com/docs/)

You can get started with Apollo and Meteor by creating a new Meteor application with the Apollo skeleton:
```shell
meteor create apollo-app --apollo
```

<h3 id="client">Apollo Client</h3>

[Apollo client docs](https://www.apollographql.com/docs/react/)

<h4 id="getting-data">Getting data</h4>

Instead of calling `Meteor.subscribe`, you will use [queries](https://www.apollographql.com/docs/react/data/queries/) to get data.

The main difference with subscriptions is that queries get called only once (by default) and don't get updated data like a subscription would. This is great for data that doesn't change often and where you don't need reactivity. 

<h4 id="changing-data">Changing data</h4>

Instead of calling a Meteor method with `Meteor.call`, you use a function called [`mutate`](https://www.apollographql.com/docs/react/data/mutations/) to run a *mutator*, which is GraphQL's equivalent to a method.

Mutators are only run on the server, but they can return an object which then can update the local cache without the need to call a query again.

<h3 id="server">Apollo Server</h3>

[Apollo server docs](https://www.apollographql.com/docs/apollo-server/)

<h4 id="getting-data-server">Getting data</h4>

Instead of using `Meteor.publish` to define publications, you write [resolve functions](https://www.apollographql.com/docs/apollo-server/data/resolvers/) – called *resolvers* – that fetch different types of data in the query.

<h4 id="changing-data-server">Changing data</h4>

Instead of using `Meteor.methods` to define methods, you write [mutators](https://www.apollographql.com/docs/tutorial/mutation-resolvers/) – functions that *mutate* (change) data.

These are part of the resolver functions under `Mutation` key.

<h3 id="graphql">GraphQL</h3>

GraphQL is a query language for apps to get the data they want. Instead of the server deciding what's in a publication, the client uses GraphQL to say exactly which fields of which objects it wants. 

- [About GraphQL](https://graphql.org/)
- [Intro to GraphQL](https://medium.com/apollo-stack/the-basics-of-graphql-in-5-links-9e1dc4cac055)
- [GraphQL coming from REST](https://medium.com/apollo-stack/how-do-i-graphql-2fcabfc94a01#.pfdj5bxxj)

<h3 id="advanced">Advanced<h3>

[Principled GraphQL](https://principledgraphql.com/)

<h4 id="latency">Latency</h4>

Meteor publications are blocking by default, whereas multiple GraphQL queries are executed in parallel. Publications stream data to the client as it arrives, whereas all the resolvers in a GraphQL query have to return before the data is sent to the client. (Although GraphQL is discussing adding the ability to stream results to the client as they come in.)

<h3>Meteor specific</h3>

Meteor has a specific Apollo package which includes user object into the context of a query.

```shell
meteor add apollo
```

On server you import `getUser` function and include it into the context option when setting up Apollo server:

```javascript
import { ApolloServer } from '@apollo/server';
import { WebApp } from 'meteor/webapp';
import { getUser } from 'meteor/apollo';
import typeDefs from '/imports/apollo/schema.graphql';
import { resolvers } from '/server/resolvers';
import express from 'express';
import { expressMiddleware } from '@apollo/server/express4';
import { json } from 'body-parser'

const context = async ({ req }) => ({
  user: await getUser(req.headers.authorization)
})

const server = new ApolloServer({
  cache: 'bounded',
  typeDefs,
  resolvers,
});

export async function startApolloServer() {
  await server.start();

  WebApp.connectHandlers.use(
    '/graphql',                                     // Configure the path as you want.
    express()                                       // Create new Express router.
      .disable('etag')                     // We don't server GET requests, so there's no need for that.
      .disable('x-powered-by')             // A small safety measure.
      .use(json())                                  // From `body-parser`.
      .use(expressMiddleware(server, { context })), // From `@apollo/server/express4`.
  )
}
```

This will make user data available (if user is logged in) as the option in the query:
```javascript
{
  Query: {
    userUniverses: async (obj, { hideOrgs }, { user }) => {
      if (!user) return null
      const selector = { userId: user._id, }
      if (hideOrgs) selector.organizationId = { $exists: false }
      return UniversesCollection.find(selector).fetch()
    }
  }
}
```

There are many other community packages that provide additional features or makes the initial setup easier, here is an incomplete list of some of them:

* [quave:graphql](https://atmospherejs.com/quave/graphql) - Utility package to create GraphQL setup in a standard way.
* [cultofcoders:apollo](https://atmospherejs.com/cultofcoders/apollo) - Meteor & Apollo integration.
* [cultofcoders:graphql-loader](https://atmospherejs.com/cultofcoders/graphql-loader) - Easily load your GraphQL schema in your Meteor app!
* [cultofcoders:apollo-accounts](https://atmospherejs.com/cultofcoders/apollo-accounts) - Meteor accounts in GraphQL
* [swydo:blaze-apollo](https://atmospherejs.com/swydo/blaze-apollo) - Blaze integration for the Apollo Client
* [swydo:ddp-apollo](https://atmospherejs.com/swydo/ddp-apollo) - DDP link and server for Apollo.