kriszyp/json-schema

Arrays and Dates validate as objects

Closed this issue · 2 comments

a schema containing a property:

thing : { type : "object", "required" : true }

will validate true for:

thing: []
thing: new Date()

This is a bit annoying and plain wrong (though the blame probably lies on JS itself). Perhaps there's some RPC-aligned reason for arrays and dates to be objects?

May I propose you use (or align with) sugarjs (http://sugarjs.com/api) to perform your "is type" validations? It'd be good if the JS community would form some kind of consensus about what is and isn't an object, and I believe sugarjs does a good job of this.

I'll put together a pull request if you wouldn't mind adding an (awesome) dependency.

require("json-schema/lib/validate").validate([], {type:"object"}) will not validate if run correctly, it will throw a validation error for the array. However, in NodeJS, if you run that from the console, it will validate because the array object is pulled from a different global (apparently the console is running in a different global now). This seems like a NodeJS issue. We could add code to handle arrays from different contexts, but it is infrequent enough that I don't think it is worth it.

A Date object is an object with JS and there is nothing to categorize it as within the realm of JSON. Dates are typically represented with numerical epoch ms or string representations of dates, both of which can be properly validated with JSON Schema. And no, I don't want to add sugarjs as a dependency, any changes can easily be handled by plain JavaScript (we are handling type: "array" just fine with normal arrays).

Thanks for the great library! I'm running up against this issue now with arrays validating as objects and I'm not sure I understand your explanation about how the array object is pulled from a different global.

echo "var jsonschema = require('json-schema'); console.log(jsonschema.validate([], {type: 'object', required: true}));" > tmp.js && node tmp.js

produces

{ valid: true, errors: [] }

likewise, running it from the node repl

coryvirok@dude $ node
> var jsonschema = require('json-schema');
undefined
> jsonschema.validate([], {type: 'object', required: true})
{ valid: true, errors: [] }

Crockford mentions this strange behavior as a result of typeof with arrays here: http://javascript.crockford.com/remedial.html

Seems like the proper way to get the type would be to use his helper function typeOf() that he provides on the link above in-lieu of using the typeof operator.

The specific fix for checking for arrays would be to use the helper in this part of the type checking code:

if(typeof type == 'string' && type != 'any' &&
    (type == 'null' ? value !== null : typeof value != type) &&  /* use typeOf(value) !== type */
    !(value instanceof Array && type == 'array') &&
    !(value instanceof Date && type == 'date') &&
    !(type == 'integer' && value%1===0)){
    return [{property:path,message:(typeof value) + " value found, but a " + type + " is required"}];
}

Let me know if you'd like a pull request.