node express: is path always optional? - node.js

According to the docs for express, the path parameter is optional for app.use, so to apply the middleware to any incoming request you can write:
app.use(function (req, res, next) {
res.send('ANY request');
next();
});
But for app.get the path parameter is apparently not optional, so to apply the middleware to any incoming GET request you have to write:
app.get('/', function (req, res, next) {
res.send('GET request');
next();
});
But I find that it doesn't complain if I do miss out the path:
app.get(function (req, res, next) {
res.send('GET request');
next();
});
So, are the above two definitions equivalent, or is the second one doing something different to the first one?
I'm also not sure of the difference between specifying / or * as the path:
app.get('*', function (req, res, next) {
res.send('GET request');
next();
});
So, in summary, is there any difference between app.get('/', fn) and app.get('*', fn) and app.get(fn)?

Somewhat confusingly, there are two methods called app.get:
https://expressjs.com/en/4x/api.html#app.get
One is the converse to app.set, the other is the one for handling GET requests. In practice JS only allows a single method, so internally Express checks how many arguments are passed to work out which one you meant:
https://github.com/expressjs/express/blob/351396f971280ab79faddcf9782ea50f4e88358d/lib/application.js#L474
So while using app.get(fn) might not complain, it won't actually work as a route because it'll be treating it as the other form of get.
The difference between app.get('*', ...) and app.get('/', ...) is that the * will match any path whereas / will only match the exact path / (and nothing more). This is different from app.use, where the path is treated like a 'starts with'.
You may find the answer I gave here helpful to understand how paths differ between get and use: Difference between app.use and app.get *in proxying*.

Related

Routes priority in Express: am I doing it wrong?

I'm a bit confused about the Express priority order for all the routes.
This is what I've done following some stackoverflow answers and other guides on internet.
I have some http requests and this is the order: is it right in your opinion? If not, why? Thanks!
app.get('/', (req, res) => {
...
});
app.get('/:car', (req, res) => {
...
});
app.get('/:car/:eng', (req, res) => {
...
});
app.put('/:car/:feature_id', (req, res) => {
...
});
app.get('/import/colors', (req, res) => {
...
});
app.post('/import/brands', (req, res) => {
...
});
app.post('/import/colors/:car_id', (req, res) => {
...
});
Express just attempts to match your routes in the order they are defined in your code for the type of request it is (.e.g GET, POST, PUT). So, if it's a GET request, Express matches only against the route definitions that include GET. Here's a few examples from the routes you show.
If there's an incoming route of /hello/there, then that will first match app.get('/:car/:eng', ...) because that matches ANY two segment path and it's the first route in order that matches.
If there's an incoming route of /import/colors, then that will also match app.get('/:car/:eng', ...) because that matches ANY two segment path.
If, on the other hand, you change the order of the code to this:
app.get('/import/colors', (req, res) => {
...
});
app.get('/:car/:eng', (req, res) => {
...
});
Then, /import/colors will match the first of these two routes because matching is tried in the order the routes are declared.
FYI, in general, I don't like using routes that have a top level wildcard because you get yourself all sorts of possible conflicts and you may find yourself boxed into a bit of a corner for future URL expansion when you want to add other routes.
Recommendation
So, if you have overlapping route definitions, then define the most specific routes first so they get a chance to match before the more general routes. Most of the time, I prefer a URL design that doesn't have overlapping routes and then you won't have this issue at all.

Order of route precedence express 3 vs 4

Accord to a book for express3. In the following case, http://localhost:3000/abcd will always print "abc*", even though the next route also matches the pattern.
My question is work in the same way for express4 ?
app.get('/abcd', function(req, res) {
res.send('abcd');
});
app.get('/abc*', function(req, res) {
res.send('abc*');
});
Reversing the order will make it print "abc*":
app.get('/abc*', function(req, res) {
res.send('abc*');
});
app.get('/abcd', function(req, res) {
res.send('abcd');
});
The first route handler that matches the route is the one that gets called. That's how Express works in all recent versions. You should generally specify your routes from more specific to less specific and then the more specific will match first and the less specific will catch the rest.
If you want a handler to see all matches and then pass things on to other handlers, you would generally use middleware:
// middleware
app.use("/abc*", function(req, res, next) {
// process request here and either send response or call next()
// to continue processing with other handlers that also match
next();
});

path treated differently between app.use() and app.get()

