Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save bookercodes/1db4484fa9cdfe40b7cc to your computer and use it in GitHub Desktop.
Save bookercodes/1db4484fa9cdfe40b7cc to your computer and use it in GitHub Desktop.
I will put this on my blog once it is up and running.

In this tutorial I will teach you how to validate user input using an Express middleware module called express-validator.

express-validator is built on top of another open-source library called validator. validator is basically a library of validation functions. Some of it's popular functions include isEmail and isNumeric but you can see a full list here. express-validator makes all the functions in validator available in a way that works nicely with Node and Express.

###Installation

Installing express-validator is easy when you use npm. Just input the following command:

npm install express-validator

This will download the latest version of the express-validator npm package.

Once the download has finished, if you look inside of the "node_modules" folder, you'll see that express-validator has a transitive dependency on validator.

###Configuration

I am going to assume that you have an "app.js" file whose contents look something like this:

// dependencies
var express = require('express');
var bodyParser = require('body-parser');

var app = express();

// middleware
app.use(bodyParser.urlencoded({ extended: false }));

(If you do not, you can quickly create a application skeleton using express generator.)

express-validator is simply another middleware module. You hook it up exactly like you would any other middleware, like this:

// dependencies
var express = require('express');
var bodyParser = require('body-parser');
var validator = require('express-validator');

var app = express();

// middleware
app.use(bodyParser.urlencoded({ extended: false }));
app.use(validator());

There is only one thing you need to watch out for and that is, you must “use” express-validator immediately after you “use” the body parser middleware otherwise the middleware might not work.

###Validation

Imagine that you have a handler function like this one:

app.post('/pages/create', function(req, res) {
});

And that the request body looks like this:

{
  leader_email: "[email protected]",
  leader_mobile_no: "017171",
  team_twitter: "http://twitter.com/teamA",
  member_count: 10,
  page_color: "#FFFFFF",
  page_accent_colour: "#FFFFFF"
}

Here we want to validate that

  • leader_email is a valid email address*
  • leader_mobile_no is a valid UK mobile phone number
  • team_twitter is a valid Twitter handle
  • member_count is both a number and divisble by 2
  • page_color and page_accent_color are valid hex color codes

* Remember. Validation is not the same as verification. Validation merely confirms that the email is in the correct format. Verification confirms that that the user has access to the email. If you need to verify the email, consider sending a verification email.

Validating an email is a common requirement so I will start there. Inside of the handler function that I mentioned earlier, call a function called checkBody and pass to that function the name of the input element and the desired error message:

req.checkBody("leader_email", "Enter a valid email address.");

Next, chain onto that function call another function call to one or more functions from the validator library. In this case, we will use the isEmail validation function:

req.checkBody("leader_email", "Enter a valid email address.").isEmail();

The checkBody function is made available by the express-validation middleware. You can also check the query string using checkQuery or the params using checkParams. See the documentation for more information on that.

Hopefully now you can see why express-validator being built on validator is not merely an implementation detail. You almost always end up calling functions from the validator library of validation functions. You can see a full list of validation functions here.

Here is how I would validate the remaining input elements:

req.checkBody("leader_email", "Enter a valid email address.").isEmail();
req.checkBody("leader_mobile_no", "Enter a valid UK phone number.").isMobilePhone("en-GB");
req.checkBody("team_twitter", "Enter a valid Twitter URL").optional().matches("http://twitter.com/*");
req.checkBody("contestant_count", "Contestant count must be a number and one that is divisible by 2").isNumber().isDivisibleBy(2);
req.checkBody("page_color", "Page colour must be a valid hex color").isHexColor();
req.checkBody("page_color_accent", "Page colour accent must be a valid hex color").isHexColor();

Notice how I call a function called optional before calling the matches function, which matches an arbitrary regular expression. The optional function says “this value is optional so do not attempt to validate it unless the user actually entered a value”.

Also notice that in the case of the contestant_count_input we chained two validation functions.

Now that we have defined our validation rules, we need to determine whether the input adheres to them. If not, we need to cease execution and show the user the errors.

To determine whether the input is valid or not, call a function called validationErrors. If this function returns no errors, the input is valid; otherwise, it is invalid and we must show the returned errors to the user:

var errors = req.validationErrors();
if (errors) {
  res.send(errors);
  return;
}
// normal processing here

Spitting out raw errors like this is not very nice. That is why it is common to send errors back with a template:

var errors = req.validationErrors();
if (errors) {
  res.render('create', { errors: errors });
  return;
}
// normal processing here

And then in your template, to show the errors conditionally:

if errors  
  ul
    for error in errors
      li!= error.msg

This is an example using the Jade template engine. I know not everyone loves Jade so for good measure, here is another example, this time using the Handlebars template engine:

{{ #if errors }}
  <ul>
    {{ #each errors }}
      <li>{{ this.msg }}</li>
    {{ /each }}
  </ul>
{{ /if }}

###Custom validation functions Sometimes your custom validation rules are just too complicated to express using a regular expression and the matches function. It is for this reason that express-validator enables you to define custom validation functions.

To illustrate custom validation functions, imagine that the user is asked to enter exactly two comma-delimited tags.

  • The request body { tags: “tag1, tag2” } would be valid
  • as where the request bodies { tags: “tag1, tag1” } and { tags: “tag1” } would be invalid

Although it might be possible to create a regular expression for this rule, I speculate that doing so would come at too much of a cost to readability. So, let us define a custom validation function.

Inside of the "app.js" file, replace:

app.use(validator());

With:

app.use(validator({
  customValidators: {
    containsTwoTags: function (value) {
      var tags = value.split(',');
      // Remove empty tags
      tags = tags.filter(function(tag) { return /\S/.test(tag) });
      // Remove duplicate tags
      tags = tags.filter(function(item, pos, self) { return self.indexOf(item) == pos; });
      return tags.length <= 2;
    }
  }
})

This custom validation function called containsTwoTags returns true if the input is valid; otherwise, it returns false. You can execute any code you want in your custom validation function so long as it returns a boolean.

You can use this custom validation function just like you would any other validation function, like this:

req.checkBody('tags', 'Enter exactly two distinct tags.').containsTwoTags();

Pretty sweet…

###Summary This has been a basic introduction to input validation in Node with express-validator. Whilst I hope I have covered enough for you to hit the ground running in your application, if you encounter any trouble, please consult the documentation or get in touch and I will be happy to help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment