Built in Middleware function - node.js

Built in middleware functions like app.use(express.json()) and app.get('/', () => res.send('Hello')).
I heard they can be called middleware functions too, I don't know if 'Built in Middleware function is the best term to call them. Do they terminate the cycle or do they automatically invoke the next() method, to pass control to the next middleware function?

Neither app.get or app.use are middleware functions. Middleware functions are those that you are passing as callbacks to the app.get, app.use, ...
In express, middleware functions have a predefined signature, either
function(req: express.Request, res: express.Response, next: express.NextFunction)
or
function(err: Error, req: express.Request, res: express.Response, next: express.NextFunction)
depending on whether it is normal or error middleware.
Any function that operates on an incoming request and have the above signature can be called a middleware function.
There are only two possible options that you can do in the middeware function, either you send a response to the requester or you call next function to pass the request to the next middleware (or forget to do any of there and wonder why the client seems stuck).
So yes, things like body-parsers, loggers, session handlers, ... do call next function otherwise your own request handlers wouldn't be executed at all (assuming they are preceded by the mentioned middleware functions).
Callbacks passed to app.get and similar methods are also middleware functions and you can call next within them and continue with another handler. Example
// these are global middleware functions - they process every request
app.use(middleware1)
app.use(middleware2)
app.use(middleware3)
// functions middleware4 and middleware5 are executed only when GET /
// request is received
app.get('/', middleware4, middleware5, (req, res) => {
return res.send({})
})

they automatically invoke the next() method .id execute successfully otherwise they will throw error
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.
As name suggests it comes in middle of something and that is request and response cycle
Middleware has access to request and response object
Middleware has access to next function of request-response life cycle
Image for post
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 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.

Related

What does this app.use() function do here:

I have some code from a tutorial and i am trying to understand it. I can't figure it out what's the purpose of this middleware function:
app.use((req, res, next) => {
res.locals.path = req.path;
next();
});
res.locals doc says:
An object that contains response local variables scoped to the request, and therefore available only to the view(s) rendered during that request / response cycle (if any).
This middleware sets the path part of the request URL to res.locals object and call next middleware.
You can use the res.locals.path to access the value in your controller later

Understanding middleware in Express

