9

My app is wrapped with <Apollo /> component that essentially initialises the client.

const client = new ApolloClient({
  link: new HttpLink({
    // ...
  }),
  cache: new InMemoryCache({
    // ..
  }),
});

Further down the road users can make certain action that requires me to set few new headers to apollo client that were not there before. I initially thought to use react context for this to pass set new headers and consume them inside <Apollo /> but am not sure if this is the right way to go about it.

After looking through the docs, it seems that apollo headers can be only set when it is initialised?

Ilja
  • 44,142
  • 92
  • 275
  • 498

3 Answers3

10

Rather than passing the headers directly to your Apollo client instance, you normally want to utilize apollo-link-context. You can store the actual header values in memory, LocalStorage or whatever makes sense for your app. Then use the link to inject them into each request before it's sent:

const headerLink = setContext((request, previousContext) => ({
  headers: {
    // Make sure you include any existing headers!
    ...previousContext.headers,
    authorization: localStorage.getItem('authHeader')
  },
}));

const client = new ApolloClient({
  link: headerLink.concat(httpLink),
  cache: new InMemoryCache()
});

setContext can be asynchronous. The function you pass it should return either an object with whatever context fields you want to change, or a Promise that will resolve to one:

const headerLink = setContext(async (request, previousContext) => {
  const authorization = await someAsyncCall()
  return {
    headers: {
      ...previousContext.headers,
      authorization,
    },
  }
});

You can check out the docs for additional examples.

Daniel Rearden
  • 80,636
  • 11
  • 185
  • 183
  • 4
    But how do you update it after the fact? For example, an initial GraphQL request to log in, doesn't have an Authorization header. Once you have logged in, how do you then update the ApolloClient instance? Do you replace it with a fresh new ApolloClient? – DeltaTango Jan 20 '21 at 22:04
  • This ```const authorization = await someAsyncCall()``` is called each time the request is called, for each query or mutation – Raphael Sep 05 '22 at 14:19
2

To expand on Daniel Rearden's answer, if you want to add headers just for a specific query/mutation and not all of the subsequent queries:

Initialise Apollo:

const httpLink = createHttpLink({
  uri: '/graphql',
});

const authLink = setContext((_, { headers }) => {
  // get the authentication token from local storage if it exists
  const token = localStorage.getItem('token');
  // return the headers to the context so httpLink can read them
  return {
    headers: {
      ...headers,
      authorization: token ? `Bearer ${token}` : "",
    }
  }
});

const client = new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache()
});

And then simply add the context to the desired query/mutation itself:

const {loading, data, error} = useQuery(QUERY_DEF, { 
    context:  {
        headers: {
            "HeaderKey": "HeaderValue"
        }
    }
});
Syed Waqas
  • 2,576
  • 4
  • 29
  • 36
0

Daniel Rearden is right. However, with Apollo 3 there're some minor changes that I've found not well systematized in the docs yet. So maybe it will help as well.

import React from 'react';
import { ApolloClient, InMemoryCache, HttpLink } from '@apollo/client';
import { setContext } from '@apollo/client/link/context';

function App() {

  const link = new HttpLink({ uri: process.env.REACT_APP_GRAPHQL_URI });

  const setAuthorizationLink = setContext((request, previousContext) => ({
    headers: {
      ...previousContext.headers,
      authorization: `Bearer ${ localStorage.getItem('auth_token') }`
    }
  }));

  const client = new ApolloClient({
    link: setAuthorizationLink.concat(link),
    cache: new InMemoryCache()
  });

  return (
    <ApolloProvider client={client}>
      ...
    </ApolloProvider>
  );
}

export default App;

Migrating to Apollo Client 3.0 (docs)

sketchnotes
  • 131
  • 1
  • 1
  • 9
  • 3
    What about the example of a log in? First GraphQL request, there is no Authorization header. How do you set it after the response comes back? How do you update headers during your app, later, down the chain? – DeltaTango Jan 20 '21 at 22:05