GithubHelp home page GithubHelp logo

flatiron / revalidator Goto Github PK

View Code? Open in Web Editor NEW
591.0 23.0 83.0 667 KB

A cross-browser / node.js validator powered by JSON Schema

Home Page: http://github.com/flatiron/revalidator

License: Apache License 2.0

JavaScript 100.00%

revalidator's Introduction

revalidator Build Status

A cross-browser / node.js validator with JSONSchema compatibility as the primary goal.

Example

The core of revalidator is simple and succinct: revalidator.validate(obj, schema):

  var revalidator = require('revalidator');

  console.dir(revalidator.validate(someObject, {
    properties: {
      url: {
        description: 'the url the object should be stored at',
        type: 'string',
        pattern: '^/[^#%&*{}\\:<>?\/+]+$',
        required: true
      },
      challenge: {
        description: 'a means of protecting data (insufficient for production, used as example)',
        type: 'string',
        minLength: 5
      },
      body: {
        description: 'what to store at the url',
        type: 'any',
        default: null
      }
    }
  }));

This will return with a value indicating if the obj conforms to the schema. If it does not, a descriptive object will be returned containing the errors encountered with validation.

  {
    valid: true // or false
    errors: [/* Array of errors if valid is false */]
  }

In the browser, the validation function is exposed on window.validate by simply including revalidator.js.

Installation

Installing npm (node package manager)

  $ curl http://npmjs.org/install.sh | sh

Installing revalidator

  $ [sudo] npm install revalidator

Usage

revalidator takes json-schema as input to validate objects.

revalidator.validate (obj, schema, options)

This will return with a value indicating if the obj conforms to the schema. If it does not, a descriptive object will be returned containing the errors encountered with validation.

{
  valid: true // or false
  errors: [/* Array of errors if valid is false */]
}

Available Options

  • validateFormats: Enforce format constraints (default true)
  • validateFormatsStrict: When validateFormats is true treat unrecognized formats as validation errors (default false)
  • validateFormatExtensions: When validateFormats is true also validate formats defined in validate.formatExtensions (default true)
  • additionalProperties: When additionalProperties is true allow additional unvisited properties on the object. (default true)
  • cast: Enforce casting of some types (for integers/numbers are only supported) when it's possible, e.g. "42" => 42, but "forty2" => "forty2" for the integer type.

Schema

For a property an value is that which is given as input for validation where as an expected value is the value of the below fields

required

If true, the value should not be undefined

{ required: true }

allowEmpty

If false, the value must not be an empty string

{ allowEmpty: false }

type

The type of value should be equal to the expected value

{ type: 'string' }
{ type: 'number' }
{ type: 'integer' }
{ type: 'array' }
{ type: 'boolean' }
{ type: 'object' }
{ type: 'null' }
{ type: 'any' }
{ type: ['boolean', 'string'] }

pattern

The expected value regex needs to be satisfied by the value

{ pattern: /^[a-z]+$/ }

maxLength

The length of value must be greater than or equal to expected value

{ maxLength: 8 }

minLength

The length of value must be lesser than or equal to expected value

{ minLength: 8 }

minimum

Value must be greater than or equal to the expected value

{ minimum: 10 }

maximum

Value must be lesser than or equal to the expected value

{ maximum: 10 }

allowEmpty

Value may not be empty

{ allowEmpty: false }

exclusiveMinimum

Value must be greater than expected value

{ exclusiveMinimum: 9 }

exclusiveMaximum

Value must be lesser than expected value

{ exclusiveMaximum: 11 }

divisibleBy

Value must be divisible by expected value

{ divisibleBy: 5 }
{ divisibleBy: 0.5 }

minItems

Value must contain more than expected number of items

{ minItems: 2 }

maxItems

Value must contain fewer than expected number of items

{ maxItems: 5 }

uniqueItems

Value must hold a unique set of values

{ uniqueItems: true }

enum

Value must be present in the array of expected values

{ enum: ['month', 'year'] }

format

Value must be a valid format

{ format: 'url' }
{ format: 'email' }
{ format: 'ip-address' }
{ format: 'ipv6' }
{ format: 'date-time' }
{ format: 'date' }
{ format: 'time' }
{ format: 'color' }
{ format: 'host-name' }
{ format: 'utc-millisec' }
{ format: 'regex' }

conform

Value must conform to constraint denoted by expected value

{ conform: function (v) {
    if (v%3==1) return true;
    return false;
  }
}

dependencies

Value is valid only if the dependent value is valid

