Nodejs Express how to write middleware to handle all response - node.js

In node JS Express, we can write middlewares to intercept requests to either
Call the next middleware in the chain by invoking next
End the chain by calling res.send or similar functions provided by res
That means, everytime we want to end a request and send a response in a particular middleware, we have to add (at least) the below snippet.
res.send();
Are there ways to write a response frame middleware like this:
responseFrame = (res,req,responseData) => {
res.send(responseData);
}
and insinde route.js, use this middleware on all path
app.use(responseFrame);
Then, we simply have to end any middleware with next(), as long as we define the correct routes, Express will take care of sending the response (if the next middleware is the responseFrame)

You can use res.locals for that.
https://expressjs.com/en/api.html#res.locals

Related

Behavior of expressjs next middleware when the response has gone

I am using express (v:4.17.1) and here is my code snippet:
//upload.array is for multer npm file uplaoding....
//LIMIT is how many files you can upload via multer ....
app.post('/processFiles', upload.array('myFile', LIMIT), (req, res, next) => {
if (!validEnv) {
res.setHeader('X-Correlation-ID', corrId);
res.status(400).json({'error':'invalid env'});
return next(); //A
}
//checking how many file hvae been uplaoded
if (totalFiles > LIMIT) {
res.status(400).json({'error':'Too many files uploaded'});
return next(); //B
}
//Some xml parsing code and later it inserts into db
}
Few questions on the way I have added 'return next();' in the routes. Please note that I have not added any explicit middleware, just relying on what express is providing:
If I keep [A] or [B] as it is, then it gives a proper error message to the browser if the conditions get TRUE and returns the response.
But if I comment the line //A or //B, it gives the error response back to browser but also prints few error logs as mentioned below:
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
I don't know why the above line is appearing when I comment the //A or //B (but wont complain if I keep as it is without commenting them) as the response was already out to the browser and the express will not execute any piece of code after the response has gone.
Please correct my understanding ?
Also, Is this the correct way to handle errors as I have coded? If No, what could be the proper way, please advice? Is there any way by which we can see the complete middleware execution in sequence until the last one via any debug flags
There are a several ExpressJS things to know that apply here:
next() tells Express to continue routing to other requests. Only call next() if you want other routes to continue to be able to process this request and send a response. Or the corallary, don't call next() if you've already sent a response.
You can only send one response for a given request. Once, you've called res.send() or .res.json() or any other way of sending a response, you should be completely done with your request processing and no other code should try to send a response.
res.send() and next() are not Javascript flow control. If you want to stop further processing of the request in your function, you need to code that with traditional Javascript flow control such as return, if/else, etc... to prevent the rest of your code from continuing to run or process the request.
To that end, your code should look like this:
//upload.array is for multer npm file uplaoding....
//LIMIT is how many files you can upload via multer ....
app.post('/processFiles', upload.array('myFile', LIMIT), (req, res, next) => {
if (!validEnv) {
res.setHeader('X-Correlation-ID', corrId);
res.status(400).json({'error':'invalid env'});
return;
}
//checking how many file hvae been uplaoded
if (totalFiles > LIMIT) {
res.status(400).json({'error':'Too many files uploaded'});
return;
}
// more code here that sends some other response
}
But if I comment the line //A or //B, it gives the error response back to browser but also prints few error logs as mentioned below: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
This error occurs when you attempt to send more than one response for the same request (e.g. call res.send(...) more than once. Your code should not allow that. Once you send a response, your code should use normal Javascript flow control (such as return or if/else) to avoid executing any more code that might send a response. Typically after you send a response, you are done processing the request and would just return from the request handler.
This is happening because of the //A. See, what is going on here in your code :
If you comment line //B it reaches the next if (totalFiles > LIMIT) which is sending another response but above the return next() is called. That is why it is generating error that once they are sent in if(!validEnv) how can Headers be sent again!
You have two if conditions that mean both might get executed, in both the conditions you are setting the headers and ending the request. Once the request is ended the headers cannot be set. So if you comment [A] which has the return statement and if the second condition is also satisfied, it will set the headers again after sending the request. so it has nothing to do with the next() function or express since there is no next middleware in the stack.
Also the error handling is looks fine. however you can use the node --inspect flag while starting the script and set breakpoint in your middleware to debug entire node code.

asynchronic calls in node.js

I have a basic misunderstanding regarding asynchronic calls using express and middlewares and i would really appreciate some help understanding it.
Suppose we have this code:
var express = require('express')
var cookieParser = require('cookie-parser')
var app = require('express')
var router = express.Router()
app.use(function timeLog (req, res, next) {
req.requestTime = Date.now()
next()
})
app .use(express.json());
app .use(express.urlencoded());
app.use(cookieParser())
router.post('/hello', function (req, res) {
//write async to file
res.send('bye')
})
Now, when the client calls this endpoint "hello":
are the middlewares which defined in App-level called asynchronicaly? I understood that they do(because they are called "Callbacks" in the documentation... so basically before reaching the router: parsing cookies, parsing json to req.body and adding req.requestTime will run asynchronicaly and then will be routed to '/hello' end point.
after routing, is the callback will run asynchronicaly? if yes, then how in this case the request is not left hanging? i see that the response is being terminated inside a body of a callback... how this make any sense? :(
would somebody please explain to me this flow?
I will try to explain how I understood "async calls" through this code above: lets say alot of users trying to get this end point. all these calls added to the call stack, then because of these callbacks are async, then they are moved to event Queue/table and will be handled after the call stack will be "empty". if this is the case, how the first user will ever get a response? the requestTime done async, parsing the json done async and when reaching the router, the callback is done async.... so when the first user will ever get a repsone if all these async calls located inside the event Queue/table and they will be handled only after the callstack is empty? what am i missing here?
Thanks.
The middleware doesn't appear to be asynchronous of its own. In other words, as you said in your comment on another answer, it is not forcing each layer in the expressjs "stack" of middleware/handlers into a separate frame in the JavaScript event queue.
If you trace the next() function in a .use(), there are a couple of setImmediates fairly early on to handle "exit router" or "no more layers," but then you get into a while loop on a stack of handlers. This is happening at around this point in the code.
So if all your middleware was similar to this section, all middleware etc would happen in the same frame within the event queue:
app.use(function(req, res, next){
console.log('synchronous layer');
next();
});
Whereas a step like this next one would put the next into a separate frame in the event queue, and potentially allow the process to handle other frames that may be queued up.
app.use(function(req, res, next){
setImmediate(()=> {
console.log('setImmediate puts this next() into a separate frame in the event queue');
next();
});
});
I can't imagine this would normally be a problem. Most things that would happen in middleware that might take some time (a database call etc) are very likely all going to be happening asynchronously (in a way that puts the next into a new frame in the event queue). But it is something worth considering when you're adding middleware...
All those middleware are using the continuation passing style. So basically they COULD run asynchonous. But they don't have to. It depends on, whether those middlewares are doing some IO. You could take a look into the code to check how the functions behave exactly, but at least, this does not matter. Just keep in mind, that they COULD run asynchronous.

Node How to use routes in parallel function

i am trying to make node render more faster.
then i want use parallel.
so how to put in routes in parallel function?
before
var app = express();
var index = require('./routes/index')();
var auth = require('./routes/auth')();
app.use('/',index);
app.use('/auth/',auth);
after ( I am trying this)
var app = express();
var index = require('./routes/index')();
var auth = require('./routes/auth')();
function parallel(middlewares){
return function (req, res, next){
async.each(middlewares,function(mw,cb){
mw(req,res,cb);
},next);
};
};
app.use(parallel([
['/',index],
['/auth/',auth],
[others here]
]));
I found a way to do this. It comes with a few caveats which are mostly due to the fact that Express is designed around sequential middleware, but by following a set of guidelines you can make it work just fine.
The Problem Statement
We want to pass in a group of middleware and have them run in parallel (or as parallel as their async operations will allow). If you have multiple independent async things to do in middleware, this should be able to get to an end result quicker (which is pretty much the whole point of doing this).
We want to be able to pass in typical routing paths (with all wildcards and special characters) as in app.use('/product/:id', fn) and then execute only the routes that match the current request "in parallel" with each other
We want Express itself to do all the route matching so we don't have to reimplement or copy any of that and so that everything Express normally supports for route matching is supported.
We want to support route parameters like req.params, even though those may be different for each middleware (not quite so common to use this in middleware, but still part of the Express design).
The Design Scheme
We create our own Router object. To that router object, we add a "start" marker middleware at the beginning (so we can see when routes are starting on this router), then we add a place holder middleware with the proper path for each of our parallel middleware handlers and then we add another "end" marker middleware at the end (so we can see when routes are done on this router). The "start" and "end" routes match all routes so they are always called. The other routes have the path that was passed in for them so they may or may not get called for any given request depending upon whether they match the current path or not.
This router gets added to the routing stack with app.use(router). In this way, the regular Express engine will do all the routing for this router and decide which routes match the current request path. But, rather than execute the regualar middleware functions when it finds a matching route path, it will just execute our placeholder middleware. When it executes the placeholder middleware, we will get to see the "start" middleware, any other middleware that matches the route which we will capture in a list and then the "end" middleware. When we get the "end" middleware, we will have captured the list of middlewares that match the current route and we can then go execute just those actual middlewares in parallel. When all those middlewares are done, we then call next() for our router allowing the rest of routing to continue.
So, in summary, we insert dummy route handlers with the actual route paths and let Express call our dummy route handlers if the path matches as a means of telling us which routes match the current path. Then, we take that list of matching routes and set them up for parallel execution. In this way, Express does all the work of telling us which routes match the current request path.
Implementation
So, to implement this, I define a new app.useParallel() and we add a fourth parameter to the middleware function for req.param that belongs to that specific middleware route definition.
// pass an array of path, fn pairs
// ['/', func1, '/somePath', func2]
app.useParallel = function(array) {
// create a router that will be inserted only for route matching
let router = express.Router();
// insert route at beginning to make start of routes getting called
router.use(function(req, res, next) {
req.routeList = [];
next();
});
// let the router have dummy route handlers with all the right paths
// so we can use it to see which paths it will match
for (let r of array) {
router.use(r[0], function(req, res, next) {
// for each route that actually gets called (and thus must have matched the path),
// save the corresponding callback function and a copy of the req.params
req.routeList.push({fn: r[1], params: Object.assign({}, req.params)});
next();
});
}
// now insert route at end of router that matches all routes to know when we're done
router.use(function(req, res, next) {
let routeList = req.routeList;
if (routeList && routeList.length) {
// now we are ready here to execute the route handlers in req.routeList in parallel
let len = routeList.length;
let doneCnt = 0;
let nextCalled = false;
for (let middleware of routeList) {
middleware.fn(req, res, function(err) {
++doneCnt;
if (err) {
// make sure we only call next() once
if (!nextCalled) {
nextCalled = true;
next(err);
}
} else {
if (doneCnt === len && !nextCalled) {
next();
}
}
}, middleware.params);
}
} else {
next();
}
});
// insert this router in the chain
app.use(router);
}
And, then this is used like this:
function test1(req, res, next, params) {
// some async operation that calls next() when done
next();
}
// similar definitions for test2(), test3() and test4()
app.parallel([['/', test1], ['/', test2], ['/:id', test3], ['/test', test4]]);
Restrictions
Running multiple middlewares potentially in parallel leads to some restrictions on the middleware - all of which seem somewhat expected if you're setting up for parallel operation. Here are some of the restrictions:
You will get interleaved execution of these handlers if any handler uses asynchronous calls and then completes sometime later. Since node.js is still single threaded, this will NOT do parallel execution of purely synchronous middleware handlers. If they are synchronous, they will still be executed synchronously.
The initial synchronous part of each parallel middleware handler (before it returns while waiting for async responses) is still called in proper sequence.
If any middleware calls next(err), the first one to do it will be the only one that gets processed - others will be ignored.
The req object is shared among all the parallel middleware functions. As such, you have to be aware of any race conditions in using it if you have async operations in your middleware writing to the req object. It can certainly be used as a place to store independent properties (different for each middleware), but two parallel middlewares cannot be expecting sequential access to the same property (one sets it and the other reads what was set) because the execution order is unpredictable. So, you are safest if each parallel middleware only reads standard properties and only writes its own properties.
Because the req object is shared, each middleware can't have its own value for req.param like normal middleware would. As such, do not use req.param at all. Instead, each parallel middleware is passed a fourth argument that is the param object. This allows each parallel middleware to have its own param object.
If any middleware actually sends a response (as opposed to just setting up req variables for later route handlers), then you need to know that it's racy. In general, I would not think you'd use parallel middleware to actually send a response, but I could imagine a few rare cases where you just want the first middleware that finds an answer to send the response. If more than one attempts to send a response, you will get a warning about multiple responses (Express will catch it for you). It is not blocked here.
It should go without saying that any async code in these parallel handlers finishes in an arbitrary order. Do not execute handlers in parallel that require any specific ordering relative to each other.
Use of the req.route property in the parallel middleware is not supported.
Minimal Testing So far
I have not exhaustively tested this, but I do have it running in a sample app that just uses random timers to call next() in each of four parallel middlewares. The route matching works. The params feature works. The middlewares do appear to run in parallel and complete in random order (per their random timers).
All parallel route handlers finish before subsequent routing continues.
The only state used during the parallel processing is stored either on the req object (which should be unique to each request) or in closures so it should be safe from race conditions of multiple parallel requests to the server that are in flight at the same time (though I haven't pounded on a server with lots of parallel requests to confirm that).

What's the point of calling next() after res.send() in Resitfy?

I am familiar with Express but new to Restify. Restify's document has many examples calling next() after res.send() as below:
server.get('/echo/:name', function (req, res, next) {
res.send(req.params);
return next();
});
This looks like a recommended pattern by some Restify experts as well:
The consequences of not calling next() in restify
What's the real use case of doing this? After you call res.send(), is there anything a handler next in the chain can do?
After I did some more research, I think I found an answer.
Only practical use case of calling next() after res.send() is when you want to install 'post-render' type middlewares to catch all transactions after route handers finish their job.
In other cases, it simply adds unnecessary overhead for every and each request because it scans the rest of routes to find a next match.
Most middlewares are 'pre-render' type, which don't need next() call anyway. Even for post-render type middlewares, depending on voluntary calls of next() is simply too risky. You'd rather want to use more error-proof method like https://github.com/jshttp/on-finished instead.
Calling next() after res.send() is a bad practice causing unnecessary overhead in most cases. It should be used only when it is absolutely needed and you know what you are doing.

Can't find the official documentation for the next() method

I see it is used in various ways: next(), next('route'), next(error)...
Where can I find the official documentation for the next() method?
I don't find any documentation summing up it's use cases on the express api docs...
UPDATE:
From what I coroborated, next works like this:
next() : sends req to the next middleware function of the current route
next('route'): sends req to next matching route
and less obvious...
next(anythingElse) sends req to the next error handling middleware, where err will be equal to anythingElse
You can view the "callback" argument under app.use() at http://expressjs.com/en/4x/api.html#app.use
There are also middleware callback function examples as well (http://expressjs.com/en/4x/api.html#middleware-callback-function-examples)
You are looking at the wrong page in the express documentation. The next callback is just to initiate/continue the request-response cycle. The actual guide is located under "Using middleware" title of Guides section on the Expressjs website.
Middleware functions are functions that have access to the request
object (req), the response object (res), and the next middleware
function in the application’s request-response cycle. The next
middleware function is commonly denoted by a variable named next.
Middleware functions can perform the following tasks:
Execute any code.
Make changes to the request and the response objects.
End the request-response cycle.
Call the next middleware function in the stack.
If the current middleware function does not end the request-response
cycle, it must call next() to pass control to the next middleware
function. Otherwise, the request will be left hanging.

Resources