GraphQL redirect when resolver throws error

11.9k views Asked by At

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!

2

There are 2 answers

0
amann On BEST ANSWER

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.

0
Shivathanu GC On

Another way of handling redirects in graphql resolvers is by setting "status" as 302 (http status code for redirect) and "Location" in the response like below code,

this.Query = {
  downloadFile: (parent, { url }, { res }) => {
    res.status(302);
    res.set('Location', url);

    return;
}