I am trying to figure out how middleware works in Express.
Whilst I understand the concept of middleware, I am confused by the middleware parameters.
Here is an example from the offical docs regarding middleware:
app.use('/user/:id', function (req, res, next) {
console.log('Request URL:', req.originalUrl)
next()
}, function (req, res, next) {
console.log('Request Type:', req.method)
next()
})
In this example, I can see there are two functions that act as two middleware which are executed one after the other before this specific route is handled.
But what are the parameters passed to these functions?
Are req and res just "empty" objects?
If so how are we able to reference the property req.originalUrl?
And if not, where is that object and its properties coming from?
They also use res.send in the tutorial, so therefore the res object seems to also have properties and not be an "empty" object.
(I understand that next is a call back argument).
Summary
The request object represents the HTTP request and has properties for the request query string, parameters, body, HTTP headers, and so on.
The response object represents the HTTP response that an Express app sends when it gets an HTTP request.
Middleware functions are functions that have access to the request object, the response object, and the next function in the application’s request-response cycle. The next function is a function in the Express router which, when invoked, executes the middleware succeeding the current middleware.
Routes can have chained methods attached (for GET, POST and DELETE requests) that take middleware functions as arguments.
The request object is the data initially received from the request, which can be modified as it passes through various middleware functions, and the response object is the data sent out.
Example Middleware
Below is an example middleware function you can copy and paste at the beginning of your app:
/**
* An example of a middleware function that logs various values of the Express() request object.
*
* #constant
* #function
* #param {object} req - The req object represents the HTTP request and has properties for the request query string, parameters, body, HTTP headers, and so on. In this documentation and by convention, the object is always referred to as req (and the HTTP response is res) but its actual name is determined by the parameters to the callback function in which you’re working.
* #param {object} res - The res object represents the HTTP response that an Express app sends when it gets an HTTP request. In this documentation and by convention, the object is always referred to as res (and the HTTP request is req) but its actual name is determined by the parameters to the callback function in which you’re working.
* #param {Function} next - `next` is used as an argument in the middleware function, and subsequently invoked in the function with `next()`, to indicate the application should "move on" to the next piece of middleware defined in a route's chained method.
* #see {#link https://expressjs.com/en/4x/api.html#req|Express Request}
* #see {#link https://expressjs.com/en/4x/api.html#res|Express Response}
* #see {#link http://expressjs.com/en/guide/writing-middleware.html|Writing Middleware}
*/
const my_logger = (req, res, next) => {
console.log("req.headers: ");
console.log(req.headers);
console.log("req.originalUrl: " + req.originalUrl);
console.log("req.path: " + req.path);
console.log("req.hostname: " + req.hostname);
console.log("req.query: " + JSON.stringify(req.query));
console.log("req.route: " + JSON.stringify(req.route));
console.log("req.secure: " + JSON.stringify(req.secure));
console.log("req.ip: " + req.ip);
console.log("req.method: " + req.method);
console.log("req.params:");
console.log(req.params);
console.log("==========================");
//if next() is not invoked below, app.use(myLogger) is the only middleware that will run and the app will hang
next();
}
// called for all requests
app.use(my_logger);
Example Routes
Below are some example routes.
The routes have chained methods attached that take middleware functions as arguments.
// some example routes
app.route("/api/:api_version/pages")
.get(api_pages_get);
app.route("/api/:api_version/topics")
.get(api_topics_get)
.post(api_login_required, api_topics_post)
.delete(api_login_required, api_topics_delete);
app.route("/api/:api_version/topics/ratings")
.post(api_login_required, api_topics_ratings_post);
Using next() in a middleware function
In the above example, you can see some methods have two middleware functions as arguments.
The first one, api_login_required, verifies login credentials and, if successful, calls next() which prompts the next middleware function to run.
It looks like this:
const api_login_required = (req, res, next) => {
// req.user exists if the user's request was previously verified, it is produced elsewhere in the code
if (req.user) {
next();
} else {
return res.status(401).json({ message: 'Unauthorized user!' });
}
}
Middleware without next()
However, the get() method attached to the route handler for /api/:api_version/pages only has a single middleware function argument: api_pages_get.
As shown below, api_pages_getdoes not call next() because there are no middleware functions that are required to run after it.
It uses the send() and json() methods of the response object to return a response.
const api_pages_get = async (req, res) => {
var page_title = req.query.page_title;
var collection = mongo_client.db("pages").collection("pages");
var query = { page_title: page_title };
var options = { projection: { page_title: 1, page_html: 1 } };
try {
var page = await collection.findOne(query);
// if there is no result
if (page === null) {
res.status(404).send('404: that page does not exist');
return;
}
// if there is a result
else if (page !== null) {
res.json(page);
return;
}
} catch (err) {
console.log("api_pages_get() error: " + err);
res.send(err);
return;
}
}
Notes on middleware
Some other notes I've previously written for my own reference that may help:
Middleware, or middleware functions, have access to the Express request and response objects and are passed as arguments to a route's chained method (or on all requests if passed as an argument to an instance of the use() method defined early in your code).
next is used as an argument in the middleware function, and subsequently invoked in the function with next(), to indicate the application should "move on" to the next piece of middleware defined in a route's chained method.
If a middleware function does not invoke next(), it will not move on to the next piece of middleware defined in a route or method handler.
Additionally, if next() is not used, and a terminating action, ie a response, is not defined in the function, the app will stay in a "hanging" state.
Do req and res are just "empty" objects?
No, req and res are never empty and are in fact same which are passed on to each middleware. You can also modify the req and res objects and the modification will persist in all next middlewares.
You can see all the available fields on req and res here respectively - request object and response object.
You can always access req and res at any point in a middleware. If you wish to the end the request response cycle, you can just use the response object and send a response like res.send(200). This will end the req-res cycle and you need not call the next().
But what paramters are given to this functions ?
You don't need to pass any parameter to this function. Express will alwasy pass the req, res and next to any middleware defined. It's the format you can assume that express uses and and all middlewares should follow.
Note that if you don't end the req-res cycle, you must call the next() which will pass on the control to the next middleware. If the middleware does not end the req-res cycle and also does not call next(), the request will keep hanging and may perhaps just timeout on the client side.
If I understand you correctly, the confusing part are the objects passed to the middleware functions? In the docs you've linked there is already an explanation for those (See below).
"But what paramters are given to this functions ?."
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.
(Source)
"Do req and res are just "empty" objects ?, if so how come we are using the field req.orginaleUrl ? and if not where is that object and
its field came from ?"
If you follow the links, you'll discover following explanation for the request object:
The req object represents the HTTP request and has properties for the request query string, parameters, body, HTTP headers, and so on.
(Source)
The originalUrl property mentioned in your question is a property of the req object.
and the response object:
The res object represents the HTTP response that an Express app sends when it gets an HTTP request.
The send is a method assigned to the res object, which will send a HTTP response.
(Source)

