Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node.js middleware organization and parameter validation

I'm building an express app and I'd like to know how fancy I can get with middleware. Roughly, I want to accomplish the following with middleware.

Done:

  • Add requestId to all routes
  • Authenticate request
  • Check whether a user has access to a given resource (apart from authentication)

Not done:

  • A) Validate parameters for a given route
  • B) Organize middleware in a sane way if it differs from route to route, and 3 middlewares are called routinely per route

I have defined my middleware in a separate file, and import it into app.js like so:

var middleware = require('./middleware');
var requestId = middleware.requestId;
var authenticate = middleware.authenticate;

To apply it to all routes I add it to express config:

var app = express.createServer();
app.configure(function () {
  app.use(express.logger());
  app.use(express.cookieParser());
  app.use(express.bodyParser());
  app.use(requestId); // add requestId to all incoming requests
});

And for route specifics, I add it as an app.get argument:

var routes = require('./v1/routes');
app.get("/v1/foo", routes.foo);
app.get("/v1/bar", authenticate, routes.bar);

Problem A

I'd love to have middleware that I could use to check parameters

validate('x','y','z')

And use it like so for a given route:

app.get("/v1/bar", authenticate, validate('x','y','z'), routes.bar);

Is there a good way to do this? Or should I just be validating on per route basis inside the route definition files?

Problem B

Is there a better way to organize and use my middleware that I should consider?

Update

I'm looking for a way to validate parameters that change a lot between routes. The below obviously don't work- I cannot pass params into the middleware- but is there way where I can define middleware that does this and call it as I've said above?

var validateParams = function (req, res, params, callback) {
  // Make sure the required parameters are in the request
  console.log('checking for params '+params);
  for (var i = 0; i < params.length; i++) {
    var param = params[i];
    if(!(param in req.query)){
      logger.info('cannot find param ['+param+'] in req: '+JSON.stringify(req.query));
      res.writeHead(400, {
        "Content-Type": "application/json"
      });
      var out = {
        "err": "request missing required parameters"
      };
      res.end(JSON.stringify(out));
      return;      
    }
  }
  callback();
}
like image 788
nflacco Avatar asked Sep 23 '12 02:09

nflacco


1 Answers

Problem A

app.get("/v1/bar", authenticate, validate, routes.bar);

function validate(req,res,next){

//Get all parameters here by req.params and req.body.parameter
//validate them and return.
if(validation_true)
next()
}

Problem B

You can use middleware in a way that you don't always need to call authenticate and validate they are called automatically. But that can lead to a mess, for ex. Your middleware then would run on every call, so for SIGNUP/REGISTER there is no point running authenticate.

With validate, sometimes you would need to validate email, sometimes phone no. so both cannot go along.

So using them separate on every call seems the BEST way to me.

like image 196
Hitesh Joshi Avatar answered Dec 07 '22 01:12

Hitesh Joshi