I was just reading the documentation on express and found these two terms, app.use(); and router.use();
I know app.use(); is used in node for Mounting a middleware at a path, and we often use it in most of the node apps. but what is router.use(); are they both same? if not, whats the difference ?
I read about router here. I also found similar questions on SO What is the difference between "express.Router" and routing using "app.get"?
and Difference between app.all('*') and app.use('/'), but they do not really answer my question. Thanks.
router.get is only for defining subpaths. Consider this example:
var router = express.Router();
app.use('/first', router); // Mount the router as middleware at path /first
router.get('/sud', smaller);
router.get('/user', bigger);
If you open /first/sud, then the smaller function will get called.
If you open /first/user, then the bigger function will get called.
In short, app.use('/first', router) mounts the middleware at path /first, then router.get sets the subpath accordingly.
But if we instead use the following:
app.use('/first', fun);
app.get('/sud', bigger);
app.get('/user', smaller);
If you open /first in your browser, fun will get called,
For /sud, bigger will get called
For /user, smaller will get called
But remember for /first/sud, no function will get called.
This link may also help: http://expressjs.com/api.html#router
router.use(); mounts middleware for the routes served by the specific router, app.use(); mounts middleware for all routes of the app (or those matching the routes specified if you use app.use('/ANYROUTESHERE', yourMiddleware());).
Example use case could be an app with one router with standard routes and one router that handles api routes, which need a valid user.
You would then mount the authentication middleware for the api router only with router.use(yourAuthMiddleware());.
If you would have an app though that requires a valid user for all routes, mount the middleware for the app with app.use(yourAuthMiddleware());
app.use() used to Mounts the middleware function or functions at the specified path,the middleware function is executed when the base of the requested path matches path.
router.use() is used to middleware function or functions, The defaults mount path to “/”.
But in
app.use() you will have to give a specified path like that:
var adsRouter = require('./adsRouter.js');
app.use('/ads', adsRouter);
or
app.use('/ads', function(req, res, next) {
// write your callback code here.
});
But while using router.use() you can give only middleware, like this:
router.use(function(req, res, next) {
console.log('%s %s %s', req.method, req.url, req.path);
next();
});
or
router.use('/test', function(req, res, next) {
// write your callback code here.
next();
});
or
//in router.js
router.use('/admin', authUtil.verifySessionId, authUtil.verifyLisencee);
router.post('/admin', controllerIndex.ads.adListingAdmin);
In the above code when the end point is '/admin' then first it will call the authUtil.verifySessionId and authUtil.verifyLisencee then it will execute next line with 'admin' end point and according to controllerIndex.ads.adListingAdmin method.
app.use(middleware): application-level middleware.
router.use(middleware): router-level middleware.
("middleware" refers to methods/functions/operations that are called between processing the request and sending the response.)
See https://expressjs.com/en/guide/using-middleware.html for a comparison of different types of middleware used in an Express app.
When looking at the express js docs for Routing (https://expressjs.com/en/guide/routing.html#express-router):
Use the express.Router class to create modular, mountable route handlers. A Router instance is a complete middleware and routing system; for this reason, it is often referred to as a “mini-app”.
A Router created with express.Router() is no different than an app created with express() in terms of functionality; it's like a logical grouping of routes/handlers/services/databases/etc. The biggest difference is the scope that it affects. A router just affects its own scope while the app is like the master/global scope for your web/app server. You could have many routers or "apps" running on one main app/web server instance. This is why you could listen to requests on an app instance via app.listen(80) but not on a router.
Related
I've created a NodeJS Express app. But my express route is invocking multiple routes function, one after another, but I only need one at a time.
My express app.js
app.use(routes)
Express router:
const router = express.Router();
router.post("/product", controller.productFunction)
router.post("/user", controller.userFunction)
router.get("/:id", idController.getId)
Whenever I create a post request for "/product" route, first the productFunction is invocked, but then the "/:id" routes getId function is also get invocked. Same thing happen for /user route as well. Always /:id route is getting invocked.
Is there any way to prevent this?
I even tried this way, but after the homepage loading then again it invockes getId function.
app.get("/", (req, res, next) => {
res.sendFile(..........);
});
app.use(routes);
I am sure that this is not an issue with the router itself.
You can't skip from POST to GET handling. So invocations are caused by different requests.
router.get("/:id", idController.getId) kind of wild card, and <server_url>/favicon.ico will trigger it
If you check it via browser it tries to get favicon or smth else and invokes this handler.
Try to make POST request via curl/Postman and idController.getId should not be called.
It is risky to serve static and process requests on a same level.
You can add some prefix to all your request, like that app.use('/api', routes); then static file will be available on /<file_name> and all server logic will be under /api/<request>
In my node/express app.js main file, I have created a mini-app router:
var router = express.Router();
that I am passing inside to my controller functions and exporting again, at the end, I am registering the router in
app.use('/Link', router);
I now wanted to set up a second Controller folder with extra Controller function and routes only for my Angular NGX-Charts, where I prep up my data from mongoDB in correct format. Therefore, I wanted to create a second router object where I am passing and registering the right routes and middleware for that router object.
My question now is, can I create and register more than one router object for my express instance, like app.use('/Link',router1, router2, router3,...) ?
and does it behave the same like one router object then (I mean, will it find the appropriate router according to which routes I am navigating to in my browser and execute the correct middleware)?
Sure, you can do that. Common use-cases would be password-protection, generating auth tokens, parsing payloads, etc.
app.use accepts any number of "middlewares" after the first argument.
Check the docs for more details: https://expressjs.com/en/4x/api.html#app.use
The arguments are fairly flexible, there are a number of options for what you can pass.
A middleware function.
A series of middleware functions (separated by commas).
An array of middleware functions.
A combination of all of the above.
Each function gets 3 arguments, which are the Request, Response, and next callback function. Here's an example with an inline middleware that logs something and forwards to the next handler.
app.use('/secret-stuff', authorize, (req, res, next) => {
console.log('token from auth middleware', req.authToken)
next()
}, render)
One thing to note is that you can only send one response, so only the final handler would send the response to the user. Everything before that should call next() to activate the next middleware in the chain.
You could pass a number of routers as long as you make sure to forward (call next()) when the paths are unmatched. You would need to use some kind of path pattern that would allow for the middleware routers to handle greater specificity in the path (e.g. '/Link/*'), otherwise you wouldn't be able to define any sub-path handlers in the middleware routers.
In the past, I haven't had the need for sub-routers. Middleware works fine for modularization.
There currently is a difference between
app.use(function(req,res,next){
});
and
router.use('/some_route', function(req,res,next){
});
...The difference being that app.use runs for every request and router.use only runs for matching routes.
My question is about the router that must lie underneath app. Surely app has some default router internal to it. Is there a way to access that router...app.router? I thought that was deprecated?
Secondly, what I am really looking for is a way to access the current router being used.
For example,
app.use(function(req,res,next){
var currentRouter = req.app._router // (?)
});
or
router.use(function(req,res,next){
var currentRouter = req._router //(?)
});
where req._router would be equal to the same router for the router.use call of course.
In the latest Express code, the default app router is in app._router.
It is created lazily which means it's not created until a route is actually defined (with app.use() or app.get() or something like that).
It does not appear that this is meant to be a public property and thus is subject to change. You can, of course, just define your own router with the root path and only use your own router and then you would not have to access or use this non-public property.
You are correct that app.router is deprecated. Trying to access it purposely throws an exception in the Express code.
So I've seen TJ's guide to creating modular Express-apps, followed it to good effects, but want to know more about the details of how it works, however a search gives me no answers.
In short I am wondering: When mounting apps in Express, what parts of the apps are shared and what parts are not?
Some examples to clarify my question:
app.js:
app.use(express.bodyParser());
app.use(loginApi); //loginApi is an express app
app.listen(3000);
This example works. But if I place the app.use(loginApi) before app.use(express.bodyParser()); , the body parser will not be available in the loginApi subapp. Why is that?
Another example:
submodule.js
var app = module.exports = require('express')();
app.all('*', function(req, res, next){
console.log('nifty middleware');
next();
});
app.js
app.get('/funtimes', fn);
app.use(submodule);
app.listen(3000);
Now in this example, If I understand it correctly, the /funtimes route will not be affected by the submodule middleware for all routes. But what about the rest of the routes of app.js ? Will they be affected? And what if I add another module, will it be affected?
if I place the app.use(loginApi) before app.use(express.bodyParser()); , the body parser will not be available in the loginApi subapp. Why is that?
That's because of the way Express handles requests. Any incoming request starts at the top of the middleware stack, starting with app.use() stack.
Middleware are simply functions that have the function signature function(req, res, next) which either call next() if they want to hand off the request to subsequent functions, or send a response themselves. You define a 'middleware chain' of a bunch of these functions (many are provided by express, like express.logger() and express.compress().)
So in the following scenario:
app.use(express.bodyParser());
var loginApi = require('./api/index.js')
app.use(loginApi);
app.use(app.router);
then an incoming request will first hit app.use(express.bodyParser()), parsing req.body. Then that function calls its internal next(), passing it to the next function in the middleware chain (app.use(loginApi)). The loginApi app has its own middleware chain, but the requests already have req.body set from the outer app. If the loginApi doesn't send a response, the request will continue to app.use(app.router) and at that point the requests will go to the routing functions you set up in your outer app.
So the answer is: A mounted app will have the middleware functions shared, which are placed before the line app.use(loginApi)
Middleware runs in order (until one of the middlewares doesn't call next()).
If you use() your mounted app before use()ing bodyParser, the entire sub-app will run before bodyParser adds its properties.
What you're asking about is middleware. This confused me for a while. Middleware are the functions that run in order to take a request in and serve back a response. app.use() takes a function as its only argument. That function manipulates the request in a consistent way.
app.use is a lot like app.all("*").
The order matters. For example, you might want to run a validator before serving the response.
One thing I learned recently is that you can pass an array of middleware functions to a route. For example
app.get("/whatever",[
function(req,res,next}{
...validation...
next();
},
function(req,res) {
...actions....
res.send(200);
}
]);
The next callback tells express to run the next function in the middleware. Middleware can also modify the request object. This is used a lot in authentication. For example, you'll see req.user getting defined from the database so in later middleware you'll be able to refer to properties of the user. But, it can also be used for a ton of other stuff.
Before I ask about app.router I think I should explain at least what I think happens when working with middleware. To use middleware, the function to use is app.use(). When the middleware is being executed, it will either call the next middleware by using next() or make it so no more middleware get called. That means that the order in which I place my middleware calls is important, because some middleware depends on other middleware, and some middleware near the end might not even be called.
Today I was working on my application and had my server running in the background. I wanted to make some changes and refresh my page and see the changes immediately. Specifically, I was making changes to my layout. I couldn't get it to work so I searched Stack Overflow for the answer and found this question. It says to make sure that express.static() is beneath require('stylus'). But when I was looking at that OP's code, I saw that he had his app.router call at the very end of his middleware calls, and I tried to figure out why that was.
When I made my Express.js application (version 3.0.0rc4), I used the command express app --sessions --css stylus and in my app.js file the code came setup with my app.router above both the express.static() and require('stylus') calls. So it seems like, if it comes already setup that way, then it should stay that way.
After re-arranging my code so I could see my Stylus changes, it looks like this:
app.configure(function(){
//app.set() calls
//app.use() calls
//...
app.use(app.router);
app.use(require('stylus').middleware(__dirname + '/public'));
app.use(express.static(__dirname + '/public', {maxAge: 31557600000}));
});
app.get('/', routes.index);
app.get('/test', function(req, res){
res.send('Test');
});
So I decided that the first step would be to find out why it is important to even have app.router in my code. So I commented it out, started my app and navigated to /. It displayed my index page just fine. Hmm, maybe it worked because I was exporting the routing from my routes file (routes.index). So next I navigated to /test and it displayed Test on the screen. Haha, OK, I have no idea what app.router does. Whether it is included in my code or not, my routing is fine. So I am definitely missing something.
So Here Is My Question:
Could somebody please explain what app.router does, the importance of it, and where I should place it in my middleware calls? It would also be nice if I got a brief explanation about express.static(). As far as I can tell, express.static() is a cache of my information, and if the application can't find the requested page, it will check the cache to see if it exists.
Note: This describes how Express worked in versions 2 and 3. See the end of this post for information about Express 4.
static simply serves files (static resources) from disk. You give it a path (sometimes called the mount point), and it serves the files in that folder.
For example, express.static('/var/www') would serve the files in that folder. So a request to your Node server for http://server/file.html would serve /var/www/file.html.
router is code that runs your routes. When you do app.get('/user', function(req, res) { ... });, it is the router that actually invokes the callback function to process the request.
The order that you pass things to app.use determines the order in which each middleware is given the opportunity to process a request. For example, if you have a file called test.html in your static folder and a route:
app.get('/test.html', function(req, res) {
res.send('Hello from route handler');
});
Which one gets sent to a client requesting http://server/test.html? Whichever middleware is given to use first.
If you do this:
app.use(express.static(__dirname + '/public'));
app.use(app.router);
Then the file on disk is served.
If you do it the other way,
app.use(app.router);
app.use(express.static(__dirname + '/public'));
Then the route handler gets the request, and "Hello from route handler" gets sent to the browser.
Usually, you want to put the router above the static middleware so that a accidentally-named file can't override one of your routes.
Note that if you don't explicitly use the router, it is implicitly added by Express at the point you define a route (which is why your routes still worked even though you commented out app.use(app.router)).
A commenter has brought up another point about the order of static and router that I hadn't addressed: the impact on your app's overall performance.
Another reason to use router above static is to optimize performance. If you put static first, then you'll hit the hard drive on every single request to see whether or not a file exists. In a quick test, I found that this overhead amounted to ~1ms on an unloaded server. (That number is much likely to be higher under load, where requests will compete for disk access.)
With router first, a request matching a route never has to hit the disk, saving precious milliseconds.
Of course, there are ways to mitigate static's overhead.
The best option is to put all of your static resources under a specific folder. (IE /static) You can then mount static to that path so that it only runs when the path starts with /static:
app.use('/static', express.static(__dirname + '/static'));
In this situation, you'd put this above router. This avoids processing other middleware/the router if a file is present, but to be honest, I doubt you'll gain that much.
You could also use staticCache, which caches static resources in-memory so that you don't have to hit the disk for commonly requested files. (Warning: staticCache will apparently be removed in the future.)
However, I don't think staticCache caches negative answers (when a file does not exist), so it doesn't help if you've put staticCache above router without mounting it to a path.
As with all questions about performance, measure and benchmark your real-world app (under load) to see where the bottlenecks really are.
Express 4
Express 4.0 removes app.router. All middleware (app.use) and routes (app.get et al) are now processed in precisely the order in which they are added.
In other words:
All routing methods will be added in the order in which they appear. You should not do app.use(app.router). This eliminates the most common issue with Express.
In other words, mixing app.use() and app[VERB]() will work exactly in the order in which they are called.
app.get('/', home);
app.use('/public', require('st')(process.cwd()));
app.get('/users', users.list);
app.post('/users', users.create);
Read more about changes in Express 4.
Routing means determining how an application responds to a client request to a particular endpoint, which is a URI (or path) and a specific HTTP request method (GET, POST, and so on).
Each route can have one or more handler functions, which are executed when the route is matched.
In Express 4.0 Router, we are given more flexibility than ever before in defining our routes.
express.Router() is use multiple times to define groups of routes.
route used as middleware to process requests.
route used as middleware to validate parameters using ".param()".
app.route() used as a shortcut to the Router to define multiple requests on a route
when we are using app.route(), we are attaching our app with that router.
var express = require('express'); //used as middleware
var app = express(); //instance of express.
app.use(app.router);
app.use(express.static(__dirname + '/public')); //All Static like [css,js,images] files are coming from public folder
app.set('views',__dirname + '/views'); //To set Views
app.set('view engine', 'ejs'); //sets View-Engine as ejs
app.engine('html', require('ejs').renderFile); //actually rendering HTML files through EJS.
app.get('/', function (req, res) {
res.render('index');
})
app.get('/test', function (req, res) {
res.send('test')
})
In express Version 4 we can easily define routes in the following manner:
server.js:
const express = require('express');
const app = express();
const route = require('./route');
app.use('/route', route);
// here we pass in the imported route object
app.listen(3000, () => console.log('Example app listening on port 3000!'));
route.js:
const express = require('express');
const router = express.Router();
router.get('/specialRoute', function (req, res, next) {
// route is now http://localhost:3000/route/specialRoute
});
router.get('/', function (req, res, next) {
// route is now http://localhost:3000/route
});
module.exports = router;
In server.js we imported the router object of the route.js file and apply it in the following manner in server.js:
app.use('/route', route);
Now all of the routes in the route.js have the following base URL:
http://localhost:3000/route
Why this approach:
The main advantage of taking this approach is that now our app is more modular. All the route handlers for a certain route now can be put into different files which makes everything more maintainable and easier to find.
An article by #kelyvinn from 2016, with the intent to demonstrate modularity, includes this code:
// controllers/apis/dogs/index.js
const
express = require('express'),
dogService = require('../../../services/dogs');
let router = express.Router();
router.get('/', dogService.getDogs);
router.get('/:id', dogService.getDogWithId);
module.exports = router;