Log requests to nodejs express - node.js

I want to log all requests like this:
8:04:20 PM - info: /api/v2 200
8:04:22 PM - info: /api/v2/asdf 200
However, in express, the middleware is called before the request is processed, so I cannot get the real response code. I always get 200. What is the right approach to accomplish this?

You can use morgan to log your requests:
const morgan = require("morgan");
app.use(morgan('dev'));
For more documentation visit morgan. Yo may also be interested in
on-finished package to execute arbitrary code on request completion.

Here you go:
app.use((req, res, next)=> {
console.log('I run on every request!');
next();
})

Have your middleware below your routes and in your routes add a third parameter on the callback like this:
app.get( "/", function( req, res, next ) {
res.send(something);
next();
});
app.use(function(req, res, next) {
console.log('after request is done');
});

Related

express middleware functions invoked twice when request is made from browser

Below is my nodejs code
const express = require('express');
const app = express();
app.use('/', (req, res, next) => {
console.log("In interceptor");
next();
});
app.use('/users', (req, res, next) => {
console.log('In /users middleware');
res.send('<h1>From "/users" handler </h1>');
});
app.use('/', (req, res, next) => {
console.log("Default handler");
res.send('<h1>From default handler</h1>');
});
app.listen(3000);
Console output when a request is made from browser (both chrome and edge)
http://localhost:3000
******************
In interceptor
Default handler
In interceptor
Default handler
******************
http://localhost:3000/users
******************
In interceptor
In /users middleware
In interceptor
Default handler
******************
But when a request is made using curl, I don't see multiple invocations
curl http://localhost:3000
******************
In interceptor
Default handler
******************
curl http://localhost:3000/users
******************
In interceptor
In /users middleware
******************
Can someone explain why middleware functions are invoked multiple times when request is made from browser?
The usual reasons you see multiple requests when a page loads from a browser are one of two things:
The browser automatically requesting the favicon.ico file.
The browser attempting to load some resource from the HTML file (script file, image, CSS file, etc..)
You can see exactly what each request is for by adding:
console.log(req.url);
to your middleware.
Found that it is happening due to /favicon.ico request made by browser. Adding specific handler (shown below) prevented default handler from being called twice
app.use('/favicon.ico', (req, res, next) => {
console.log('favicon handler');
res.sendStatus(200);
});

Node/Express - Otherwise Route and CORS

I'm getting a Node/Express API ready for production however have some questions/advice need help on:
1 - I'm using the npm package cors - did so for development to basically disable CORS, however now that I'm moving to production I only want certain URLS to be able to reach the API.
So to so this what I've seen is:
var corsOptions = {
origin: 'http://www.example.com',
methods: ['GET', 'POST']
};
app.get('*', cors(corsOptions), function(req, res, next) {
res.json({msg: 'This is CORS-enabled for only example.com.'});
});
However (from what I've seen) I'd need to do this for everyone request type e.g.
app.post('*', cors(corsOptions), function(req, res, next) {
res.json({msg: 'This is CORS-enabled for only example.com.'});
});
app.del('*', cors(corsOptions), function(req, res, next) {
res.json({msg: 'This is CORS-enabled for only example.com.'});
});
Is there an easier way to avoid such duplication?
2 - And the second question - I have a long list of API routes e.g.
router.post('/registerUser', function(req, res) {
...
}
Is it possible to place some kind of 'otherwise' line so that if a route doesn't match anything I've defined i can return something specific?
Thanks.
For first put cors as a middleware before your first route.
app.use(cors(corsOptions));
//routes down below
Explanation: Cors will be set for all the routes below for every request. As this middleware will be executed first.
For second put your otherwise or 404 route after your last route.
app.use((req,res,next)=>{
//Your message
res.send('Page Not Found');
});
Explanation: If any route will not be matched then this route will trigger.

Is there any way to monitor every response in Express.js?

I want to create a middleware function in express.js. which can monitor every requests and responses. I created a middleware but it can only monitor the requests, not the responses.
function middlewareFunc (req,res,next) {
console.log(req.body , req.params , req.query);
next();
}
You should know that res in function(req, res, next) is a instance of class http.ServerResponse. So it can be listen on finish event, please see the link: https://nodejs.org/api/stream.html#stream_event_finish
app.use(function (req, res, next) {
function afterResponse() {
res.removeListener('finish', afterRequest);
res.removeListener('close', afterRequest);
// action after response
}
res.on('finish', afterResponse);
res.on('close', afterResponse);
// action before request
// eventually calling `next()`
});
app.use(app.router);
app.use() and middleware can be used for "before" and a combination of the close and finish events can be used for "after."
For that you can write two middlewares
1) Before all request endpoints.
//middleware
function middlewareFunEarlier(req,res,next) {
console.log(req.body , req.params , req.query);
next();
}
app.use(middlewareFunEarlier);
app.get('/', function(req, res, next){
//do something
res.end();
});
2) After all end points. And you must have to use next() in all endpoints
app.get('/', function(req, res, next){
//do something
next();
});
app.use(middlewareFunLater);
//middlware
function middlewareFunLater(req, res, next){
console.log(res);
res.end();
}
It can be work around with existing tools.
Ok, so first of all, the reason you are only seeing the requests is because of how middleware works. Everything gets run once in a certain order, and runs only once. When your middleware gets run it is most likely before the response has been created. In order to get the response you would have to make your code run when your controller goes to render or something like that.
Second of all, it seems like basic logging is all you need.(weather it be with a library or just console logging stuff.)