{
  town: { required: true, dependencies: 'country' },
  country: { maxLength: 3, required: true }
}

Nested Schema

We also allow nested schema

{
  properties: {
    title: {
      type: 'string',
      maxLength: 140,
      required: true
    },
    author: {
      type: 'object',
      required: true,
      properties: {
        name: {
          type: 'string',
          required: true
        },
        email: {
          type: 'string',
          format: 'email'
        }
      }
    }
  }
}

Custom Messages

We also allow custom messages for different constraints

{
  type: 'string',
  format: 'url'
  messages: {
    type: 'Not a string type',
    format: 'Expected format is a url'
  }
{
  conform: function () { ... },
  message: 'This can be used as a global message'
}

Tests

All tests are written with vows and should be run with npm:

  $ npm test

License: Apache 2.0

revalidator's People

Contributors

3rd-eden avatar badsyntax avatar bmeck avatar brian-gates avatar colinf avatar davidgwking avatar eiriksm avatar facundoolano avatar ggoodman avatar indexzero avatar indutny avatar ixti avatar jcrugzz avatar julianduque avatar liammclennan avatar marak avatar mikewadsten avatar mmalecki avatar okv avatar panuhorsmalahti avatar pksunkara avatar rkusa avatar seangarner avatar slaskis avatar snb2013 avatar southern avatar stefansedich avatar timoxley avatar yeikos avatar zeke avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

revalidator's Issues

Error message in the proper order

{
    "type": "object",
    "properties": {
        "customer": {
             "type": "object",
             "properties": {
                "name": {
                     "type": "string",
                     "required": true
                  }
             }
        },
        "user": {
            "type": "object",
            "properties":{
                "name": {
                    "type": "string",
                    "required": true
                }
            }
        }
    }
}

and if I provided the value like

{
    "customer": {  },
    "user": {  }
}

Then I get the error like

{
    "errors": [
        {
            "attribute": "required",
            "property": "user.name",
            "expected": true,
            "message": "is required"
        },
        {
            "attribute": "required",
            "property": "customer.name",
            "expected": true,
            "message": "is required"
        }
    ]
}

That is the order of the error message is wrong. I need to get customer and then user.

I can't use formats as regex

To fix it I must do this:

var Scheme = require('revalidator');

Scheme.validate.formatExtensions = Scheme.validate.formats;
Scheme.validate.defaults.formatExtensions = true;

Missing some serious features

I've just started using this package due to the need of custom messages, but unfortunately I'd probably stop using it, because it lacks some features that are critical.

  1. An array of required properties can't be stated inside the object itself, but only inside the property.
    It means that this is schema is not valid
{
    "type": "object",
    "properties": {
        "name": {
            "type": "string"
        },
        "type": {
            "type": "string"
        }
    },
    "required": ["name", "type"]
}

and instead I have to write it like that:

{
    "type": "object",
    "properties": {
        "name": {
            "type": "string",
            "required": true
        },
        "type": {
            "type": "string",
            "required": true
        }
    }
}
  1. anyOf, allOf, oneOf and not are not supported, and are simply ignored, so many of my objects cannot be validated against their schema

angular-schema-form security validator

Both https://github.com/Textalk/angular-schema-form/ and https://github.com/joshfire/jsonform allow for the use of a JSONSchema with additional form definition to determine what to display to the user.

It would be great if the validator could take into account the fields defined in the form view definition that goes with a schema as well to ensure that additional fields are not submitted or can filter out unwanted fields (or at least warn about them).

https://github.com/Textalk/angular-schema-form/blob/master/dist/schema-form.js implements the merge with the form format in "service.merge".

Thoughts on providing a defaultMessage via the schema?

In addition to being able to provide messages with validate.messages, just wondering what peoples thoughts were on being able to specify a fallback message in the schema? Either that or perhaps dropping the "no default message" text so it's simpler to assign a fall back message ourselves (error.message || 'Value is stuffed :/)?

Maybe both?

"before" ignored if "description" is provided.

Original issue here can be found at flatiron/prompt#62.

Test case:

var prompt = require('prompt');

var schema={
  properties:{
   filename: {
      before: function(value) { return 'v -> ' + value.toUpperCase(); },
      description:'Enter output file name',
      pattern: /^[a-z0-9\s\-\.]*$/i,
      message: 'Name must be only letters, spaces, or dashes',
      default: 'filename.json',
      required: false
    },
  }
}

prompt.start();
prompt.get(schema, function (err, result) {
  if(err) {
    console.log('cancelled error');
    return;
  }
  console.log(err, result);
});

