Get response status code in a middleware
Asked Answered
S

4

11

I am building an app in which I am trying to build my own logging system for each request.

For each request, I'd like to log the timestamp, the method used, the route, and finally the response code that has been sent to the client.

I have the following code for the moment :

// index.js
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');

const app = express();
app.use(bodyParser.json());
app.use(cors());

app.use(require('./lib/logging'));

app.get('/', (req, res, next) => {
  res.send('hello world !');
});

app.listen(3001);

// ./lib/logging.js
const moment = require('moment');
const chalk = require('chalk');
const log = console.log;

module.exports = (req, res, next) => {
  let now = `[${chalk.green(moment().format('HH:mm:ss'))}]`;
  let method = chalk.magenta(req.method);
  let route = chalk.blue(req.url);
  let code = chalk.yellow(res.statusCode); // Always 200
  log(`${now} ${method} request received on ${route} ${code}`);
  next();
}

Unfortunately, even if I do res.status(201).send('hello world') It will always catch a 200 status code... Is there a way to catch any response outgoing to the client and fetch its status code ?

Strapped answered 27/6, 2018 at 9:1 Comment(7)
Where is middleware calling?Scarbrough
In the index, before declaring the route `'/'. I tried putting the middleware after the routes but I don't think this is the solutionStrapped
Your middlewares won't execute after you do res.send. Use the solution from the following question - #20176306Krause
Kinda off-topic, but I just realized how clumsy this is with express, and how easy with Koa. Anyway, I think for this use-case you might simply need to hook into the finish event instead of using middleware.Fling
I still can't get status code even with the res.on('finish', () => {console.log(res) /* undefined */})Strapped
you can create middleware and override send function.Scarbrough
@NeilRichter i don't see where res is coming from in your event handler.Fling
S
22

Using the finish event from the response was indeed the good solution. The problem was in the finish event callback, I just couldn't use the arrow function because it wouldn't bind the this keyword, and this is were was stored the response data.

So the following code is working :

// ./lib/logging.js

const moment = require('moment');
const chalk = require('chalk');
const log = console.log;

module.exports = (req, res, next) => {
  let now = `[${chalk.green(moment().format('HH:mm:ss'))}]`;
  let method = chalk.magenta(req.method);
  let route = chalk.blue(req.url);
  res.on('finish', function() {
    let code = chalk.yellow(this.statusCode);
    log(`${now} ${method} request received on ${route} with code ${code}`);
  })

  next();
}
Strapped answered 27/6, 2018 at 10:3 Comment(0)
M
10

The Express response extends the Node.js http.ServerResponse, so you can listen for the 'finish' event:

Event: 'finish'

Emitted when the response has been sent. More specifically, this event is emitted when the last segment of the response headers and body have been handed off to the operating system for transmission over the network. It does not imply that the client has received anything yet.

app.use((req, res, next) => {
  res.on('finish', () => {
    console.log(`Responded with status ${res.statusCode}`);
  });
  next();
});
Moxa answered 30/11, 2020 at 15:19 Comment(0)
S
2

Create middleware and Override send function

app.use(function (req, res) {
    var send = res.send;
    res.send = function (body) {
        // Do something
        send.call(this, body);
    };
});
Scarbrough answered 27/6, 2018 at 9:57 Comment(0)
S
0

What I understand is you need to add some status codes in the response

You can simply set status codes like this

let code = {
   serverError:500,
   forbidden:401
}

res.status(code.serverError).json({
  message:'Server error'
})

If you want to set in the middleware

middleware.js

const statuscode = function middleware(req,res,next){


    let code = {
       serverError:500,
       forbidden:401
    }

    req.statusCode =code.serverError
   next()

}

module.exports = {
  statuscode
}

In the index.js

const middleware = require('./middleware');

app.get('/',middleware.statuscode, (req, res, next) => {
  console.log("Code from middleware",req.statusCode);
  res.send('hello world !');
});
Scalage answered 27/6, 2018 at 9:20 Comment(2)
By doing this, it means I have to put the middleware.statuscode in each route, which I don't want. I can catch every requests, can't I catch every responses ?Strapped
Put the status codes in config file and use it where you needScalage

© 2022 - 2024 — McMap. All rights reserved.