Express 4.x routing and capturing URL parameters [duplicate] - node.js

I'm not sure if this is a bug in Express, or if I'm just doing something wrong (probably the latter), but I'm finding that req.params is only retaining parameters in the final step of the request. To demonstrate what I mean:
Working Example:
router.get('/:id/test', function(req, res){
// req.params.id is not undefined
});
Doesn't Work :(
File 1:
router.use('/:id', require('./file2'));
File 2:
router.get('/test', function(req, res){
// req.params.id is undefined?!
});
Now... the above seems totally illogical to me, seeing as the Express generator defines routes in the above way - and it must still be defined in the path somewhere. Surely I should still be able to access "id"?
So basically, am I missing something? Is this deliberate/is it documented? FWIW I'm using Express v4.12.0.
Disclaimer: the file thing is probably irrelevant, but better to be safe than sorry.

When you create your Router in File 2, you need to tell it to inherit params from parents.
var router = express.Router({mergeParams: true});
http://expressjs.com/api.html#router

Related

NodeJS, express - routing

I´ve setup a little NodeJS API with 'expressjs'. In my code I have some similar code blocks looking like this:
app.get('/api/my/path', (req, res) => {
doSomethingUseful();
});
All thoses requests do something different, so the function being called is always different too.
I´m asking myself if this is good practice for writing code in NodeJS or not.
If there is a better / cleaner way of writing all those paths I would appreciate if you could tell me how or at least giving me a place to look for it.
EDIT 1: To be clear: I ask if it´s a good idea to write a lot of 'app.get(...)' into one source code file or if there is a better way?
Yes there is a better way than writing all routes in one file. For example, let us say you have routes for users and questions.
For users, you want get/set/put/delete for profile, and similarly for questions.So you create the following folder structure: /api/users and /api/questions
In /api/users,
const express=require('express')
const router=express.Router()
//this handles route: /users
router.get('/',(req,res)=>{})
//this handles route: /users/profile
router.get('/profile',(req,res){})
//this is to retrieve profile of specific user by user id :/users/profile/:userID
router.get('/profile/:userId',(req,res))
router.post('/profile',(req,res))
.
.
Then, in your index.js or entry point of your project,
const users=require('./api/users')
const questions=require('./api/questions')
app=require('express')
app.use('/users',users)
app.use('/questions',questions)
So in effect, you say for any /users route, refer to the users.js file, for any /questions routes, refer questions.js file and so on
Use a simple module, don't be invoking routes until you form a heap.
Try Route Magic
You want to do just 2 lines of code and have the module read your directory and file structure to handle all the app.use routing invocations, like this:
const magic = require('express-routemagic')
magic.use(app, __dirname, '[your route directory]')
For those you want to handle manually, just don't use pass the directory to Magic.

how to extract part of url server side in nodejs express

Currently working on a nodejs express server. And I think I'm doing something in an inefficient way. I have this route set up
app.get('/admin/scanTable/:table', require('./AUTH/ValidateCookie.js'), require('./AUTH/verifyURI.js'), require('./ROUTES/render.js'));
so the url here is /admin/scanTable/:table. I know I can get the whole path with req.route.path. I know I can use req.params.table to collect the table parameter. But the thing I don't know how to get is the first part of the path, in this case admin. I know I could get it by looking for / symbols and slicing the parts I need from req.route.path but I figure with all these functionalities that express has, there's probably a better way of doing this.
I know I can use
app.use('/admin', function(req, res, next){console.log('admin called'), next();});
to check if this part of the uri was called to then execute some code, but it's not really what I want. Can anyone tell me the easiest way to find this? At the moment I have attached a variable to req.string whenever app.use('/admin' is called it will attach the string admin to this variable which then makes it available to all other functions that are called. But even this feels like overkill. Any Ideas?
Both options you describe are valid and straightforward:
Using a regex on req.route.path, a la /^admin/.test(req.route.path)
Using middleware to attach a new property to the req object, a la
app.use('/admin', function(req, res, next){ req.adminRoute = true; next();});
or if you need to do this same thing for all admin routes, do it once:
var adminRouter = require("express").Router();
router.get("/scanTable/:table", require("./AUTH/ValidateCookie.js"), ...);
router.use(function (req, res, next) { req.adminRoute = true; next(); }));
app.use("/admin", adminRouter);
I don't know the context of your application, but I would consider using the last example, and putting anything else that's specific to /admin routes as middleware also.

Express Router undefined params with router.use when split across files

I'm not sure if this is a bug in Express, or if I'm just doing something wrong (probably the latter), but I'm finding that req.params is only retaining parameters in the final step of the request. To demonstrate what I mean:
Working Example:
router.get('/:id/test', function(req, res){
// req.params.id is not undefined
});
Doesn't Work :(
File 1:
router.use('/:id', require('./file2'));
File 2:
router.get('/test', function(req, res){
// req.params.id is undefined?!
});
Now... the above seems totally illogical to me, seeing as the Express generator defines routes in the above way - and it must still be defined in the path somewhere. Surely I should still be able to access "id"?
So basically, am I missing something? Is this deliberate/is it documented? FWIW I'm using Express v4.12.0.
Disclaimer: the file thing is probably irrelevant, but better to be safe than sorry.
When you create your Router in File 2, you need to tell it to inherit params from parents.
var router = express.Router({mergeParams: true});
http://expressjs.com/api.html#router

Express 4 route handling with named parameters and router.param()

Is there a clean way to handle key/value query params in Express 4 routes?
router.route('/some/route?category=:myCategory')
I want to detect the presence of 'myCategory' in this route and use router.param([name], callback) to handle the associated logic.
router.param('myCategory', function(req, res, next, id) {
/* some logic here... */
});
The above 'router.param()' works fine if I have a route like /some/route/:myCategory but fails if I use
router.route('/some/route?category=:myCategory')
Am I doing something wrong here, or is this not supported in the Express 4 router out of the box?
Express treats properties after a ? as query params. So for:
/some/route?mycategory=mine
you would have to use:
req.query.mycategory or req.query['mycategory']
See this for more examples.

Safe to append to req parameter?

In express, when I use routing middleware, is it OK to append to the request object? Or is it a bad pattern? Alternatives? Thanks.
app.get('/', getLayout, function(req, res){
if(req.layout == 'simple') ...render simple layout...
else ...render full layout...
});
where
getLayout = function(req, res, next){
req.layout = (req.params.blah == 'blah') ? 'layout_simple' : 'layout_full';
next();
}
I don't see why you shouldn't.
I do it a lot.
I am under the impression this is what middleware typically does.
From the express docs:
http://expressjs.com/guide.html#route-middleware
They set req.user in their middleware as the current user.
I agree with j_mcnally that this is a fine pattern as long as you don't go overboard. Specifically, I append most things that are more closely related to the response to the res object. This would be things like layout info, HTML fragments, my intermediate jsdom env representation of the response, etc. For req, tacking on things that are representations of query string or request body info makes sense. This would be things like input parameters, parsed search queries, the current user object, etc.
The express docs suggest it's somewhat a standard practice:
http://expressjs.com/guide.html#route-middleware
But it can significantly effect performance because of the way V8 works:
http://blog.tojicode.com/2012/03/javascript-memory-optimization-and.html
http://www.scirra.com/blog/76/how-to-write-low-garbage-real-time-javascript

Resources