Express 4: Handle every and all errors

While coding my app, I sometimes had a little mishap when typing my URLs in the browser, and thus sometimes got the error message:
Cannot GET /some/route
Which was true, since the route may was not defined.
But since this app is planned to enter production, I kinda don't want to use this flat message as my "error page".
Looking into the Express 4 docs, they tell me to .use() a middleware with 4 arguments. I did that. But I'd still get this issue...
Turns out that this message comes from the finalhandler module and my bet is, that this middleware comes before my error-catching, 4-argument middleware.
Here is a basic express app that I threw together while trying to find a solution:
var app = require("express")();
app.use("/yo", function(req, res, next){
res.send("Yo!");
});
app.use(function(error, req, res, next){
res.send("An error: "+error);
console.log(error);
});
app.listen(10000);
Accessing /yo works. But, / or /derp yields the Cannot GET message instead of my little middleware.
So, how is this done correctly, now?
The error middleware is only for actual errors, such as a middleware or route handler throwing an exception or passing an error to next().
If you want to provide a route handler for requests that do not match any existing routes, then just add a middleware after all of your app's routes/middleware like:
var app = require("express")();
app.use("/yo", function(req, res, next){
res.send("Yo!");
});
app.use(function(req, res, next) {
res.send('Could not route your request!');
});
app.use(function(error, req, res, next){
res.send("An error: "+error);
console.log(error);
});
app.listen(10000);

Express.js Response Timeout

PROBLEM
I've been looking for request/response timeouts for Express.js but everything seems to be related to the connection rather than the request/response itself.
If a request is taking a long time, it should be timed out. Obviously this shouldn't happen but even a simple mistake as having a route handler without a call to the callback or without res.send(), the browser will keep waiting for a reply forever.
An empty route handler is a perfect example of this.
app.get('/sessions/', function(req, res, callback){});
FIX
I added the following before app.use(app,router); and it seemed to add the timeout functionality. Does anyone have any experience/opinion on this?
app.use(function(req, res, next){
res.setTimeout(120000, function(){
console.log('Request has timed out.');
res.send(408);
});
next();
});
Note that I've set the timeout to 2 minutes.
There is already a Connect Middleware for Timeout support:
var timeout = express.timeout // express v3 and below
var timeout = require('connect-timeout'); //express v4
app.use(timeout(120000));
app.use(haltOnTimedout);
function haltOnTimedout(req, res, next){
if (!req.timedout) next();
}
If you plan on using the Timeout middleware as a top-level middleware like above, the haltOnTimedOut middleware needs to be the last middleware defined in the stack and is used for catching the timeout event. Thanks #Aichholzer for the update.
Side Note:
Keep in mind that if you roll your own timeout middleware, 4xx status codes are for client errors and 5xx are for server errors. 408s are reserved for when:
The client did not produce a request within the time that the server was prepared to wait. The client MAY repeat the request without modifications at any later time.
You don't need other npm modules to do this
var server = app.listen();
server.setTimeout(500000);
inspired by https://github.com/expressjs/express/issues/3330
or
app.use(function(req, res, next){
req.setTimeout(500000, function(){
// call back function is called when request timed out.
});
next();
});
An update if one is using Express 4.2 then the timeout middleware has been removed so need to manually add it with
npm install connect-timeout
and in the code it has to be (Edited as per comment, how to include it in the code)
var timeout = require('connect-timeout');
app.use(timeout('100s'));
In case you would like to use timeout middleware and exclude a specific route:
var timeout = require('connect-timeout');
app.use(timeout('5s')); //set 5s timeout for all requests
app.use('/my_route', function(req, res, next) {
req.clearTimeout(); // clear request timeout
req.setTimeout(20000); //set a 20s timeout for this request
next();
}).get('/my_route', function(req, res) {
//do something that takes a long time
});
If you need to test your api, this solotion can you help.
I used this in middleware to test my frontend.
For exmaple: if you need to test loader in frontend.
const router = require('express').Router();
const { data } = require('./data');
router.get('/api/data', (req, res, next) => {
setTimeout(() => {
res.set('Content-Type', 'application/json')
res.status(200).send(data)
next()
}, 2000)
})
module.exports = router;
request.setTimeout(< time in milliseconds >) does the job
https://nodejs.org/api/http.html#http_request_settimeout_timeout_callback
You can try:
return await new Promise((resolve) =>
setTimeout(() => {
resolve(resp);
}, 3000),
);
In above code, 3000 = 3 sec.
Change it according to your requirement.
I have not tried for very long scenarios though. Let me know the results in comments.
Before you set your routes, add the code:
app.all('*', function(req, res, next) {
setTimeout(function() {
next();
}, 120000); // 120 seconds
});

Resources