4

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.
1
  • There isn't a right answer to this, which one works best for your needs? Commented Nov 24, 2013 at 16:14

2 Answers 2

5

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.

Sign up to request clarification or add additional context in comments.

1 Comment

This is how i'm doing validation for small projects but now i would have to validate the parameters in controller and then once again at the service. I've added service layer because in the future i'm gonna add support for different protocols, so validating input in service layer is more DRY. Thank you for the reply : )
4

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.

1 Comment

Thanks for the reply. It's not small project. By sanitization i mean html escaping the input and stuff like that (non business logic). I think i'm going for option #1. I will just simple sanitize (html escape) all input fields and push them back to the view.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.