When working with LoopBack models, you can validate data before it gets persisted into your datastore multiple different ways. The documentation describes the various methods, but I wanted to play with it a bit and demonstrate a few examples.

To begin, let’s consider an example in which you’ve defined a model property with a particular type and you do not pass in the correct value. I’ve got a Cat model that includes a name (string), age (number), and color (string). None of these values are required (and this is important). What happens if I try to post a string value for age?

Here is the JSON I used:

{
  "name": "Test",
  "age": "Bad",
  "color": "blue",
  "id": 0
}

And here is the response:

shot1

Notice that no error was thrown, but the invalid value was nulled out. This only happens because age is not required, so LoopBack simply throws out the incorrect value. You can address this by simply making age required. Then when you post the same value, you get the proper response:

shot2

Woot! OK, but that’s pretty simple. What about things such as validating that age is numeric, a whole number, and “reasonable” (for a cat, say below 25)? Turns out there are different ways of handling validation. Obviously you can write completely custom code, so yes, what I just described is completely doable. But LoopBack includes some validation “shortcuts” out of the box, so the great news is that you can skip writing validation functions in many cases. The docs cover this in depth, but at a high level,in one line you can add validation methods to require:

  • A property to not exist. (Which seems odd, but you may have conditional logic where if some condition is true, a property must not exist.)
  • The presence of a property.
  • A value not be in a particular set. So you could say that a name can’t be Ray or Bob.
  • A value to be in a particular set. So a name must be Ray or Bob.
  • Match a regular expression.
  • Length to be at least so many characters, or at most so many characters, or exactly one length.
  • A number to be an integer (as in the age example provided above).
  • A value to be unique. This one only works in a few supported datastores, but keep in mind that you can always write your own logic to handle cases where it isn’t supported.

So what does it look like to include these rules?All of the validation examples I mentioned above can be included with one line of code. Here is how you would require a name to be one of two values:

module.exports = function(Person) {
	Person.validatesInclusionOf('name', {'in':['Ray','Jeanne']});	
};

That’s it. But let’s kick it up a notch. You can write completely custom validation using one of two functions: `validate` or `validateAsync`. As their names imply, the first is for synchronous validation logic and the other is asynchronous. Here’s a simple example that uses a timeout and returns a pass/fail at a later time:

function myCustom(err, done) {
	var name = this.name;
	setTimeout(function() {
		if(name === 'Ray') {
			err();
		}
		done();			
	}, 1000);	
}
	
Person.validateAsync('name', myCustom, {message:'Dont like'});

This example calls the `myCustom` function to validate a name asynchronously. (I could have “inlined” the function too, but maybe other properties will use the same logic.) Your custom function is passed two objects, `err` and `done`. At first, I thought I should call `err` and exit, but that’s not the case. An error condition is more like a flag. Note how I don’t return, or abort, or anything in my error condition. All I do is call `err` itself, and then continue on.

Now when I try to create a person, it will take a second, and if the name is `Ray`, I get an error. Notice the error message defined is probably not the nicest I could write.

Obviously this is a rather trivial example, but it demonstrates how powerful LoopBack is in terms of customization. While LoopBack lets you create a simple API in minutes, “real” applications will have unique business needs. What I appreciate about LoopBack is the incredible level of customization at all points of the API process. No matter your particular needs, LoopBack will provide a way to support them.