Simple modularity with Apollo Link

Probably the biggest change in Apollo Client 2.0 is the transition from using the concept of a network interface to a more modular approach based on a new primitive: Apollo Link.

Note: To learn more about the motivation behind Apollo Link, check out this article by Evans Hauser who worked on Apollo Link as a summer intern: Apollo Link: The modular GraphQL network stack

The now deprecated network interface used to enable your ApolloClient instance to send HTTP requests. It was also possible to hook into the process of preparing and sending the request (or processing the response) using the concept of middleware, e.g. for adding headers to the request.

Apollo Client 2.0 still is based on the idea of middleware — however, this middleware now actually is a first-class citizen and can be implemented using Apollo Link. For each task that you require for your networking stack (data validation, logging, caching,…) you can now write a dedicated link and simply add it to the chain of middleware that’s invoked whenever you’re sending a request.

Here is what a simple implementation for a Link that’s making HTTP calls based on graphql-request looks like:

class GraphQLRequestLink extends ApolloLink { constructor ( { endpoint , headers } ) { super ( ) this . client = new GraphQLClient ( endpoint , { headers } ) } request ( operation ) { return new Observable ( observer => { const { variables , query } = operation this . client . request ( print ( query ) , variables ) . then ( data => { observer . next ( data ) observer . complete ( ) } ) . catch ( e => { observer . error ( e ) } ) } ) } }

There are already a number of officially supported links which you can simply pull into your application using npm. Here’s a quick overview over a few of them (see here for the full list):

apollo-link-http : Used to send GraphQL operations over HTTP

: Used to send GraphQL operations over HTTP apollo-link-error : Used for custom error reporting (e.g. with Sentry)

: Used for custom error reporting (e.g. with Sentry) apollo-link-dedup : Deduplicated matching requests before sending them

: Deduplicated matching requests before sending them apollo-link-ws : Used to send GraphQL operations over Websockets (often used for subscriptions)

Observables instead of Promises

Another major change in going from 1.x to 2.0 is that Observables are replacing Promises as the core primitive for how data is processed.

The biggest difference between Promises and Observables is that an Observable represents a stream of data (meaning it can receive multiple values over time) while a Promise only represents a single value resulting from an asynchronous operation.

Observables emit events during their lifetime, there generally are three kinds of events:

The next event carries the data the observers are interested in. This event can (but doesn’t have to) be emitted multiple times. For example, if an Observable represents a simple HTTP request, next will be emitted only once. If it represents mouse click events, it can emit any number of events until the Observable terminates.

event carries the data the observers are interested in. This event can (but doesn’t have to) be emitted multiple times. For example, if an Observable represents a simple HTTP request, will be emitted only once. If it represents mouse click events, it can emit any number of events until the Observable terminates. The error event indicates that an error occurred and terminates the Observable. Observers will receive some information that describes the error attached to the event.

event indicates that an error occurred and terminates the Observable. Observers will receive some information that describes the error attached to the event. The completed event simply terminates the Observable and doesn’t carry any data.

This example from Evans Hauser’s article makes the role of these events clear:

class CatchLink extends ApolloLink { request ( operation , forward ) { const observable = forward ( operation ) return new Observable ( observer => { const subscription = observable . subscribe ( { next : observer . next . bind ( observer ) , error : error => { observer . next ( { data : { error , } , } ) } , complete : observer . complete . bind ( observer ) , } ) return ( ) => { subscription . unsubscribe ( ) } } ) } }

The CatchLink intercepts any errors that are received from the API and places them in the data field of the GraphQL response, thus treating them as regular response data which are not terminating the Observable. In the case of next and completed events it simply forwards these to the observers.

The introduction of Observables opens the door to use links for implementing not only regular queries and mutations that follow the classic “request-response-cycle”, but also for subscriptions or live queries which continuously receive data from the server.

New npm package structure

If you have used react-apollo before, you most likely know that it was the only dependency you had to install in your application to import anything you’d need from Apollo Client (except for subscriptions). A typical setup with react-apollo looked as follows:

import { ApolloProvider , createNetworkInterface , ApolloClient } from 'react-apollo' const networkInterface = createNetworkInterface ( { uri } ) const client = new ApolloClient ( { networkInterface } ) export default ( < ApolloProvider client = { client } > < App / > < / ApolloProvider > )

Since one major theme of Apollo Client 2.0 is modularity, you now have to import your functionality from multiple individual packages:

import { ApolloProvider } from 'react-apollo' import { ApolloClient } from 'apollo-client' import { HttpLink } from 'apollo-link-http' import { InMemoryCache } from 'apollo-cache-inmemory' const client = new ApolloClient ( { link : new HttpLink ( { uri } ) , cache : new InMemoryCache ( ) , } ) export default ( < ApolloProvider client = { client } > < App / > < / ApolloProvider > )

In order to send queries and mutations, you also need to explicitly install the graphql-tag and even graphql libraries.

To offer some convenience when getting started, the Apollo team created the apollo-client-presets package which includes apollo-client , apollo-cache-inmemory and apollo-link-http . Read more about the installation in the README.

What’s next

Apollo Client is a community-driven effort and thanks to the new link concept, it’s possible to write dedicated pieces of functionality and share them with other developers. This enables different cache implementations (so you’re not depending on Redux any more when using Apollo Client), offline support, deferred queries and much more! Exciting times for GraphQL 💚