Handling different routes that start similarly in NodeJS, Express - node.js

I'm creating an API which have Articles and Comments belonging to those articles.
const articleRoutes = require('./api/routes/articles');
const commentRoutes = require('./api/routes/comments');
then
app.use('/articles', articleRoutes);
app.use('/comments', commentRoutes);
Anything starting with "articles/" gets forwarded to articleRoutes, and anything starting with "comments/" gets forwarded to commentRoutes.
Comment GET requests are like
/comments?article=ID_OF_ARTICLE
Like this everything is working perfectly.
However
I want to restructure the comments route to be like
/articles/ID_OF_ARTICLE/comments
However now they both start with "/articles"
How would I deal with this?

I would try the following:
app.use('/articles/:id/comments', commentRoutes);
app.use('/articles', articleRoutes);
So I think the order is important in the above.
// inside commentRoutes
Router.get('/', (req, res) => {
let articlesId = req.originalUrl.split('/')[2]
})
I hope this helps

The originalUrl approach seems to work too, But I went with the solution here
Apparently I can do
app.use('/articles/:articleId/comments', function(req, res, next) {
req.articleId = req.params.articleId;
next();
}, commentRoutes);
and in commentRoutes
// in commentRoutes
router.get('/', (req, res, next) => {
let articleId = req.articleId
})
So I can attach the required parameter to the request as a separate entry and access it directly

Related

How to pass one of multiple middleware nodejs

I have a router like this
router.post("/roomplayers",[authjwt.verifyTokenAdmin,authjwt.finishedRoomManagement,authjwt.activeRoomManagement],
RoomController.findPlayers)
and I would to get the controller RoomController.findPlayers if the admin have this cofinishedRoomManagementdepermission
OR this activeRoomManagement
How can I do that
If your question is how to pass through many middleware's in your route the solution is below.
const tokenMiddleWare = (req, res, next) =>{
//Your code here
next();
}
const isAdminMiddleWare = (req, res, next)=>{
//Your code here
next();
}
So now that we have two middlewares and one controller(I omitted it though) now you can work on route and pass those middlewares and controller but before I start I want point something important
So with the next you want to push the user down out of the middleware driving them closer to the route that they want to hit only when they meet all you validation that's when you want to push them down
router.post('/api/login', tokenMiddleWare, isAdminMiddleWare, (req, res)=>{
authController.login(req, res);
})
Now this would be how you pass down multiple middlewares and using your controller

Express 4: router syntax

