Working with Apollo Client and GraphQL Live Queries

Working with Apollo Client and GraphQL Live Queries

Apollo Client is great for executing GraphQL operations and managing local state. But when data changes on the server (by other users), there's no way to know that happened without refetching the query.

Polling often bloats the network, and overfetches data you already know about. Instead you can use GraphQL Live Queries to keep the client updated.

In this guide we will use the @grafbase/apollo-link library to switch connection types depending on the type of query invoked.

npm install @apollo/client graphql @grafbase/apollo-link

We'll begin by creating a utility to create and return the ApolloClient instance:

import { ApolloClient, ApolloLink, InMemoryCache } from '@apollo/client'

const initializeApolloClient = (link: ApolloLink) => {
  return new ApolloClient({
    cache: new InMemoryCache(),
    link: link
  })
}

Next define a createApolloLink function that returns the correct HTTPLink based on if the request is a @live query or not.

You can do this using the helper isLiveQuery from @grafbase/apollo-link which you can pass to split from @apollo/client to switch between the custom links.

import { HttpLink, split } from '@apollo/client'
import { SSELink, isLiveQuery } from '@grafbase/apollo-link'
import { getOperationAST } from 'graphql'

const token = '...'

export const createApolloLink = () => {
  const sseLink = new SSELink({
    uri: process.env.GRAFBASE_API_URL,
    headers: {
      authorization: `Bearer ${token}`
    }
  })

  const httpLink = new HttpLink({
    uri: process.env.GRAFBASE_API_URL,
    headers: {
      authorization: `Bearer ${token}`
    }
  })

  return split(
    ({ query, operationName, variables }) =>
      isLiveQuery(getOperationAST(query, operationName), variables),
    sseLink,
    httpLink
  )
}

Note: It's here you will also use an auth provider to set the token value.

Here we wrap the <App /> with ApolloProvider passing in the custom client:

import React from 'react'
import { ApolloProvider } from '@apollo/client'
import ReactDOM from 'react-dom/client'

import { initializeApolloClient } from './client'

const client = initializeApolloClient(createApolloLink())

const App = () => {
  return (
    // ...
  )
}

ReactDOM.createRoot(document.getElementById('root')).render(
  <ApolloProvider client={client}>
    <App />
  </ApolloProvider>
)

You can now use the @live directive with any query and Apollo Client will automatically listen for changes using server-sent events.

query @live {
  messageCollection(first: 5) {
    edges {
      node {
        id
        body
      }
    }
  }
}

That's it! Apollo Client will now automatically switch between the HttpLink and SSELink where required.