Some Express.Router() routes do not execute middleware function - node.js

I'm trying to wrap my head around my implementation of express.router() not triggering of the middleware function assigned to it.
I wrote a pretty big app and trying to add a few more endpoints to my path, but for some reason the 9th route gets loaded but does not trigger the function.
app.js
server.use(cors());
server.use(function (req, res, next) {
next();
});
server.use("/", express.static("./assets"));
server.use("/api", api);
server.use("/debug", debug);
server.use("/config", config);
server.use("/control", control);
server.use("/tools", files);
And this is where I declared my routes with the respective functions.
router.get("/teams", onGetTeams);
router.get("/players", onGetPlayers);
router.get("/achievements", getTop3);
router.get("/xpression", onXprPayload);
router.get("/snapshot", onRequestSnapshot);
router.get("/round-timeline", onRequestTimelinePayload);
router.get("/:half", onRequestHalf);
router.get("/dashboard-message", onSetDashboardMessage);
router.get("/get-match-odds", getTeamOdds);
function getTeamOdds(req, res) {
console.log("Sent odds");
res.json(odds);
res.end();
}
When I make the request for the last route, the function does not get executed, and I get back a 200 response.
Is there something big I'm missing?
Thank you !

Your route definition here:
router.get("/:half", onRequestHalf);
is a wildcard route that matches ALL routes so none of the routes after it will get called unless that specific route calls next() to continue routing.
Top level wildcard routes are problematic for this reason. I would suggest avoiding them. There are temporary work-arounds like moving their definition to be the last top level route definition, but they can still be limiting for defining future routes because they are so greedy.
My recommendation would be to not make it a top level route:
router.get("/half/:half", onRequestHalf);
So, it won't conflict with the other top level routes and it essentially has it's own URL scope all to itself.

Related

Express route: some routes are not recognised [duplicate]

I'm trying to wrap my head around my implementation of express.router() not triggering of the middleware function assigned to it.
I wrote a pretty big app and trying to add a few more endpoints to my path, but for some reason the 9th route gets loaded but does not trigger the function.
app.js
server.use(cors());
server.use(function (req, res, next) {
next();
});
server.use("/", express.static("./assets"));
server.use("/api", api);
server.use("/debug", debug);
server.use("/config", config);
server.use("/control", control);
server.use("/tools", files);
And this is where I declared my routes with the respective functions.
router.get("/teams", onGetTeams);
router.get("/players", onGetPlayers);
router.get("/achievements", getTop3);
router.get("/xpression", onXprPayload);
router.get("/snapshot", onRequestSnapshot);
router.get("/round-timeline", onRequestTimelinePayload);
router.get("/:half", onRequestHalf);
router.get("/dashboard-message", onSetDashboardMessage);
router.get("/get-match-odds", getTeamOdds);
function getTeamOdds(req, res) {
console.log("Sent odds");
res.json(odds);
res.end();
}
When I make the request for the last route, the function does not get executed, and I get back a 200 response.
Is there something big I'm missing?
Thank you !
Your route definition here:
router.get("/:half", onRequestHalf);
is a wildcard route that matches ALL routes so none of the routes after it will get called unless that specific route calls next() to continue routing.
Top level wildcard routes are problematic for this reason. I would suggest avoiding them. There are temporary work-arounds like moving their definition to be the last top level route definition, but they can still be limiting for defining future routes because they are so greedy.
My recommendation would be to not make it a top level route:
router.get("/half/:half", onRequestHalf);
So, it won't conflict with the other top level routes and it essentially has it's own URL scope all to itself.

Why middleware is getting called even when the mount path specified is not it's own?

I am new to node and express, trying to explore things. I made two middlewares both with their specified mount path, the MIDDLEWARE 2 is getting called even when the request is not for it.
The code written by me:
// middleware 1
app.use('/demo',function(req, res, next){
console.log("MIDDLEWARE 1 CALLED");
next();
});
// middleware 2
app.use('/', function(req, res, next){
console.log("MIDDLEWARE 2 CALLED");
next();
});
app.get('/demo',function(req, res){
console.log("Hello, How are you?");
});
And now in the browser, I type: localhost:8000/demo
In console I am getting this:
MIDDLEWARE 1 CALLED
MIDDLEWARE 2 CALLED
Hello, How are you?
My question is when I specify the path in request as /demo why does the second middleware gets called?However, when I type this: localhost:8000, it works as expected Only middleware 2 is called.
Where am I wrong in the first case?
Thanks in advance for any help you are able to provide.
Express' app.use will apply to every request with a path that starts with your entered path. Meaning app.use('/demo', ...) will apply to every route that starts with /demo, and app.use('/', ...) will apply to every route that starts with /, which obviously is every route.
If you only want to have it on the exact / path, maybe app.all('/', ...) could solve your issue as it only applies to the exact match but still for all HTTP methods.

difference between app.all('*') VS app.use(function)?

