5
votes

I would like to read a response header with Apollo Client and I cannot.

I'm using Apollo server and Apollo client for GraphQL API communication, and I would like to send headers back and forth. I've set up the client so that it sends a x-client-version header, and I have set up the server to sometimes also reply with that same header.

The issue is that when I try to read the x-client-version header (or any header really) with Apollo client, I get undefined. I have set up some Afterware below based on examples I found online and even YouTube walkthroughs:

const clientVersionAfterware = new ApolloLink((operation, forward) =>
  forward(operation).map(response => {
    const {
      response: { headers },
    } = operation.getContext();
    console.log(headers);
    if (headers) {
      const token = headers.get("x-client-version");
      console.log(token);
      if (token) {
        localStorage.setItem("clientVersion", token);
      }
    }

    return response;
  }),
);

Attach it to the link chain:

    const httpLink = handleErrors.concat(
  clientVersionAfterware.concat(new HttpLink(linkOptions)),
);
const batchHttpLink = handleErrors.concat(
  clientVersionAfterware.concat(
    new BatchHttpLink({ ...linkOptions, batchInterval: 10 }),
  ),
);

Ultimately wiring up the links in the ApolloClient constructor:

new ApolloClient({
    link: split(
      ({ operationName = "" }) => operationName.startsWith("findOrCreate"),
      httpLink,
      batchHttpLink,
    ),
    cache,
    ...opts,
  });

I've heard that the headers object is blank but that the headers can still be read, but that's definitely not true in my experience. I can see that the server is indeed returning the x-client-version header that I expect to read:

Chrome Response Headers

I thought that maybe upgrading my packages would help, but they did not. The versions I'm using:

"apollo-cache-inmemory": "^1.5.1",
"apollo-client": "^2.5.1",
"apollo-link-batch-http": "^1.2.4",
"apollo-link-error": "^1.1.2",
"apollo-link-http": "^1.5.11",

Is there something I'm missing? Thanks in advance!

2

2 Answers

1
votes

I figured it out.

Turns out updating apollo-client is not enough. I upgraded the following packages and now the headers object is populated:

"apollo-link-batch-http": "^1.2.9",
"apollo-link-error": "^1.1.8",
"apollo-link-http": "^1.5.12",

I'm sure you don't need to update apollo-link-error, but the other two should suffice (especially apollo-link-http).

1
votes

I was missing Access-Control-Expose-Headers on the /graphql endpoint:

  app.use((req, res, next) => {
    res.append("x-version-backend", `${BUILD_VERSION}`);
    res.append("Access-Control-Expose-Headers", "x-version-backend");
    next();
  });

After that I could see my headers:

const responseLogger = new ApolloLink((operation, forward) => {
    return forward(operation).map(result => {
      const headers = operation.getContext().response.headers;
      const backendVersion = headers.get("x-version-backend");
      console.info(`x-version-backend:${backendVersion}`);
      return result;
    });
  });