express icon indicating copy to clipboard operation
express copied to clipboard

Allow for multiple parameter names in router.param()

Open markg85 opened this issue 6 years ago • 6 comments

Hi,

I just found out about router.param() and immediately started using it in my code. It makes checks based on parameters so darn clean :) Really good job on the inventor of that idea!

While using it i found myself wondering with a url like: "/:year/:month/:day". How can you make a router.param(...) function that is called when exactly those 3 arguments have been provided in the url? Perhaps it is possible, but i haven't seen a way in the documentation.

Since router.param() works on parameter names, i would suggest a feature like the following to allow for an implementation of the above to be possible in router.param().

router.param(['year', 'month', 'day'], (req, res, next, obj) => {
   obj.year; // contain the year value
   obj.month; // contain the month value
   obj.day; // contain the day value
});

I would say that the first array in which the params are provided as string must be the exact order in which they would occur in the app.get('/:year/:month/:day' ...) function;

Is there any technical (or practical) reason why a feature like this wouldn't be possible? What are your thoughts on this?

Best regards, Mark

markg85 avatar Jul 30 '17 19:07 markg85

He @markg85 Can i have some other Details LIke your Total api structure so that I can work with my local Express.js Server

MuthukumarHelios avatar Aug 03 '17 08:08 MuthukumarHelios

He @markg85 Can i have some other Details LIke your Total api structure so that I can work with my local Express.js Server

What do you mean? I have no further details? The topic i started is a feature request :) I don't have an implementation for that request.

markg85 avatar Aug 03 '17 08:08 markg85

Having briefly looked into the source code of router.param() (which is proto.param() in router/index.js), I noticed that all current router.param() did is push the callback on the router.params[paramName] array, and does nothing else. router.handle(), a not documented method, does the actual work. It calls another internal method router.process_params(), that actually invokes the pushed callbacks on each parameter one by one, sequentially without repeat. From index.js:

proto.process_params = function process_params(layer, called, req, res, done) {  
    var params = this.params;
    //...
    function param() {
        //...
        key = keys[i++];
        name = key.name;
        //...
        paramCallbacks = params[name];
        //...
        paramCallback();
    }
    function paramCallback(err) {
        var fn = paramCallbacks[paramIndex++];
        //...
        if (!fn) return param();
        
        try {
            fn(req, res, paramCallback, paramVal, key.name);
        } catch (e) {
            paramCallback(e);
        }
    }

    param();
}    

I believe to add the feature you asked may require changing these structures, and I don't feel of that much necessity if you can just give the job to a normal app.use() like methods.

kevinkassimo avatar Aug 03 '17 09:08 kevinkassimo

@kevinkassimo Thank you for your response! Could you provide an example for the app.use() version of a "/:year/:month/:day" structure? I don't see how to do that, but that is likely due to just not knowing about it :)

markg85 avatar Aug 07 '17 09:08 markg85

@markg85 req.params will serve as the obj you wanted in normal path matching methods. Thus I believe something like

app.get("/:year/:month/:day", function (req, res, next) {
  req.params["year"];
  req.params.month;
  req.params.day
  //...
  next();
})

should be good enough. (I should have said app.METHOD(), as app.use() is more likely for middleware and does prefix matching.)

kevinkassimo avatar Aug 07 '17 10:08 kevinkassimo

It would be good to have the router.param() accepting multiple middlewares, that will permit us to split our middleware

example:

router.param('userId', 
	(req: Request, res: Response, next: NextFunction) => {
	  // Common middleware validating the data
	},
	(req: Request, res: Response, next: NextFunction) => {
	  // Middleware to assign the data, etc...
	}
)

oktapodia avatar Dec 07 '20 15:12 oktapodia