app.all('*', function(req, res, next) {
vs
app.use(function (req, res, next) {
Whats the difference? doesn't both take in each request to the server?
For the wildcard * path, there's really not much of a meaningful difference at all. It appears to me like the internal implementation may be slightly more efficient for app.use(fn), then app.all('*', fn). And, if you intend for it to run on all routes, then app.use() makes more logical sense to me since what you're really doing is middleware and that's what app.use() is specially designed for.
Summary for app.all('*', fn) vs. app.use(fn):
No difference in order of execution.
app.use() fires regardless of methods, app.all() only fires for parser supported methods (probably not relevant since the node.js http parser supports all expected methods).
Summary for app.all('/test', fn) vs. app.use('/test', fn):
No difference in order of execution
app.use() fires regardless of methods, app.all() only fires for parser supported methods (probably not relevant since the node.js http parser supports all expected methods).
app.use() fires for all paths that start with /test include /test/1/ or /test/otherpath/more/1. app.all() only fires if its an exact match to the requested url.x
Details
All route handlers or middleware that match a given route are executed in the order they were defined so app.all('*', fn) and app.use(fn) do not have any different ordering when placed in identical places in the code.
In looking at the Express code for app.all() it appears that the way it works is that it just goes through all the HTTP methods that the locally installed HTTP parser supports and registers a handler for them. So, for example, if you did:
app.all('*', fn);
The Express code would run these:
app.get('*', fn);
app.put('*', fn);
app.post('*', fn);
app.delete('*', fn);
// ...etc...
Whereas app.use() is method independent. There would be only one handler in the app router's stack that is called no matter what the method is. So, even if an unsupported http verb was issued and the parser let the request get this far, the app.use() handler would still apply whereas the app.all() handler would not.
If you use a path with both app.all() and app.use() that is not just a simple wildcard like '*', then there is a meaningful difference between the two.
app.all(path, fn) only triggers when the requested path matches the path here in its entirety.
app.use(path, fn) trigger when the start of the requested path matches the path here.
So, if you have:
app.all('/test', fn1); // route 1
app.use('/test', fn2); // route 2
And, you issue a request to:
http://yourhost.com/test // both route1 and route2 will match
http://yourhost.com/test/1 // only route2 will match
Because only middleware with app.use() fires for partial matches where the requested URL is contains more path segments beyond what is specified here.
So, if you intend to insert some middleware that runs for all routes or runs for all routes that are descended from some path, then use app.use(). Personally, I would only use app.all(path, fn) if I wanted a handler to be run only for a specific path no matter what the method was and I didn't not want it to also run for paths that contain this path at the start. I see no practical reason to ever use app.all('*', fn) over app.use(fn).

Express Framework app.post and app.get

I am fairly new to the express framework. I couldn't find the documentation for application.post() method in the express API reference. Can someone provide a few examples of all the possible parameters I can put in the function? I've read a couple sites with the following example, what does the first parameter mean?
I know the second parameter is the callback function, but what exactly do we put in the first parameter?
app.post('/', function(req, res){
Also, let's say we want the users to post(send data to our server) ID numbers with a certain format([{id:134123, url:www.qwer.com},{id:131211,url:www.asdf.com}]). We then want to extract the ID's and retrieves the data with those ID's from somewhere in our server. How would we write the app.post method that allows us to manipulate the input of an array of objects, so that we only use those object's ID(key) to retrieve the necessary info regardless of other keys in the objects. Given the description of the task, do we have to use app.get() method? If so, how would we write the app.get() function?
Thanks a lot for your inputs.
1. app.get('/', function(req, res){
This is telling express to listen for requests to / and run the function when it sees one.
The first argument is a pattern to match. Sometimes a literal URL fragment like '/' or '/privacy', you can also do substitutions as shown below. You can also match regexes if necessary as described here.
All the internal parts of Express follow the function(req, res, next) pattern. An incoming request starts at the top of the middleware chain (e.g. bodyParser) and gets passed along until something sends a response, or express gets to the end of the chain and 404's.
You usually put your app.router at the bottom of the chain. Once Express gets there it starts matching the request against all the app.get('path'..., app.post('path'... etc, in the order which they were set up.
Variable substitution:
// this would match:
// /questions/18087696/express-framework-app-post-and-app-get
app.get('/questions/:id/:slug', function(req, res, next){
db.fetch(req.params.id, function(err, question){
console.log('Fetched question: '+req.params.slug');
res.locals.question = question;
res.render('question-view');
});
});
next():
If you defined your handling functions as function(req, res, next){} you can call next() to yield, passing the request back into the middleware chain. You might do this for e.g. a catchall route:
app.all('*', function(req, res, next){
if(req.secure !== true) {
res.redirect('https://'+req.host+req.originalUrl);
} else {
next();
};
});
Again, order matters, you'll have to put this above the other routing functions if you want it to run before those.
I haven't POSTed json before but #PeterLyon's solution looks fine to me for that.
TJ annoyingly documents this as app.VERB(path, [callback...], callback in the express docs, so search the express docs for that. I'm not going to copy/paste them here. It's his unfriendly way of saying that app.get, app.post, app.put, etc all have the same function signature, and there are one of these methods for each supported method from HTTP.
To get your posted JSON data, use the bodyParser middleware:
app.post('/yourPath', express.bodyParser(), function (req, res) {
//req.body is your array of objects now:
// [{id:134123, url:'www.qwer.com'},{id:131211,url:'www.asdf.com'}]
});

Placeholder segments in express middleware mount points

When using Express I can define routes with a placeholder in the route string, something like:
app.get("/users/:user_id/photos", function(req,res){<blah>});
and then in my handler I can user req.params["user_id"] to get whatever was in the URL and use it in my request.
Middleware can be mounted at certain paths such that only requests matching that path will use the middleware. Can I use placeholders in the mount path of a middleware? For example, could I do something like:
app.use("/users/:user_id/photos", <middleware>);
and then inside the middleware have some way of accessing what the segment that maps to :user_id was?
EDIT 1:
I am aware that I can put the middleware directly in the route declaration, à la:
app.get("/users/:user_id/photos", <middleware>, function(req,res){<blah>});
It doesn't take much imagination to see how that would get out of hand as an app grows.
Middlewares are chaining in the order you add them.
middleware = function(req,res,next){
if(valid(req))
next();
else
res.send(400, "Emergerd");
}
// First middleware
app.get("/users/:user_id/photos", middleware);
app.get("/users/:user_id/photos", function(req,res){
// function after middleware
});

Resources