1

I've got a react app using Apollo to retrieve data from a graphql endpoint.

I have an error link method set up to show different messages if an http error is returned from the GQL, which works fine for 4xx errors. However, if the server fails with a 5xx error, I get a generic "failed to fetch" error message in my method, but I don't get an error code.

The 503 error usually indicates that we're in maintenance mode, so I want to be able to show a different message if we get a 503, vs any other 5xx error. Is there a way I can adjust my error handling to get the code for 5xx errors? I can't see anything obvious in the errorResponse being passed to the method.

Here's a truncated version of my onError link:

  const errorLink = onError((errorResponse) => {
    const { graphQLErrors, networkError, operation } = errorResponse;

    // Doesn't work - networkError is null.
    if ((
      networkError?.statusCode === 503
    ) && !window.location.pathname.includes('maintenance-mode')
    ) {
      // [show maintenance mode page]
    }

    // This works.
    if (networkError?.statusCode === 401 && operation?.operationName !== 'auth') {
      // [redirect to login page]
    }

    // [...etc]
  });
Heather Gaye
  • 1,118
  • 1
  • 11
  • 19

1 Answers1

0

One way to directly access the HTTP status codes in Apollo Client is by extending the standard HttpLink with a custom link that exposes the response object. This way, you can access the status code directly from the response.

Here's code manually written caught from my previous similar project.

import { ApolloLink } from '@apollo/client';
import { onError } from '@apollo/client/link/error';
import { createHttpLink } from '@apollo/client/link/http';

// Create a custom link that exposes the response object.
const customFetch = (uri, options) => {
  return fetch(uri, options).then(response => {
    // The status and statusText attributes are added to the response body here.
    return response.text().then(body => {
      return new Response(JSON.stringify({
        data: JSON.parse(body),
        status: response.status,
        statusText: response.statusText,
      }), {
        status: response.status,
        statusText: response.statusText,
      });
    });
  });
};

// Create HttpLink with custom fetch method
const httpLink = createHttpLink({
  uri: 'http://your-graphql-endpoint',
  fetch: customFetch,
});

const errorLink = onError(({ graphQLErrors, networkError }) => {
  if (networkError) {
    const { status } = JSON.parse(networkError.bodyText);

    if (status === 503) {
      // [show maintenance mode page]
    }
  }

  if (networkError?.statusCode === 401) {
    // [redirect to login page]
  }

  // [...etc]
});

// Combine your errorLink and httpLink
const link = ApolloLink.from([errorLink, httpLink]);

// Create your Apollo Client with the combined link
const client = new ApolloClient({
  link,
  cache: new InMemoryCache(),
});

In this example, I create a custom fetch function that is used by Apollo's HttpLink. The fetch function adds the status code and status text to the body of the response object. This allows you to access the status code directly from the networkError in your onError function.

Hope my answer would give you a hint.

Louis
  • 532
  • 1
  • 2
  • 11
  • Hey, thanks for responding. I updated my existing httpLink as you recommended, but on a 500 error, the 'fetch' inside the customFetch errors out without getting as far as the '.then'. If I add a .catch, the response is just my text error saying "failed to fetch at customFetch [...]". – Heather Gaye Aug 01 '23 at 06:54