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!
GraphQL Redirect is a simple module extending contributed GraphQL module. It replaces default route handling so that GraphQL query follows redirects created by Redirect module and returns query result for the destination route. It supports internationalization and chained redirects.
To add errors to your data, you need to use the Union type (a.k.a. Result ) in your GraphQL schema. Also, the logic in the resolver is rewritten so that next to the result or error for the operation you also need to return a type for it.
If the response includes GraphQL errors, they are returned on error. graphQLErrors and the response data is set to undefined even if the server returns data in its response. This means network errors and GraphQL errors result in a similar response shape. This is the default error policy.
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.
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With