Apollo Link response headers
Asked Answered
B

2

18

I am using the latest version of Apollo Client in a simple React app and I am trying to pull out a header value from the response that is being used to show the size of the record set being returned.

I appreciate that this is not the most elegant way of providing the result set size, but that is how the API has currently been set up.

I was hoping to use the the middleware type options to do this, but when I inspect the response object I can't seem to pull out any headers.

The network trace does show that the response header is as expected so I suspect I am misunderstanding how to get at the underlying objects that I need.

I have checked the documentation, but nothing stands out as obvious hence the question here ...

Barbed answered 22/11, 2017 at 21:4 Comment(0)
B
32

When the backend responds, the headers should include:

Access-Control-Expose-Headers: * // or the name of your refreshToken field

Here you have the full code:

Front-end: (Apollo & React)

const httpLink = new HttpLink({ uri: URL_SERVER_GRAPHQL })

// Setup the header for the request
const middlewareAuthLink = new ApolloLink((operation, forward) => {
  const token = localStorage.getItem(AUTH_TOKEN)

  const authorizationHeader = token ? `Bearer ${token}` : null
  operation.setContext({
    headers: {
      authorization: authorizationHeader
    }
  })
  return forward(operation)
})
// After the backend responds, we take the refreshToken from headers if it exists, and save it in the cookie.
const afterwareLink = new ApolloLink((operation, forward) => {
  return forward(operation).map(response => {
    const context = operation.getContext()
    const { response: { headers } } = context

    if (headers) {
      const refreshToken = headers.get('refreshToken')
      if (refreshToken) {
        localStorage.setItem(AUTH_TOKEN, refreshToken)
      }
    }

    return response
  })
})

const client = new ApolloClient({
  link: from([middlewareAuthLink, afterwareLink, httpLink]),
  cache: new InMemoryCache()
})

In the backend (express). If we need to refresh the token (e.g: because the actual one is going to expire)

const refreshToken = getNewToken()
res.set({
  'Access-Control-Expose-Headers': 'refreshToken', // The frontEnd can read refreshToken
  refreshToken
})

Documentation from: https://www.apollographql.com/docs/react/networking/network-layer/#afterware

Bereft answered 22/11, 2019 at 2:13 Comment(2)
I wonder if there is a way to take the header and put it in the response. Maybe in some kind of wrapper object?Sorry
nice. thank you. finally i found the root of all evilSparkman
B
22

Found the answer here: https://github.com/apollographql/apollo-client/issues/2514

Have to access it via the operation context ... interestingly the dev tools appears to show that the headers object is empty, but you can then pull named headers from it ...

const afterwareLink = new ApolloLink((operation, forward) => {
  return forward(operation).map(response => {
    const context = operation.getContext();
    const { response: { headers } } = context;
    
    if (headers) {
      const yourHeader = headers.get('yourHeader');
    }
    
    return response;
  });
});
Barbed answered 24/11, 2017 at 20:56 Comment(5)
I am using the same code, and I still receive null: github.com/apollographql/apollo-client/issues/… any idea what could be wrong?Bereft
Does anybody know why the dev tool shows the headers object is empty??Shambles
@Shambles yes, header are lazy loaded i.e. they are loaded only the first time you access them. Try calling headers.lazyInit(); and they will magically appearDibucaine
If using CORS, you'll need to add your headers to Access-Control-Expose-Headers returned by your server: github.com/apollographql/apollo-client/issues/… Otherwise you just get things like content length and type.Spoliate
This DID NOT WORK for me. I had to forward(operation).subscribe({complete: () => { console.info(operation.getContext().response.headers); })Twoup

© 2022 - 2024 — McMap. All rights reserved.