How come when I do a GET request on /foo, my request passes through the first middleware function in example A, but bypasses it in example B ?
Example A
GET '/foo"
app.use('/', function(req, res, next) {
console.log("req passes through here");
next();
}
app.get('/foo', function(req, res, next) {
console.log("then req passes through here");
}
Example B
GET '/foo"
app.get('/', function(req, res, next) {
console.log("this part is bypassed...");
next();
}
app.get('/foo', function(req, res, next) {
console.log("then req passes through here");
}
app.use() and app.get() use the same path argument.
So how come the middleware mounted on / in not executed in example B ?
app.use() instructs the app to use the specified path for all methods (GET, PUT, POST, etc) on all calls. Specifically app.use:
Mounts the specified middleware function or functions at the specified path: the middleware function is executed when the base of the requested path matches path.
While app.get() instructs it to use the path for that specific method (GET) for that specific path only.
Routes HTTP GET requests to the specified path with the specified callback functions.

expressjs: how can I use bodyParser only for a specific resource?

I am using expressjs, I would like to use the body Parser only for specific resource, how can I do that?
app.use() allows you to specify a "mount path", as well as which middleware to mount, so you should be able to get away with;
app.use('/foo', express.bodyParser);
As express.bodyParser returns a function whose signature is req, res, next (as with all middleware), this seems analagous to adding it as a handler to a resource;
app.get('/foo', express.bodyParser);
app.get('/foo', function (req, res, next) {
// req has been parsed.
});
#Matt answer is good, you can optimize its syntax by writing:
app.get('/foo', express.bodyParser, function (req, res, next) {
// parsed request
});

Difference between app.all('*') and app.use('/')

Is there a useful difference between app.all("*", … ) and app.use("/", … ) in Express.js running on Node.js?
In most cases they would work equivalently. The biggest difference is the order in which middleware would be applied:
app.all() attaches to the application's router, so it's used whenever the app.router middleware is reached (which handles all the method routes... GET, POST, etc).
NOTICE: app.router has been deprecated in express 4.x
app.use() attaches to the application's main middleware stack, so it's used in the order specified by middleware, e.g., if you put it first, it will be the first thing to run. If you put it last, (after the router), it usually won't be run at all.
Usually, if you want to do something globally to all routes, app.use() is the better option. Also, it has less chance of future bugs, since express 0.4 will probably drop the implicit router (meaning, the position of the router in middleware will be more important than it is right now, since you technically don't even have to use it right now).
app.use takes only one callback function and it's meant for Middleware. Middleware usually doesn't handle request and response, (technically they can) they just process input data, and hand over it to next handler in queue.
app.use([path], function)
app.all takes multiple callbacks, and meant for routing. with multiple callbacks you can filter requests and send responses. Its explained in Filters on express.js
app.all(path, [callback...], callback)
app.use only sees whether url starts with the specified path
app.use( "/product" , mymiddleware);
// will match /product
// will match /product/cool
// will match /product/foo
app.all will match complete path
app.all( "/product" , handler);
// will match /product
// won't match /product/cool <-- important
// won't match /product/foo <-- important
app.all( "/product/*" , handler);
// won't match /product <-- Important
// will match /product/
// will match /product/cool
// will match /product/foo
app.use:
inject middlware to your front controller configuring for instance: header, cookies, sessions, etc.
must be written before app[http_method] otherwise there will be not executed.
several calls are processed in the order of writing
app.all:
(like app[http_method]) is used for configuring routes' controllers
"all" means it applies on all http methods.
several calls are processed in the order of writing
Look at this expressJs code sample:
var express = require('express');
var app = express();
app.use(function frontControllerMiddlewareExecuted(req, res, next){
console.log('(1) this frontControllerMiddlewareExecuted is executed');
next();
});
app.all('*', function(req, res, next){
console.log('(2) route middleware for all method and path pattern "*", executed first and can do stuff before going next');
next();
});
app.all('/hello', function(req, res, next){
console.log('(3) route middleware for all method and path pattern "/hello", executed second and can do stuff before going next');
next();
});
app.use(function frontControllerMiddlewareNotExecuted(req, res, next){
console.log('(4) this frontControllerMiddlewareNotExecuted is not executed');
next();
});
app.get('/hello', function(req, res){
console.log('(5) route middleware for method GET and path patter "/hello", executed last and I do my stuff sending response');
res.send('Hello World');
});
app.listen(80);
Here is the log when accessing route '/hello':
(1) this frontControllerMiddlewareExecuted is executed
(2) route middleware for all method and path pattern "*", executed first and can do stuff before going next
(3) route middleware for all method and path pattern "/hello", executed second and can do stuff before going next
(5) route middleware for method GET and path patter "/hello", executed last and I do my stuff sending response
With app.use(), the "mount" path is stripped and is not visible to the middleware function:
app.use('/static', express.static(__dirname + '/public'));
Mounted middleware functions(express.static) are not invoked unless the req.url contains this prefix (/static), at which point it is stripped when the function is invoked.
With app.all(), there is no that behavior.
Yes, app.all() gets called when a particular URI is requested with any type of request method (POST, GET, PUT, or DELETE)
On other hand app.use() is used for any middleware you might have and it mounts onto a path prefix, and will be called anytime a URI under that route is requested.
Here is the documentation for app.all & app.use.
Two differences all above answers don't mention.
The first one:
app.all accepts a regex as its path parameter. app.use does NOT accept a regex.
The second one:
app.all(path, handler) or app[method](path, handler) handlers' path must be same to all path. This is, app[method] path is complete.
app.use(path, handler), if use's path is complete, the handler's path must be /. If the use's path is the start of the complete path, the handler path must be the rest of the complete path.
app.use("/users", users);
//users.js: the handler will be called when matchs `/user/` path
router.get("/", function (req, res, next) {
res.send("respond with a resource");
});
// others.js: the handler will be called when matches `/users/users` path
router.get("/users", function (req, res, next) {
res.send("respond with a resource");
});
app.all("/users", users);
//others.js: the handler will be called when matches `/`path
router.get("/", function (req, res, next) {
res.send("respond with a resource");
});
//users.js: the handler will be called when matches `/users` path
router.get("/users", function (req, res, next) {
res.send("respond with a resource");
});
There are two main differences:
1. pattern matching (answer given by Palani)
2. next(route) won't work inside the function body of middleware loaded using app.use . This is stated in the link from the docs:
NOTE: next('route') will work only in middleware functions that were loaded by using the app.METHOD() or router.METHOD() functions.
Link: http://expressjs.com/en/guide/using-middleware.html
The working effect of next('route') can be seen from the following example:
app.get('/',
(req,res,next)=>{console.log("1");
next(route); //The code here skips ALL the following middlewares
}
(req,res,next)=>{next();}, //skipped
(req,res,next)=>{next();} //skipped
);
//Not skipped
app.get('/',function(req,res,next){console.log("2");next();});

Resources