Express-graphql: How can we use middlewares after graphqlHTTP?

Created on 18 Apr 2017  路  5Comments  路  Source: graphql/express-graphql

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?

Most helpful comment

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();
    }
);

All 5 comments

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;
  }
})

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dmytro-kerest picture dmytro-kerest  路  3Comments

jamesmoriarty picture jamesmoriarty  路  4Comments

KieronWiltshire picture KieronWiltshire  路  3Comments

phuchle2 picture phuchle2  路  3Comments

arealmaas picture arealmaas  路  4Comments