add ability to access other object values in the "conform" function

it's very difficult to validate certain properties without being able to refer to other object properties: e.g. comparing two dates, etc.

it would be pretty easy to create this functionality via "conform" attribute -- conform function could receive one extra parameter "object" which would reference the whole object with properties being validated.

so, when calling checkType, the "conform" constraint would take this form:

constrain('conform', value, function (a, e, object) { return e(a, object) });

instead of the current:

constrain('conform', value, function (a, e) { return e(a) });

and the "constrain" function would change from this:

function constrain(name, value, assert) {
  if (schema[name] !== undefined && !assert(value, schema[name])) {
    error(name, property, value, schema, errors);
  }
}

to this ('object' would exist in this context just like schema)

function constrain(name, value, assert) {
  if (schema[name] !== undefined && !assert(value, schema[name], object)) {
    error(name, property, value, schema, errors);
  }
}

consequently, the "conform" attribute would take this form:

{ conform: function (v,object) {
        if(object['some_other_property'] > v) return true;
        return false;
    }
}

date-time format validation regex is invalid

JSON Schema validation specification refers to rfc3339 chapter 5.6

This sample date-time value : 2014-03-11T00:00:00.000+01:00 is rejected by revalidator and it should not.

I propose the following modification of the regex from
/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:.\d{1,3})?Z$/
to
/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?((?:[\+\-]\d{2}:\d{2})|Z)$/

Note that this proposition also include a fix where the . separator for millisecond could be replaced by any character.

Object validation throwing error

object throws error on validation

value is an object

example of schema:
properties: {
callType: {
description: "Type of Call",
type: "object",
required: true,
properties: {
id: {
type: ["string", "number"],
required: true
},
description: {
type: 'string',
required: true
}
}
},
}

Objects are throwing errors when trying to do a validation on them. In the validateProperty there is no string check on value (in this case value is an object) and so .trim() throws an error because you can't trim an object.

Validate confirmation field

Would love to see logic to support validating a password confirmation field. Perhaps something like this:

