Search code examples
reactjsreduxgraphqlapollo

Apollo GraphQL: Change default Header INSIDE React Child Component


I'm trying to change the default header of my Apollo Graph QL Client INSIDE a react component and I simply cant manage to find anything in the docs. So in my index.js I create and link my client as described and add a JWT Token header. But what if I want to change the headers inside my React Component. For example, I want to replace the Token on reauthenticate.

In Axios you can simply do something with this.

axios.defaults.headers.common['Auth-Token'] = 'foo bar';

How can I do something like that with React Apollo? Here is he important part of my index.js

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

const authLink = setContext((_, { headers }) => {

const token = localStorage.getItem('token');
return {
    headers: {
        ...headers,
        authorization: token ? `Bearer ${token}` : "",
    }
}
});

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

I tried to export the client and then import it to the component create a new Link and changethe old one but this didn't work.

There must be some easier way for this. Any suggestions


Solution

  • createHttpLink accept fetch options, in which you can custom how you want your fetch to behave. A simple implementation could look like this:

    import { ApolloProvider, graphql } from "react-apollo";
    import { ApolloClient } from "apollo-client";
    import { InMemoryCache } from "apollo-cache-inmemory";
    import { ApolloLink } from "apollo-link";
    import { createHttpLink } from "apollo-link-http";
    
    const customFetch = (uri, options) => {
      return fetch(uri, {
        ...options,
        headers: {
          ...options.headers,
          "x-custom-header": "custom value"
        }
      });
    };
    
    const fetchLink = createHttpLink({
      uri: "https://graphql-pokemon.now.sh",
      fetch: customFetch
    });
    
    const client = new ApolloClient({
      link: ApolloLink.from([fetchLink]),
      cache: new InMemoryCache()
    });
    

    As you can see in customFetch, I added x-custom-header with "custom value". This will be applied to all query that uses this client. But, I am also spreading options.headers for the fetch options, so any headers that come will be passed through.

    In our component, we can pass extra headers like this:

    const WrappedPokemon = graphql(PokemonQuery, {
      options: {
        context: { headers: { "x-another-custom-header": "another custom value" } }
      },
      props: ({ data }) => ({
        loading: data.loading,
        pokemon: data.pokemon || {}
      })
    })(Pokemon);
    

    This extra header will only exist for this query only, unlike the one above.

    I have made a simple implementation in codesandbox to help you understand the implementation.

    The result looks like this: The custom headers are getting passed through, yay!