GraphQL redirect when resolver throws error

GraphQL redirect when resolver throws error

I’m using graphql-server-express to build a GraphQL server that consumes a REST API.
I’m in the situation that a REST call could return a 301 or 401 status code when the user isn’t authenticated to access the resource. I’m using a cookie that is set on the client and forwarded to the REST API while resolving the GraphQL query.
Is it possible to send a 301 redirect to the client in response to a call to the GraphQL endpoint when such an error occurs?
I’ve tried something like res.sendStatus(301) … in formatError but this doesn’t work well as graphql-server-express tries to set headers after this.
I’ve also tried to tried to short-circuit the graphqlExpress middleware with something like this:
export default graphqlExpress((req, res) => {
res.sendStatus(301);
return;
});

While the client receives the correct result, the server still prints errors (in this case TypeError: Cannot read property ‘formatError’ of undefined – most likely because the middleware receives empty options).
Is there a good way how to get this to work? Thanks!

Solutions/Answers:

Solution 1:

Here’s how I implemented this.

On the server side:

// Setup
export default class UnauthorizedError extends Error {
  constructor({statusCode = 401, url}) {
    super('Unauthorized request to ' + url);
    this.statusCode = statusCode;
  }
}

// In a resolver
throw new UnauthorizedError({url});

// Setup of the request handler
graphqlExpress(async (req, res) => ({
  schema: ...,
  formatError(error) {
    if (error.originalError instanceof UnauthorizedError) {
      res.status(error.originalError.statusCode);
      res.set('Location', 'http://domain.tld/login');
    } else {
      res.status(500);
    }

    return error;
  },
});

On the client side:

const networkInterface = createNetworkInterface();

networkInterface.useAfter([{
  applyAfterware({response}, next) {
    if ([401, 403].includes(response.status)) {
      document.location = response.headers.get('Location');
    } else {
      next();
    }
  }
}]);

In Apollo Client 2.0, you can probably use apollo-link-error on the client side for this.

Related:  Wrap GraphQL scalar type with a special case resolver

References