Can I use 2 different functions on the same route? Node.js

I have 2 different methods that I want to be called when a specific form is filled. I know that I can't have a form with 2 actions so I am just wondering can I call 2 different methods on the same route in Node.js?
I need something like this
router.post('/webmark/addcollection', webmarks.addCollection);
router.post('/webmark/addcollection', webmarks.uploadPicture);
so basically when the button in the form is pressed, the action would redirect to the specific route and the 2 methods would be called.
No, if do it that way, then you will be overwriting the first.
A better approach to that is like below:
router.post('/webmark/addcollection', webmarks.addCollection, webmarks.uploadPicture);
And make sure you make the call to next middleware function here uploadPicture from addCollection handler by adding next() in addCollection middleware on the successful operation.
exports.addCollection = function(req, res, next){
// You logic goes here
// On success operation call next middleware
next();
}
exports.uploadPicture = function(req, res){
// You logic for uploadPicture
}
You can just put the uploadPicture inside the addCollection and it will work as you want.
Your first function receives 3 input (request, response, next), at the end of this function, call next().

nodeJS code pattern => Express middleware/Oauth2/Passport

I inherited a codebase where it looks like they run middleware in node with the following pattern for Oauth2 passport strategy
module.exports = function (router) {
router.get('/', function (req, res, next) {
passport.authenticate('type', object, function(err, info) {
//pass info object to next middleware
})(req,res,next) <---where does this go?!?
})
}
From my current understanding of the code base, this is actually the last function call in the middleware chain, so could I just add a piece of middleware to the bottom?
Does this sound like the right idea?
And just to clarify what I'm trying to do:
pass data from Oauth callback through middleware function by attaching it to the req
perform DB business logic (create or lookup account)
login with JWT
redirect
This appears to be the "custom callback" method of using passport's authenticate function. If you look at the documentation you can see how they expect it to be used. That said, I don't know what that second argument is supposed to be doing (the object) - it looks like a variable, but I don't see it defined anywhere, and I'm not sure the authenticate method takes arguments in that manner. Also, the custom callback takes three arguments: err, user, and then info... which might trip you up.
Okay, so now to your actual question of "could I just add a piece of middleware to the bottom?" Sort of? The fact is, you're in a routing middleware at that point. If it matches and auth is successful, then you should do whatever code for that route is required inside the custom callback. That's the point of this way of doing things. Alternatively you could use passport.authenticate as a piece of middleware itself (it returns a middleware function usable in the CommonJS pattern.
If you don't want to change up the code, then you could just do this:
module.exports = function (router) {
router.get('/', function (req, res, next) {
passport.authenticate('PICK A VALID TYPE', function(err, user, info) {
// this custom callback will be executed once auth completes
// (either successfully or not
// put code in here to perform DB business logic, login, and redirect
})(req,res,next); <--- this executes the passport.authenticate middleware
})
};

SendFile issues with respect to control flow in Express Middleware

Here is relevant portion of my code, simplified for narrowing the issue:
app.use(middleware1);
app.use(middleware2);
function middleware1(req,res,next) {
...//get extension of request URL
switch (extension)
{
case 'js' :
..
case 'html': res.sendFile(res.originalUrl,function(err) {});
break; //break1
case 'njm' : break; //break2
default : console.log('default');
break;
}
}
function middleware2(req,res,next) {
console.log("I am in middleware2");
}
Question is this: In case extension is html, for example, I would not expect middleware2 to be called at all but it does!
It appears that sendFile initiates the sending of the file and control execution falls thru before the sendFile's callback is called. If I replace break1 by next() or return next() that would be equally flawed - Control will go to next middleware2 before sendFile's callback is executed. How do I stop middleware2 from getting called for the first set of extensions? Also, if extension is 'njm', even without a next(), middleware2 is called. Why?
Please do not suggest using Express static middleware because I have some logic involved in serving different file types which is more complex then the simplified scenario given above.
res.sendFile() is a bit unique. If you don't pass it a completion callback, then it will call next() for you. See details later in this answer.
What you are reporting is opposite of how Express says it works so I think there must be something that is not quite happening the way you report it.
The whole point of the Express middleware is that any given middleware call gets a chance to field the request and then it either handles the request by generating a response or if it wants the middleware chain to continue, then it calls next(). If next() is not called, then the middleware chain stops and nothing else is called in the current middleware chain. If this is application level middleware (with app.use()), then there should be no further app level middleware processing if you do not call next() from your middleware.
Here's a quote from the Express middleware page:
If the current middleware does not end the request-response cycle, it
must call next() to pass control to the next middleware, otherwise the
request will be left hanging.
This is a pretty good article about Express middleware: Express Middleware Demystified which helps explain a lot more of the details. It also confirms that if you don't call next() then no more handlers will be called in the middleware chain.
There is one special case with res.sendFile(). If you don't pass it a completion callback, then it will call next() itself. If you pass it the completion callback, then it will not call next(). This does not appear to be well documented, but if you look at the res.sendFile() code here, you can see how it works.
One thing to watch out for with your debugging is that sometimes the browser issues more requests than you may realize. For example, when you first hit a homepage of a site, the browser may ask for the website favicon which causes an extra request to hit your web server. So, I'm wondering if your console.log() debugging is confusing you because perhaps there is more than one request coming in, not a single request that is going through both pieces of middleware. Also, a cross origin Ajax call may request AJAX options before requesting the actual Ajax call too.
You can differentiate multiple requests like this and more accurately see whether it is actually going from middleware1 to middleware2 on the same request:
var reqCntr = 1;
app.use(middleware1);
app.use(middleware2);
function middleware1(req,res,next) {
if (!req.reqCntr) {
req.reqCntr = reqCntr++;
}
console.log("middleware1: " + req.reqCntr);
...//get extension of request URL
switch (extension)
{
case 'js' :
..
case 'html': res.sendFile(res.originalUrl,function(err) {});
// return here because the request is now handled
return;
case 'njm' : break; //break2
default : console.log('default');
break;
}
// the request was not handled so call the next link in the middleware chain
next();
}
function middleware2(req,res,next) {
if (!req.reqCntr) {
req.reqCntr = reqCntr++;
}
console.log("middleware2: " + req.reqCntr);
}
Also, it seems like the middleware1 cases where you are not handling the request should call next() so I've modified the above middleware1 to do that. If you handle the request in the switch statement, then return. If not, it will fall through to a call to next().
Once you write app.use(middleware2), middleware2 will be used for all routes on app once middleware1 is completely executed.
As you want to use middleware2 conditionally I would suggest you to use the following method:
app.use(middleware1);
function middleware1(req,res,next) {
...//get extension of request URL
switch (extension)
{
case 'js' : middleware2(req, res, next);
break;
case 'html': res.sendFile(res.originalUrl,function(err) {});
break;
case 'njm' : middleware2(req, res, next);
break;
default : middleware2(req, res, next);
break;
}
}
function middleware2(req,res,next) {
console.log("I am in middleware2");
}

Resources