It's a little hard to explain this in text. I apologise if I am not clear. I am using express v4.14.
// main.js - Defines app
var app = require("express")();
app.use("/order/job", require("./job").router);
app.use("/order", require("./order").router);
app.use(function (req, res) {
res.sendStatus(204); // All middleware requests will end here
});
// job.js - Defines the routes for job
var router = require("express").Router();
module.exports.router = router;
router.get("/:jobId", mw_job); // Full url is /order/job/:jobId
// order.js - Defines routes for order
var router = require("express").Router();
module.exports.router = router;
router.get("/:orderId", mw_order); // Full url is /order/:orderId
:jobIdmw_job will be executed.mw_order will be executed, even though the URL is not an exact match.mw_order is /order/:orderId, hence :orderId in this case is jobAs I am using require("express").Router(), there is no matter of precedence in the routes.
Question: Is there any way where I can stop mw_order from executing? I will still prefer to use the router instance because I have this scenario:
// main.js
var app = require("express")();
app.use("/order", require("./order").router);
app.use(function (req, res) {
res.sendStatus(204); // All middleware requests will end here
});
// order.js
var router = require("express").Router();
module.exports.router = router;
router.get("/:orderId", mw_order); // Full url is /order/:orderId
router.get("/:orderId", mw2_order); // Added - This is expected to be executed after mw_order
Hi @iamjoyce I'm trying to reproduce your issue, but even after setting up the code you provided (and I filled in what I made a guess for your mw_job and mw_order since you didn't provide an implementation), I'm unable to.
Here is a log of my console:
$ npm i [email protected]
+ [email protected]
added 1 package and updated 11 packages in 1.7s
$ cat main.js
// main.js - Defines app
var app = require("express")();
app.use("/order/job", require("./job").router);
app.use("/order", require("./order").router);
app.use(function (req, res) {
res.sendStatus(204); // All middleware requests will end here
});
app.listen(3000);
$ cat job.js
// job.js - Defines the routes for job
var router = require("express").Router();
module.exports.router = router;
router.get("/:jobId", mw_job); // Full url is /order/job/:jobId
function mw_job(req, res) {
res.send('response sent from mw_job');
}
$ cat order.js
// order.js - Defines routes for order
var router = require("express").Router();
module.exports.router = router;
router.get("/:orderId", mw_order); // Full url is /order/:orderId
function mw_order(req, res) {
res.send('response sent from mw_order');
}
$ node main.js &
[1] 79737
$ curl http://127.0.0.1:3000/order/job/testing123
response sent from mw_job
You can see that the request I made to your app for /order/job/testing123 only ran the mw_job code. Can you provide any additional details? Not sure how to proceed on my end.
Hi @dougwilson Thank you very much, I apologise for the lack of details.
Can you modify your files as such -
// main.js - Defines app
var app = require("express")();
app.use("/order/job", require("./job").router);
app.use("/order", require("./order").router);
app.use(function (req, res) {
res.json(req.reply); // All middleware requests will end here
});
app.listen(3000);
// job.js - Defines the routes for job
var router = require("express").Router();
module.exports.router = router;
router.get("/:jobId", mw_job); // Full url is /order/job/:jobId
function mw_job(req, res, next) {
// res.send('response sent from mw_job');
req.reply = 'response sent from mw_job';
next();
}
// order.js - Defines routes for order
var router = require("express").Router();
module.exports.router = router;
router.get("/:orderId", mw_order); // Full url is /order/:orderId
function mw_order(req, res, next) {
// res.send('response sent from mw_order');
req.reply = 'response sent from mw_order';
next();
}
curl http://127.0.0.1:3000/order/job/testing123 will then give you _response sent from mw_order_ instead of _mw_job_.
Hi @iamjoyce unfortunately I had to fill in some additional code, as the code you provided gave the error ReferenceError: next is not defined. After I got it into a runnable state I still got response sent from mw_job, not the mw_order like you did. Can you point out what is different here? How were you able to run the code without getting the ReferenceError: next is not defined that I got? It's possible that the modifications I did is what is making our outcomes different, which is why I'm wondering.
Can you paste out your console to me just the same way I'm doing? That may help a lot.
$ npm i [email protected]
+ [email protected]
added 42 packages in 4.069s
$ cat main.js
// main.js - Defines app
var app = require("express")();
app.use("/order/job", require("./job").router);
app.use("/order", require("./order").router);
app.use(function (req, res) {
res.json(req.reply); // All middleware requests will end here
});
app.listen(3000);
$ cat job.js
// job.js - Defines the routes for job
var router = require("express").Router();
module.exports.router = router;
router.get("/:jobId", mw_job); // Full url is /order/job/:jobId
function mw_job(req, res, next) {
// res.send('response sent from mw_job');
req.reply = 'response sent from mw_job';
next();
}
$ cat order.js
// order.js - Defines routes for order
var router = require("express").Router();
module.exports.router = router;
router.get("/:orderId", mw_order); // Full url is /order/:orderId
function mw_order(req, res, next) {
// res.send('response sent from mw_order');
req.reply = 'response sent from mw_order';
next();
}
$ node main.js &
[1] 7461
$ curl http://127.0.0.1:3000/order/job/testing123
"response sent from mw_job"
Hi @dougwilson, thank you very much for your patience. I guarantee this code is correct -
// main.js - Defines app
var app = require("express")();
app.use("/order/job", require("./job").router);
app.use("/order", require("./order").router);
app.use(function (req, res) {
res.json(req.reply); // All middleware requests will end here
});
app.listen(3000);
// job.js - Defines the routes for job
var router = require("express").Router();
module.exports.router = router;
router.get("", mw_job); // Full url is /order/job
function mw_job(req, res, next) {
console.log("mw_job invoked");
req.reply = "response sent from mw_job";
next();
}
var router = require("express").Router();
module.exports.router = router;
router.get("/:orderId", mw_order); // Full url is /order/:orderId
function mw_order(req, res, next) {
console.log("mw_order invoked");
req.reply = "response sent from mw_order";
next();
}
$ curl http://127.0.0.1:3000/order/job/
"response sent from mw_order"
Hi @iamjoyce hmm, weird indeed. This time when I coped your code above and ran the server and did the curl command, it gave no error, and _an empty response_, so I'm _still_ not getting the response sent from mw_order like you. Can you point out where I went a-miss in the log of my console below? Perhaps you can provide the same kind of console capture of your session as well?
$ npm i [email protected]
+ [email protected]
added 42 packages in 4.012s
$ cat main.js
// main.js - Defines app
var app = require("express")();
app.use("/order/job", require("./job").router);
app.use("/order", require("./order").router);
app.use(function (req, res) {
res.json(req.reply); // All middleware requests will end here
});
app.listen(3000);
$ cat job.js
// job.js - Defines the routes for job
var router = require("express").Router();
module.exports.router = router;
router.get("", mw_job); // Full url is /order/job
function mw_job(req, res, next) {
console.log("mw_job invoked");
req.reply = "response sent from mw_job";
next();
}
$ cat order.js
var router = require("express").Router();
module.exports.router = router;
router.get("/:orderId", mw_order); // Full url is /order/:orderId
function mw_order(req, res, next) {
console.log("mw_order invoked");
req.reply = "response sent from mw_order";
next();
}
$ node main.js &
[1] 14716
$ curl http://127.0.0.1:3000/order/job/testing123
Hi @dougwilson, I am very very sorry, the URL is supposed to be without testing123
$ curl http://127.0.0.1:3000/order/job/
Basically I have two URLs,
job.js http://127.0.0.1:3000/order/joborder.js http://127.0.0.1:3000/order/:orderIdAn order can have one or many jobs, which is why the URL is in this way.
I have modified job.js to be clearer on what's the final goal.
curl http://127.0.0.1:3000/order/job/mw_job, (2) mw2_job, (3) mw_order are invoked. (Incorrect)mw_job, (2) mw2_job will be invoked.curl http://127.0.0.1:3000/order/testing123/ (:orderId = "testing123")mw_order is invoked. (Correct)// main.js - Defines app
var app = require("express")();
app.use("/order/job", require("./job").router);
app.use("/order", require("./order").router);
app.use(function (req, res) {
res.json(req.reply); // All middleware requests will end here
});
app.listen(3000);
// job.js - Defines the routes for job
var router = require("express").Router();
module.exports.router = router;
router.get("", mw_job); // Full url is /order/job
router.get("", mw2_job); // <------ Added
function mw_job(req, res, next) {
console.log("mw_job invoked");
req.reply = "response sent from mw_job";
next();
}
function mw2_job(req, res, next) {
console.log("mw2_job invoked");
req.reply = "response sent from mw2_job"; // This line will overwrite req.reply from mw_job
next();
}
// order.js - Defines routes for order
var router = require("express").Router();
module.exports.router = router;
router.get("/:orderId", mw_order); // Full url is /order/:orderId
function mw_order(req, res, next) {
console.log("mw_order invoked");
req.reply = "response sent from mw_order";
next();
}
$ curl http://127.0.0.1:3000/order/job/
"response sent from mw_order"
Ah, I see now. Sorry, I didn't see the URL; I kept seeing the one with the testing123 for some reason. Ultimately your issue is in your use of "next()"; you see, when you call "next()", you are declaring that the code didn't want to finish off the request, that the next things in line should complete the request handling. You need to use res.send() or similar when you want to respond and don't call next instead of storing the response in req.reply and calling "next()", otherwise when you make route definitions that apply to more than one URL (as in your case), they will both always execute.
In your example job.js file, you have
router.get("", mw_job); // Full url is /order/job
router.get("", mw2_job); // <------ Added
... which both will always match the same URL, so of course mw2_job will run that URL if mw_job called "next()".
I hope that helps!
From what I can see, this isn't a bug, so if you are looking for support or discussions around how to implement something, please stop by our support channel: https://gitter.im/expressjs/express
And mw_order is also called in your case because the path for that is set to "/order/:orderId", which means /order/job/ will match it, since ":orderId" is just anything in that segment. You can do a few things for that case:
(1) Add a guard in mw_order to "if (req.params.orderId === 'job') return next();"
(2) Declare the ":orderId" parameter on the router and code in what you expect to be a valid ":orderId" like "router.param("orderId", function (req, res, next, orderId) { if (orderId === 'job') next('route') else next() })" (see http://expressjs.com/en/4x/api.html#router.param)
(3) If you want the trailing slash to matter in the routing, enable strict routing mode "router = require('express').Router({ strict: true })" (see http://expressjs.com/en/4x/api.html#express.router)