gruber-validate
v0.2.1
Published
Validator wrapper to use on front & back end of boilerplate
Downloads
1
Readme
Validate
This package is designed to solve one problem in one situation.
The situation: Node / Express JS API with an Angular front end. You may be able to use it with something other than Express and Angular, but it wasn't designed for such uses. Currently Angular 2 is in beta, I'm not sure how it will handle Angular 2.
The problem: my form validation and API validation wasn't DRY. I was keeping two sets of validators. This can be extremely dangerous if your backend accepts invalid or insecure data.
The package is a bit complicated This package is more of a boilerplate. you should perform a git clone and update the source/validations.js file with your own validations. Then publish your package to NPM. I set it up as a boilerplate because I keep my backend and front end projects seperate. I use Node's package manager to keep my validations the same in both projects.
Usage
Express
This has a pretty simple middleware function you can use. The middleware performs the following tasks:
- Checks each field to verify it's valid.
- if a field isn't valid, the middleware will stop the route return a status of 400 to the client.
- Removes any field that is not in the validator (this is on by default but can be disabled)
- Sets req.validatorType to the validatorType (in case you want it later in the route pipeline)
If any fields are invalid it will string together the errors and call:
res.status(400).json({errors: errors});
The client should be able to expose the errors (just in case), but in reality the client should never see them (because the front end is using the same validation)
The Express middleware parameters
- validatorType: {string} (Required) - the name of the validator that will be used. The validatorTypes are defined in the source/validations.js file. You should add your own and delete the one's you don't use. The names of the validatorTypes should correspond with a RESTful route and the front end form.
- strict: {boolean} (optional: defaults true) - when set to true the middleware will delete any parameters found in req.body. This ensures the user can only update the fields you validate. If there are extra fields in the req.body, they will be deleted but not cause the validation to fail. This way, if you have an authentication token in the request body, they won't cause your validation to fail. But you need to use the parameters prior to validation, or they will be deleted.
Expects json parameters in req.body (that means something like body-parser is required).Expects a validatorType parameter (the name of the form). Returns JSON 400 on failure. if validation succeeds it will move to the next middleware. Lastly it will set req.validatorType = validatorType;
Requirements
- The middleware expects json parameters in the req.body, which means body-parser or its equivalent is required.
Example
var express = require('express');
var bodyParser = require('body-parser');
var validate = require('gruber-validate');
var app = express();
app.use(bodyParser.json());
express_app.get('/api/register', validate('register'), function (req, res) {
// if I get here the parameters validated successfully.
});
Client
Copy client.js into public location.
window.validateField = function(model, fieldName, data) ...
call window.validateField with the proper attributes to validate the field.
I bundle into Angular using the following
The angular bundle will add the validation error to the form. That way you can check if the form is invalid. This package has an issue where the input type cannot be email. There is something about the validation that happens automatically. You can add ng-options to the field but i just use type="text" instead.
// Directive
app.directive('validator', function() {
return {
require: ['^form', 'ngModel'],
scope: {ngModel:'=', modelType:'@', fieldName:'@'},
templateUrl: 'ValidatorTemplate.html',
link: function(scope, elm, attrs, ctrls) {
var ngModelCtrl = ctrls[1];
scope.form = ctrls[0];
scope.field = scope.form[scope.fieldName];
ngModelCtrl.$validators.wb = function(modelValue, viewValue) {
scope.errors = window.validate_field(scope.modelType, scope.fieldName, viewValue);
if (scope.errors) return false;
return true;
};
}
};
});
<!-- template -->
<div ng-show="form.$submitted || field.$touched">
<p class="text-danger" ng-show="errors">{{errors}}</p>
</div>
<!-- Example Usage -->
<form name="login_form" novalidate ng-submit="login()">
<input type="text" ng-model="email" name="email" class="form-control" placeholder="Email" required>
<validator ng-model='email' model-type='login' field-name='email'></validator>
<div>
<button type="submit" class="btn btn-primary">Log in</button>
</div>
</form>
// Controller Example
app.controller('LoginCtrl', ['$scope', function($scope) {
$scope.login = function() {
if ($scope.login_form.$valid) {
// Will only get here if there are no errors on the input
}
};
}]);
These can be copied from the angular folder...
How it works
Before you can even setup and start using this package you'll need to know how it works.
Some guy named Chriso made Validator (https://github.com/chriso/validator.js). A tool that can be used to validate your data on the front end as well as the back end. You'll need to check it out. The validator has most of the validations you'll be using, things like isEmail, etc.
File Summary
- Chriso's validator is our little worker bee, he handles all the validations.
- source/validate.js is our distribution hub.
- source/validations.js is our definitions.
- source/extenders.js has extensions for our validator (https://github.com/chriso/validator.js#extensions)
- source/client.js is our client's gateway. You can define more functionality for the client here. (this isn't used on the client directly, it needs to be bundled and browserfied first)
- express.js is our Node gateway (express middleware). He will be our apps starting place that way you can call him directly from Node.
- angular/ has my predefined directive I use in Angular.
- client.js is our browser ready validation tool.
source/validations.js
This is the confusing part. You'll be defining everything you need here.
validations {object}
variable in source/validations.js
The validations
variable will be an object. source/validate.js will pull the definitions for validating from here. We're going to create this using the todo example.
var validations = {};
validationType {object}
property in Validations object
Each property on the validations variable will be a different ValidationType. These should correspond to the client forms and the backend APIs. For example: if your front end has a Todo form that has a corresponding API on the back end. You will add a validationType of todo
. Each validationType will be an object of their own.
var validations = {
todo: {}
};
field {object}
property in validationType
Each property on the validationType will be a field/parameter. These will correspond to parameters on your api and fields (such as input's) on your frontend. To keep with the same example: the todo
validationType will have two properties: completed
& title
. Each field will also be an object.
var validations = {
todo: {
completed: {},
title: {}
}
};
validations {object | boolean}
property in field
Each property in the field will be a validation. This is where you'll define a fields validations. So the completed
field will have a isBoolean
validation. The isBoolean
validation doesn't have any options, so you can set it as true
.
var validations = {
todo: {
completed: {isBoolean: true},
title: {}
}
};
The title
field will need two validations:
- required: This is an extension to Christo's validator package. You can find it located in the source/extenders.js file. It simply verifies the existence of the field. Set the required validator to
true
. - minLength: This is also an extension to Christo's validator package. The minLength validation won't do much if it doesn't know how long the minimum length is. So instead of setting
minLength
to true, set it to an object:{options: 6}
. The options value tells our tool to make sure our string is longer than 6 characters.
var validations = {
todo: {
completed: {isBoolean: true},
title: {required: true, minLength: {options: 6}}
}
};
Ok. Now let's say you have two forms for todo. One for Create and one for put. And now you need to use a different validator for put. Here's how we add it:
var todoTitleMinLength = 6; // DRY ALL UP IN THIS BEAST
var validations = {
todo: {
completed: {isBoolean: true},
title: {required: true, minLength: {options: todoTitleMinLength}}
}
};
validations.todoUpdate = {
completed: validations.todo.completed, // Because I made this definition after defining validations I can call myself.
title: {minLength: {options: todoTitleMinLength}} // this sucker isn't required anymore
};
THREE CHEERS FOR DRYNESS!!!
How do you know the names of the validations? Chriso has many predefined in his application. You can see them here: https://github.com/chriso/validator.js#validators
I've had to add 3 I needed, you'll find them in source/extenders.js. You can also define your own using: https://github.com/chriso/validator.js#extensions. They should be placed in the source/extenders.js.
DEFAULT_ERROR_MESSAGES {object}
variable in source/validations.js This is the other variable you'll need to define. The validate tool generates error messages automatically, most of which are from here. Each property on the object should have the same name as the validations (the properties you defined on the fields above). Each error message will be a simple string.
Example:
var DEFAULT_ERROR_MESSAGES = {
isEmail: 'is not an email address.',
required: 'is required.',
isAlpha: 'must only contain letters (a-zA-Z).',
minLength: 'must be atleast ${options} characters long.',
maxLength: 'must be shorter than ${options} characters.'
};
This is as far as I got before I got bored. I can't believe you're even reading this. I designed this project for myself. I just made it public because I'm cheap.
Browse the code and review the tests for a better understanding.
Setup
Remember how I said it's more of a boilerplate?