Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Input validation, sanitization and service layer

I'm trying to keep my controller actions as lightweight as possible so i am implementing service layer. Now i've stucked with validation and sanitization. I know that validation should be done in service layer but what about sanitization? I would like to re-render the with the input data when there are validation errors.

//userService.js function
function register(data, callback) {
    if (!data) {
        return callback(new Error('Here some error...'));
    }

    /* Sanitize and validate the data */

    /* Method #1 */
    //If not valid then call back with validationErrors
    if (notValid) {
        return callback({
            validationErrors: {
                'username': 'Username is already in use.',
                'email': 'Invalid characters.',
            }
        });
    }

    /* Method #2 */
    if (notValid) {
        return callback({
            fields: {
                //We put here a sanitized fields

            },
            validationErrors: {
                'username': 'Username is already in use.',
                'email': 'Invalid characters.',
            }
        });
    }

};


//userController.js function
// GET/POST: /register
function registerAction(request, response, next) {
    if (request.method === 'POST') {
        var registerData = {
            username: request.body['username'],
            password: request.body['password'],
            email: request.body['email'],
            firstName: request.body['firstName'],
            lastName: request.body['lastName'],
        };

        register(registerData, function(error, someDataIfSucceed) {
            if (error) {
                //Re-post the data so the user wont have to fill the form again

                //Sanitize registerData variable here.

                return response.render('register', {
                    error: error,
                    validationErrors: error.validationErrors
                });
            };

            //User registered succesfully.
            return response.render('registerSuccess');
        });

        return;
    }

    return response.render('register');
}

I see there 2 options.

  1. Call service function 'register' with raw POST data, sanitize and validate it then push back only validation errors. If there are validation errors then sanitize them in controller before rendering the view.
  2. Same as first one but we push back validation errors and sanitized fields.
like image 653
RlyDontKnow Avatar asked Feb 15 '23 14:02

RlyDontKnow


2 Answers

If you're using Express, an interesting option is:

  • Create a middleware and use it as a validation layer, using express-validator, which is based on node-validator. For example (see node-validator documentation for all validation/sanitization options):

    exports.validate = function(req, res, next) {
    
      req.assert('username').notEmpty();
      req.assert('password').notEmpty();
      req.assert('email').isEmail();
      req.assert('firstName').len(2, 20).xss();
      req.assert('lastName').len(2, 20).xss();
    
      var errors = req.validationErrors(true);
    
      if (errors){
        res.status(400).json({ status: 'ko', errors: errors });
      }
      else {
        next();
      }
    
    }
    
  • Then, in your controller, simply obtain the validated request params and run the sign up logic (your register function call and response rendering),

IMHO, this way you can keep your code more clean and decoupled.

like image 113
xmikex83 Avatar answered Feb 17 '23 19:02

xmikex83


If it's a small project don't bother, just do what works.

If, however, it is a large (read: long-lived) project, then:

If by "sanitization" you mean HTTP/HTML sanitization (or inputs, or of display messages), then this belongs in the controller. Think about it this way: the controller may not be the only place where you pass input to your service layer from. In the future you might have API access to the service. Or a test driver may invoke it directly, without going thru HTTP. So HTTP/HTML is just the transport, and as such logic specific to it should be outside of the service.

If, however, by "sanitization" you mean business-logic sanitization (e.g.: you don't allow non-existing country codes), then by all means this should be in the service, for exactly the same reasons.

like image 37
Nitzan Shaked Avatar answered Feb 17 '23 20:02

Nitzan Shaked