Is there anyway to use a middleware after graphqlHTTP middleware? As a use case, suppose we want to use response.redirect() after using graphqlHTTP middleware. How can we do that?
Hey there,
I have a similar question. In my case I'm trying to wrap the sequelize-graphql generated db calls in a transaction. I'd like to do so in order to set a user id variable in the DB (for DB level sharing/access control). Here's what I've got so far:
app.use(
"/graphql",
function (req,res) {
return sequelize.transaction().then(function (t) {
sequelize.query("SELECT set_config('tg.lims_user', '" + userId + "',true);", {raw: true});
var graphqlFunc = graphqlHTTP({
schema: schema,
graphiql: true,
})
return graphqlFunc(req,res)
.then(function () {
return t.commit();
}).catch(function (err) {
return t.rollback();
})
})
}
);
This will rollback the transaction if graphql throws an error, but, should the commit fail, the graphql response will have already been returned to the client. It seems like we need to buffer the response and not send it until the transaction commits. Not sure how we can do this with express-graphql. Is there any way to pass a "next" into the graphqlHTTP generated function?
Any help would be appreciated!
Thanks!
const { PassThrough } = require('stream');
function graphqlMiddlewareWrapper(graphqlMiddleware) {
return (req, res, next) => {
const resProxy = new PassThrough();
resProxy.headers = new Map();
resProxy.statusCode = 200;
resProxy.setHeader = (name, value) => {
resProxy.headers.set(name, value);
};
res.graphqlResponse = (cb) => {
res.statusCode = resProxy.statusCode;
resProxy.headers.forEach((value, name) => {
res.setHeader(name, value);
});
resProxy.pipe(res).on('finish', cb);
};
graphqlMiddleware(req, resProxy).then(() => next(), next);
};
}
Usage
app.use('/graphql',
graphqlMiddlewareWrapper(graphqlHttp({
schema,
graphiql: true,
})),
(req, res, next) => {
console.log('SUCCESS');
if (something) {
// res.redirect(), etc
res.status(200).end('something');
} else {
// pass through graphql response
res.graphqlResponse(next);
}
},
(err, req, res, next) => {
console.log('CATCH ERROR');
res.status(500).end(err.message);
next();
}
);
Thanks for the suggestion @amokrushin, and @mkermani144 for the question. This looks like a reasonable solution to me. I'm going to close this for now. If anybody has any further questions about this, I think Stack Overflow would be a good forum for it; feel free to post a link back here if you want to leave a bread-crumb trail for people to follow who might stumble onto this issue.
i am using extensions function for this purpose, it gets call after gql https://github.com/graphql/express-graphql#providing-extensions
Just FYI for anyone using apollo-server-express you can do this:
graphqlExpress({
schema,
formatResponse(response) {
// do something with response
return response;
},
formatError(err) {
// same
return err;
}
})
Most helpful comment
Usage