Apollo authorization with header recipe doesn't work

I'm learning how to make a react app using graphql and apollo.

At first, I was able to make a query that returned the posts from the server:

(in my app.js file)

<Query
    query={gql`
      {
        feed {
          id
          title
        }
      }
    `}
  >
    {({ loading, error, data }) => {
      if (loading) return <p>...loading...</p>;
      if (error) return <p>ERROR ! Try reloading</p>;

      return data.feed.map(feed => (
        <div key={feed.id}>{`Title: ${feed.title}`}</div>
      ));
    }}
  </Query>
);

It worked.

Then, I wanted to make queries and mutations that required authorization. Since the server requires headers I followed this recipe.

(in my index.js file)

import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import ApolloClient from 'apollo-boost';
import { ApolloProvider } from 'react-apollo';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { createHttpLink } from 'apollo-link-http';
import { setContext } from 'apollo-link-context';

import registerServiceWorker from './registerServiceWorker';
import App from './App/App';

const GRAPHQL_API_URI = 'https://shopozor-server.herokuapp.com/';

const httpLink = createHttpLink({
  uri: GRAPHQL_API_URI,
});

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()
});

ReactDOM.render(
  <ApolloProvider client={client}>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </ApolloProvider>,
  document.getElementById('root')
);
registerServiceWorker();

Then my previous query didn't work any more. I received an error payload instead of the posts. And an error message was written in the console:

[Network error]: SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data

After debugging, I could know that the referred index.js file was located in the apollo-boost module, which starts with

"use strict"

Plus I found that the

createHttpLink({
   uri: GRAPHQL_API_URI,
});   

didn't use the link I gave it, but used an empty string instead.

Now i'm out of ideas. Can someone help me solving this problem ?

Thanks

Upvotes: 2

Views: 2324

Answers (2)

A friend of mine figured out the problem. I'm using

import ApolloClient from 'apollo-boost';

instead of

import { ApolloClient } from 'apollo-client';

which are different packages with the same name. I had thought that apollo-boost was just a bundle using apollo-client, but no. If i make this tiny change, it works.

apollo-boost doesn't support all apollo features yet and, even if it gives a working client out of the box, I can't use it for everything. Have a look at this article.

Upvotes: 2

soupette
soupette

Reputation: 1280

You need to create the middleware first. Here is how I got it working

import { ApolloLink } from 'apollo-client-preset';
import { ApolloClient } from 'apollo-client';
import { HttpLink } from 'apollo-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';

const httpLink = new HttpLink({ uri: GRAPHQL_API_URI });

// Middleware to set the headers
const middlewareAuthLink = new ApolloLink((operation, forward) => {
  const token = localStorage.getItem('token');
  const authorizationHeader = token ? `Bearer ${token}` : null
  operation.setContext({
    headers: {
      authorization: authorizationHeader,
    },
  });

  return forward(operation);
 });

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

Upvotes: 0

Related Questions