I am using Express 4 with the new router. At least one thing continues to confuse me, and it is a syntax problem - I am wondering if there is a regex that can do what I want. I have a standard REST api, but I want to add batch updates, so that I can send all the info to update some users models with one request, instead of one PUT request per user, for example. Anyway, I currently route all requests to the users resources, like so:
app.use('/users, userRoutes);
in userRoutes.js:
router.get('/', function (req, res, next) {
//gets all users
});
router.put('/:user_id', function (req, res, next) {
//updates a single user
});
but now I want a route that captures a batch request, something like this:
router.put('/Batch', function (req, res, next) {
//this picks up an array of users from the JSON in req.body and updates all
});
in other words, I want something which translates to:
app.use('/usersBatch, function(req,res,next){
}
...but with the new router. I can't get the syntax right.
I tried this:
app.use('/users*, userRoutes);
but that doesn't work. Does anyone know how to design this?
I'm guessing that the call to [PUT] /users/Batch is being picked up by the [PUT] /users/:user_id route. The string /:user_id is used as a regular expression causing it to also collect /Batch.
You can either move /Batch before /:user_id in the route order, refine the regex of /:user_id to not catch /Batch or change /Batch to something that won't get picked up too early.
(plus all the stuff Michael said)
REST doesn't include a POST as a list syntax. That's because each URL in REST point to an individual resource.
As an internet engineer I haven't seen any bulk PUTs or POSTs, but that said, it's your app, so you can make whatever API you like. There are definitely use cases for it.
You'll still need to describe it to Express. I would do it like this:
var express = require('express');
var router = express.Router();
router.get('/', function (req, res) {}); // gets all users
router.post('/:user_id', function (req, res) {}); // one user
router.put('/:user_id', function (req, res) {}); // one user
router.patch('/:user_id', function (req, res) {}); // one user
router.delete('/:user_id', function (req, res) {}); // one user
app.use('/user', router); // Notice the /user/:user_id is *singular*
var pluralRouter = express.Router();
pluralRouter.post('/', function (req, res) {
// req.body is an array. Process this array with a foreach
// using more or less the same code you used in router.post()
});
pluralRouter.put('/', function (req, res) {
// req.body is another array. Have items in the array include
// their unique ID's. Process this array with a foreach
// using +/- the same code in router.put()
});
app.use('/users', pluralRouter); // Notice the PUT /users/ is *plural*
There are other ways to do this. Including putting comma-delimited parameters in the URL. E.g.
GET /user/1,2,3,4
But this isn't that awesome to use, and vague in a PUT or POST. Parallel arrays are evil.
All in all, it's a niche use case, so do what works best. Remember, the server is built to serve the client. Figure out what the client needs and serve.

Routing in Express.js

I am currently express router in Node.js and having a problem like below. Let's say I have two url; one is to get a user info and one is to register users to an application.
http://example.com/users/:idUser (this will give a information of a user)
http://example.com/users/registration (this will allow a user registration)
The problem I have facing is when I call registration, the router is working with idUser; so I had to edit like user/registration instead of users. If I want to use as users/registration, which kinds of work do I have to do. I am still a newbie in Node.js.
Thanks.
You need to order the routes appropriately so that the registration route comes before.
app.get('/users/registration', function(req, res, next) {
....
});
app.get('/users/:userId', function(req, res, next) {
....
});
Just invert the order, like this:
app.get('/users/registration', function(req, res, next) {
...
});
app.get('/users/:userId', function(req, res, next) {
...
});

In express how do I redirect a user to an external url?

I have a payment system using node.js and braintree, when the payment is successful I want to send the user to the back end. My back end is setup elsewhere.
I have tried
res.writeHead(301,
{Location: 'http://app.example.io'}
);
res.end();
So window.location is obviously not available. I cant think of any ways to redirect a user?
You can do
res.redirect('https://app.example.io');
Express docs: https://expressjs.com/en/api.html#res.redirect
The selected answer did not work for me. It was redirecting me to: locahost:8080/www.google.com - which is nonsense.
301 Moved Permanently needs to be included with res.status(301) as seen below.
app.get("/where", (req, res) => {
res.status(301).redirect("https://www.google.com")
})
You are in the same situation since your back-end is elsewhere.
app.get("/where", (req, res) => {
res.status(301).redirect("https://www.google.com")
})
You need to include the status (301)
I just have the same issue and got it work by adding "next". I use routers so maybe you have same issue as mine? Without next, i got error about no render engine...weird
var express = require('express');
var router = express.Router();
var debug = require('debug')('node_blog:server');
/* GET home page. */
router.get('/', function(req, res, next) {
debug("index debug");
res.render('index.html', { title: 'Express' });
});
router.post("/", function (req, res, next) {
//var pass = req.body("password");
//var loginx = req.body("login");
//res.render('index.html', { title: 'Express' });
res.redirect("/users")
next
});
module.exports = router;
None of these worked for me, so I tricked the receiving client with the following result:
res.status(200).send('<script>window.location.href="https://your external ref"</script>');
Some will say if noscript is on this does not work, but really which site does not use it.

forwarding to another route handler without redirecting in express

I have the following code :
app.get('/payment', function(req, res) {
// do lots of stuff
});
now I want to add the following :
app.post('/payment', function(req, res) {
req.myvar = 'put something here';
// now do the same as app.get() above
});
Obviously I want to reuse the code. I tried doing next('/payment') inside the post handler and put it above the get handler, but no luck, probably because they are different VERBs.
What are my options ?
Thanks.
Just lift out the middleware to its own function and use it in both routes.
function doLotsOfStuff (req, res) {
// do lots of stuff
}
app.get('/payment', doLotsOfStuff);
app.post('/payment', function(req, res, next) {
req.myvar = 'put something here';
next();
}, doLotsOfStuff);

Resources