path treated differently between app.use() and app.get() - node.js

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.

Related

node express: is path always optional?

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*.

Node.js matching the url pattern

I need an equivalent of following express.js code in simple node.js that I can use in middleware. I need to place some checks depending on the url and want to do it in a custom middleware.
app.get "/api/users/:username", (req,res) ->
req.params.username
I have the following code so far,
app.use (req,res,next)->
if url.parse(req.url,true).pathname is '/api/users/:username' #this wont be true as in the link there will be a actual username not ":username"
#my custom check that I want to apply
A trick would be to use this:
app.all '/api/users/:username', (req, res, next) ->
// your custom code here
next();
// followed by any other routes with the same patterns
app.get '/api/users/:username', (req,res) ->
...
If you only want to match GET requests, use app.get instead of app.all.
Or, if you only want to use the middleware on certain specific routes, you can use this (in JS this time):
var mySpecialMiddleware = function(req, res, next) {
// your check
next();
};
app.get('/api/users/:username', mySpecialMiddleware, function(req, res) {
...
});
EDIT another solution:
var mySpecialRoute = new express.Route('', '/api/users/:username');
app.use(function(req, res, next) {
if (mySpecialRoute.match(req.path)) {
// request matches your special route pattern
}
next();
});
But I don't see how this beats using app.all() as 'middleware'.
You can use node-js url-pattern module.
Make pattern:
var pattern = new UrlPattern('/stack/post(/:postId)');
Match pattern against url path:
pattern.match('/stack/post/22'); //{postId:'22'}
pattern.match('/stack/post/abc'); //{postId:'abc'}
pattern.match('/stack/post'); //{}
pattern.match('/stack/stack'); //null
For more information, see: https://www.npmjs.com/package/url-pattern
Just use the request and response objects as you would in a route handler for middleware, except call next() if you actually want the request to continue in the middleware stack.
app.use(function(req, res, next) {
if (req.path === '/path') {
// pass the request to routes
return next();
}
// you can redirect the request
res.redirect('/other/page');
// or change the route handler
req.url = '/new/path';
req.originalUrl // this stays the same even if URL is changed
});

Forward request to alternate request handler instead of redirect

I'm using Node.js with express and already know the existence of response.redirect().
However, I'm looking for more of a forward() functionality similar to java that takes the same parameters as redirect, but internally forwards the request instead of having the client perform the redirect.
To clarify, I am not doing a proxy to a different server. I'd like to forward('/other/path') directly within the same app instance
It wasn't apparently obvious how to do this from the express documentation. Any help?
You just need to invoke the corresponding route handler function.
Option 1: route multiple paths to the same handler function
function getDogs(req, res, next) {
//...
}}
app.get('/dogs', getDogs);
app.get('/canines', getDogs);
Option 2: Invoke a separate handler function manually/conditionally
app.get('/canines', function (req, res, next) {
if (something) {
//process one way
} else {
//do a manual "forward"
getDogs(req, res, next);
}
});
Option 3: call next('route')
If you carefully order your router patterns, you can call next('route'), which may achieve what you want. It basically says to express 'keep moving on down the router pattern list', instead of a call to next(), which says to express 'move down the middleware list (past the router)`.
You can implement forward (aka rewrite) functionality by changing request url property and calling next('route').
Note that the handler performing forward needs to be configured before other routes which you perform forwards to.
This is example of forwarding all *.html documents to routes without .html extension (suffix).
function forwards(req, res, next) {
if (/(?:.+?)\.html$/.test(req.url)) {
req.url = req.url.replace(/\.html$/, '');
}
next('route');
}
You call next('route') as the last operation. The next('route') passes control to subsequent routes.
As mentioned above, you need to configure forwards handler as one of the first handlers.
app.get('*', forwards);
// ...
app.get('/someroute', handler);
The above example will return the same content for /someroute as well as /someroute.html. You could also provide an object with a set of forward rules ({ '/path1': '/newpath1', '/path2': '/newpath2' }) and use them in forward mechanism.
Note that regular expression used in forwards function is simplified for mechanism presentation purposes. You would need to extend it (or perform check on req.path) if you would like to use querystring parameters etc.
I hope that will help.
For Express 4+
Using the next function does not work if the next handler is not added in the right order. Instead of using next, I use the router to register the handlers and call
app.get("/a/path", function(req, res){
req.url = "/another/path";
app.handle(req, res);
}
Or for HTML5 mode of React/Angular
const dir = process.env.DIR || './build';
// Configure http server
let app = express();
app.use('/', express.static(dir));
// This route sends a 404 when looking for a missing file (ie a URL with a dot in it)
app.all('/*\.*', function (req, res) {
res.status(404).send('404 Not found');
});
// This route deals enables HTML5Mode by forwarding "missing" links to the index.html
app.all('/**', function (req, res) {
req.url = 'index.html';
app.handle(req, res);
});
Using the next function does not work if the next handler is not added in the right order. Instead of using next, I use the router to register the handlers and call
router.get("/a/path", function(req, res){
req.url = "/another/path";
router.handle(req, res);
}
Express 4+ with nested routers
Instead of having to use the outside of route/function app, you can use req.app.handle
"use strict";
const express = require("express");
const app = express();
//
// Nested Router 1
//
const routerOne = express.Router();
// /one/base
routerOne.get("/base", function (req, res, next) {
res.send("/one/base");
});
// This routes to same router (uses same req.baseUrl)
// /one/redirect-within-router -> /one/base
routerOne.get("/redirect-within-router", function (req, res, next) {
req.url = "/base";
next();
});
// This routes to same router (uses same req.baseUrl)
// /one/redirect-not-found -> /one/two/base (404: Not Found)
routerOne.get("/redirect-not-found", function (req, res, next) {
req.url = "/two/base";
next();
});
// Using the full URL
// /one/redirect-within-app -> /two/base
routerOne.get("/redirect-within-app", function (req, res, next) {
req.url = "/two/base";
// same as req.url = "/one/base";
//req.url = req.baseUrl + "/base";
req.app.handle(req, res);
});
// Using the full URL
// /one/redirect-app-base -> /base
routerOne.get("/redirect-app-base", function (req, res, next) {
req.url = "/base";
req.app.handle(req, res);
});
//
// Nested Router 2
//
const routerTwo = express.Router();
// /two/base
routerTwo.get("/base", function (req, res, next) {
res.send("/two/base");
});
// /base
app.get("/base", function (req, res, next) {
res.send("/base");
});
//
// Mount Routers
//
app.use("/one/", routerOne);
app.use("/two/", routerTwo);
// 404: Not found
app.all("*", function (req, res, next) {
res.status(404).send("404: Not Found");
});
app.get('/menzi', function (req, res, next) {
console.log('menzi2');
req.url = '/menzi/html/menzi.html';
// res.redirect('/menzi/html/menzi.html');
next();
});
This is my code:when user enter "/menzi",the server will give the page /menzi/html/menzi.html to user, but the url in the browser will not change;
You can use run-middleware module exactly for that. Just run the handler you want by using the URL & method & data.
https://www.npmjs.com/package/run-middleware
For example:
app.runMiddleware('/get-user/20',function(code,body,headers){
res.status(code).send(body)
})

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