validate({password: 'foo', passwordConfirm: 'bar'}, { properties: { passwordConfirm: { match: 'password' } } }

ensure property is not present

Is there a way to declare that a specific property/key should not be a part of a schema? I have a property that I don't want updated.

Failure to validate union properties that are schemas

I've been forced to switch libraries because the current structure of the code would require sweeping changes to allow support for union properties wherein on of the possible options in the union is a schema itself.

The code assumes that union properties are a list of types while the spec states that these can be types or entire schemas.

Maybe a mistake when working with arrays.

case 'array':
  constrain('items', value, function (a, e) {
    var nestedErrors;
    for (var i = 0, l = a.length; i < l; i++) {
      nestedErrors = [];
      validateProperty(object, a[i], property, e, options, nestedErrors);
      nestedErrors.forEach(function (err) {

in validateProperty(object, a[i], property, e, options, nestedErrors); need use i instead of property:

validateProperty(object, a[i], i, e, options, nestedErrors);

Otherwise cast create empty property in array, like [ 22, 33, 11, 44, 77, '': 77 ].

allowEmpty: true doesn't work with pattern

short version

If a property is defined with allowEmpty: true, but also has a value specified for pattern, revalidator will consider an empty value for that property to be an error. required: false works as expected with pattern.
Depending on your reading of the documentation, this might not be a bug, but I would expect allowEmpty: true to permit the empty string.

code

var revalidator = require('revalidator'),
    schema = {
        properties: {
            empty_or_re: {
                required: false,
                allowEmpty: true,
                pattern: /^ok/i
            }
        }
    };
[
    {},
    {empty_or_re: ''},
    {empty_or_re: 'okay'},
    {empty_or_re: 'nope'}
].forEach(function(form_data) {
    var validation = revalidator.validate(form_data, schema)
    console.dir({
        form_data: form_data,
        valid: validation.valid,
        errors: validation.errors
    });
});

output

{ form_data: {}, valid: true, errors: [] }
{ form_data: { empty_or_re: '' },
  valid: false,
  errors: 
   [ { attribute: 'pattern',
       property: 'empty_or_re',
       expected: /^ok/i,
       actual: '',
       message: 'invalid input' } ] }
{ form_data: { empty_or_re: 'okay' }, valid: true, errors: [] }
{ form_data: { empty_or_re: 'nope' },
  valid: false,
  errors: 
   [ { attribute: 'pattern',
       property: 'empty_or_re',
       expected: /^ok/i,
       actual: 'nope',
       message: 'invalid input' } ] }

Async conform support

It'd be helpful if the conform method supported a callback to help with async validation of properties. eg a database lookup

Format + 'null' type

Hello,

I'm trying to have a property that could either be a date-time or null:

$ cat test.js
var revalidator = require('revalidator');

var schema = { properties: { datetime: { type: ['string', 'null'], format: 'date-time', default: null } } },
    object = { datetime: null },
    result = revalidator.validate(object, schema);

console.log(result);
$ node test.js
{ valid: false,
  errors: 
   [ { attribute: 'format',
       property: 'datetime',
       expected: 'date-time',
       actual: null,
       message: 'is not a valid date-time' } ] }
$ 

Brief code inspection suggests this is a bug because formats are enforced before types so the validation code has no way of knowing null is actually fine where the format is expected.

Is this a bug or am I overlooking something?

Possible bug and fix when validating non-required field with "email" format

I am not sure if this is a bug or intended. Given the following schema property:

txtEmail : {
    required : false,
    allowEmpty: true,
    type : "string",
    format : "email",
}

revalidator returns a validation error if the field txtEmail is empty, even though required is set to false and allowEmpty to true.

The following fixes the issue for me:

$ diff revalidator-orig.js revalidator.js 
233c233
<     if (value === undefined) {

---
>     if (value === undefined || value === '') {

What is "default" used for?

The first example in the README has a property with a field named default but the code doesn't seem to implement it.

Maybe add after revalidator.js:253 something like:

} else if (schema.default !== undefined) {
    object[property] = schema.default;
    return;
}

And document that it sets the default value on the object's property if it doesn't exist and isn't required?

validating objects that contain functions

Suppose you have an object that holds arguments to some complex function and a schema that represents valid arguments. Revalidator works well if all the arguments are already defined values of various types: string, number, integer, boolean, or a nested structure (array, object). However, if one of the values in the object is a function, you can't determine in advance whether it will return a valid value that conforms to the schema. A trivial fix is to assume that the function will be fine. Is there a way to automatically defer validation?

Multiple conform messages

A use case I'm running into is wanting to have two different conform messages. For example, conform that value is Foo, or error of "Needs to be Foo", and also conform that value is Bar, or error of "Needs to be Bar".

I can think of two alternative APIs to implement allowing this.

  1. Allow conform to return an array of the form [result, errorMessage]
conform: function(v) {
  if (foo) { return [false, 'Not foo']; }
  else if (bar) { return [false, 'Not bar']; }
  else { return true; }
}
  1. Allow conform to be an array itself, as well as conform.messages
{ 
  conform: [
    function(v){ ... },
    function(v){ ... }
  ],
  messages: {
    conform: [
      'First conform test error',
      'Second conform test error'
    ]
  }
}

Hopefully others see this as useful, or maybe there are alternatives that I am missing?

Unable to customize message for additional properties

There is currently no way to assign a custom validation message when an additionalProperties error occurs. When error is called during this check the schema is set to false, destroying any additional message data that could be present in the schema.

I'm wondering if there's a workaround for this, other than checking to see if the error attribute is additionalProperties and then format a message accordingly.

allowEmpty true, minLength > 0 throws a validation error

Reading some other issue it seems this is intended, but I want to ask if this should be the case.

I've personally had the need for optional value fields that must have a min length if included. Is this a valid use case? If not, why so?

npm bump and publish

The version in npm is a little bit out of date. What's the eta on a republish?

minLength and maxLength is not working with number

minLength and maxLength is not working along with the type number or integer

Note: It will be useful to count phone number, pincode etc.

For example :

          var revalidator = require('revalidator');

          console.dir(revalidator.validate({pincode:3333}, {
                        properties: {
                                             pincode: {
                                                   message: 'Error',
                                                   type: 'number',
                                                   minLength: 5,
                                                   required:true
                                               }
                                            }
          }));

Code instead of messages

Hi! I need use error code instead of messages. Propose:

  • Add error code.

or

  • Modify messages from:
...

var message = schema.messages && schema.messages[attribute] || schema.message || validate.messages[attribute] || "no default message";
message = message.replace(/%\{([a-z]+)\}/ig, function (_, match) { return lookup[match.toLowerCase()] || ''; });

...

to:

...

var message = schema.messages && schema.messages[attribute] || schema.message || validate.messages[attribute] || "no default message";
if ('string' === typeof message) message = message.replace(/%\{([a-z]+)\}/ig, function (_, match) { return lookup[match.toLowerCase()] || ''; });

...

Publish v0.3.0 to npm

It looks as though version has been bumped to 0.3.0 at b040256, but it has yet to be published to npm. Is there an ETA as to when it will be published?

Thanks.

Update documentation on using array of objects in a schema

Update documentation with an example of how to use array of objects. Example below. The code actually works but it's not clear in the documentation how to implement it.

    'products': {
      required: false,
      'type': 'array',
      minItems: 1,
      maxItems: 50,
      items: {
        'type': 'object',
        properties: {
          text: {
            'type': 'string',
            format: 'email',
            maxLength: 140,
            minLength: 5,
            required: false
          },
          picture: {
            description: 'Upload a picture',
            'type': 'string',
            required: false,
            maxLength: 250,
            pattern: /(\.jpg|\.jpeg|\.gif|\.png)$/i,
            messages: {
              pattern: "only images of type .png .jpg .gif .jpeg are allowed"
            }
          }           
        }
      }
    }

Crashes when 'additionalProperties' is a schema.

[richard@tigger blah]$ cat blah.js 
var revalidator = require('revalidator')
var object = { 
    foo: 'bar'
}

var schema = { 
    properties: { 
        "baz": { 
            type: 'string',
            required: true
        }
    },
    additionalProperties: 
    {
        type: 'string',
        description: 'This will crash revalidator' 
    },
    type: 'object' }

return revalidator.validate(object, schema)
[richard@tigger blah]$ node blah.js

/home/richard/blah/node_modules/revalidator/lib/revalidator.js:278
    if (schema.format && options.validateFormats) {
              ^
TypeError: Cannot read property 'format' of undefined
    at validateProperty (/home/richard/blah/node_modules/revalidator/lib/revalidator.js:278:15)
    at validateObject (/home/richard/blah/node_modules/revalidator/lib/revalidator.js:232:11)
    at Object.validate (/home/richard/blah/node_modules/revalidator/lib/revalidator.js:35:7)
    at Object.<anonymous> (/home/richard/blah/blah.js:20:20)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Function.Module.runMain (module.js:497:10)
    at startup (node.js:119:16)

Client (browser) side validation is not working

When including "revalidator.js", validate() method is not exposed on the window object. Please see the following jsfiddle for an example (view console errors): http://jsfiddle.net/H6kkW/

Possible fix could be passing in the "window" object to the IIF, instead of window.json (wasn't it supposed to be window.JSON anyway?).

EDIT: windows.json is what should be used.

minLength and maxLength description switched in readme

readme has:
maxLength

The length of value must be greater than or equal to expected value

{ maxLength: 8 }
minLength

The length of value must be lesser than or equal to expected value

{ minLength: 8 }

But in reality, the descriptions are the opposite. maxLength requires the value to be less than or equal to maxLength. minLength requires the value to be greater than or equal to minLength.

Error message in the proper order

{
    "type": "object",
    "properties": {
        "customer": {
             "type": "object",
             "properties": {
                "name": {
                     "type": "string",
                     "required": true
                  }
             }
        },
        "user": {
            "type": "object",
            "properties":{
                "name": {
                    "type": "string",
                    "required": true
                }
            }
        }
    }
}

and if I provided the value like

{
    "customer": {  },
    "user": {  }
}

Then I get the error like

"errors": [
{
"attribute": "required",
"property": "user.name",
"expected": true,
"message": "is required"
},
{
"attribute": "required",
"property": "customer.name",
"expected": true,
"message": "is required"
},

That is the order of the error message is wrong. I need to get user and then customer.

How do you handle arbitrary property names?

I have a case where the property name of an object could be any string, but the value of the property has a structure that I would like to check. The structure of the arbitrary property is always the same too. How would I do this?

source missing license header

I noticed that the JavaScript file doesn't have a license header. This seems to be a common practice amongst JavaScript libraries.
Would it be possible to add the information to the file so users can easily adhere to the project's license?
Something like:
/*!

  • revalidator-v0.3.1.
  • Licensed under the Apache 2.0 License.
    */

Array validation

I have an array of contacts:

var contacts = [{
    type: 'email',
    value: '[email protected]'
}, {
    type: 'phone',
    value: '+8 9123 23213123'
}]

Can you please give me an example of schema for this case?

add patternProperties documentation

This is a great feature. I had been using revalidator for some time, but did not know it existed.

I forked to implement something similar, started digging through the source and tests, and there was this beauty. It's definitely a feature worth documenting.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.