zaggino / z-schema Goto Github PK
View Code? Open in Web Editor NEWJSON Schema validator written in JavaScript for NodeJS and Browsers
License: Other
JSON Schema validator written in JavaScript for NodeJS and Browsers
License: Other
not sure if I am going crazy, but when I try to NPM install this library, no code is actually included in the package. There's no .js files inside node_modules/z-schema and requiring the library doesn't work.
afischer-mba ~ $ npm install z-schema
npm http GET https://registry.npmjs.org/z-schema
npm http 304 https://registry.npmjs.org/z-schema
npm http GET https://registry.npmjs.org/q
npm http 304 https://registry.npmjs.org/q
[email protected] node_modules/z-schema
└── [email protected]
afischer-mba ~ $ ls node_modules/z-schema/
LICENSE README.md node_modules package.json
afischer-mba ~ $ node
> require('z-schema')
Error: Cannot find module 'z-schema'
at Function.Module._resolveFilename (module.js:338:15)
at Function.Module._load (module.js:280:25)
at Module.require (module.js:362:17)
at require (module.js:378:17)
at repl:1:2
at REPLServer.self.eval (repl.js:111:21)
at Interface.<anonymous> (repl.js:250:12)
at Interface.EventEmitter.emit (events.js:93:17)
at Interface._onLine (readline.js:199:10)
at Interface._line (readline.js:517:8)
I have an application that uses Swagger 1.2 schema files. Their schema files are not perfect but I've been able to work around them using jjv. I want to use z-schema and I've started writing a few tests to see how I'd load the schema files I need. I've run into a problem where a Maximum call stack exceeded
happens with the following code (Warning, it's long but the purpose was to give you a copy/paste test instead of you having to download the Swagger 1.2 schema files yourself.). When I run the code, I get the following error:
/private/tmp/testing/node_modules/z-schema/src/SchemaCache.js:38
if (Array.isArray(schema)) {
^
RangeError: Maximum call stack size exceeded
I'm using [email protected]
. Here is the code that creates the error above:
var dataTypeBaseJson = {
"id": "http://wordnik.github.io/schemas/v1.2/dataTypeBase.json#",
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Data type fields (section 4.3.3)",
"type": "object",
"oneOf": [
{
"required": [
"type"
]
},
{
"required": [
"$ref"
]
}
],
"properties": {
"type": {
"type": "string"
},
"$ref": {
"type": "string"
},
"format": {
"type": "string"
},
"defaultValue": {
"not": {
"type": [
"array",
"object",
"null"
]
}
},
"enum": {
"type": "array",
"items": {
"type": "string"
},
"uniqueItems": true,
"minItems": 1
},
"minimum": {
"type": "string"
},
"maximum": {
"type": "string"
},
"items": {
"$ref": "#/definitions/itemsObject"
},
"uniqueItems": {
"type": "boolean"
}
},
"dependencies": {
"format": {
"oneOf": [
{
"properties": {
"type": {
"enum": [
"integer"
]
},
"format": {
"enum": [
"int32",
"int64"
]
}
}
},
{
"properties": {
"type": {
"enum": [
"number"
]
},
"format": {
"enum": [
"float",
"double"
]
}
}
},
{
"properties": {
"type": {
"enum": [
"string"
]
},
"format": {
"enum": [
"byte",
"date",
"date-time"
]
}
}
}
]
}
},
"definitions": {
"itemsObject": {
"oneOf": [
{
"type": "object",
"required": [
"$ref"
],
"properties": {
"$ref": {
"type": "string"
}
},
"additionalProperties": false
},
{
"allOf": [
{
"$ref": "#"
},
{
"required": [
"type"
],
"properties": {
"type": {},
"format": {}
},
"additionalProperties": false
}
]
}
]
}
}
};
var modelsObjectJson = {
"id": "http://wordnik.github.io/schemas/v1.2/modelsObject.json#",
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"required": [
"id",
"properties"
],
"properties": {
"id": {
"type": "string"
},
"description": {
"type": "string"
},
"properties": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/propertyObject"
}
},
"subTypes": {
"type": "array",
"items": {
"type": "string"
},
"uniqueItems": true
},
"discriminator": {
"type": "string"
}
},
"dependencies": {
"subTypes": [
"discriminator"
]
},
"definitions": {
"propertyObject": {
"allOf": [
{
"not": {
"$ref": "#"
}
},
{
"$ref": "dataTypeBase.json#"
}
]
}
}
};
var oauth2GrantTypeJson = {
"id": "http://wordnik.github.io/schemas/v1.2/oauth2GrantType.json#",
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"minProperties": 1,
"properties": {
"implicit": {
"$ref": "#/definitions/implicit"
},
"authorization_code": {
"$ref": "#/definitions/authorizationCode"
}
},
"definitions": {
"implicit": {
"type": "object",
"required": [
"loginEndpoint"
],
"properties": {
"loginEndpoint": {
"$ref": "#/definitions/loginEndpoint"
},
"tokenName": {
"type": "string"
}
},
"additionalProperties": false
},
"authorizationCode": {
"type": "object",
"required": [
"tokenEndpoint",
"tokenRequestEndpoint"
],
"properties": {
"tokenEndpoint": {
"$ref": "#/definitions/tokenEndpoint"
},
"tokenRequestEndpoint": {
"$ref": "#/definitions/tokenRequestEndpoint"
}
},
"additionalProperties": false
},
"loginEndpoint": {
"type": "object",
"required": [
"url"
],
"properties": {
"url": {
"type": "string",
"format": "uri"
}
},
"additionalProperties": false
},
"tokenEndpoint": {
"type": "object",
"required": [
"url"
],
"properties": {
"url": {
"type": "string",
"format": "uri"
},
"tokenName": {
"type": "string"
}
},
"additionalProperties": false
},
"tokenRequestEndpoint": {
"type": "object",
"required": [
"url"
],
"properties": {
"url": {
"type": "string",
"format": "uri"
},
"clientIdName": {
"type": "string"
},
"clientSecretName": {
"type": "string"
}
},
"additionalProperties": false
}
}
};
var authorizationObjectJson = {
"id": "http://wordnik.github.io/schemas/v1.2/authorizationObject.json#",
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"additionalProperties": {
"oneOf": [
{
"$ref": "#/definitions/basicAuth"
},
{
"$ref": "#/definitions/apiKey"
},
{
"$ref": "#/definitions/oauth2"
}
]
},
"definitions": {
"basicAuth": {
"required": [
"type"
],
"properties": {
"type": {
"enum": [
"basicAuth"
]
}
},
"additionalProperties": false
},
"apiKey": {
"required": [
"type",
"passAs",
"keyname"
],
"properties": {
"type": {
"enum": [
"apiKey"
]
},
"passAs": {
"enum": [
"header",
"query"
]
},
"keyname": {
"type": "string"
}
},
"additionalProperties": false
},
"oauth2": {
"type": "object",
"required": [
"type",
"grantTypes"
],
"properties": {
"type": {
"enum": [
"oauth2"
]
},
"scopes": {
"type": "array",
"items": {
"$ref": "#/definitions/oauth2Scope"
}
},
"grantTypes": {
"$ref": "oauth2GrantType.json#"
}
},
"additionalProperties": false
},
"oauth2Scope": {
"type": "object",
"required": [
"scope"
],
"properties": {
"scope": {
"type": "string"
},
"description": {
"type": "string"
}
},
"additionalProperties": false
}
}
};
var parameterObjectJson = {
"id": "http://wordnik.github.io/schemas/v1.2/parameterObject.json#",
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"allOf": [
{
"$ref": "dataTypeBase.json#"
},
{
"required": [
"paramType",
"name"
],
"properties": {
"paramType": {
"enum": [
"path",
"query",
"body",
"header",
"form"
]
},
"name": {
"type": "string"
},
"description": {
"type": "string"
},
"required": {
"type": "boolean"
},
"allowMultiple": {
"type": "boolean"
}
}
},
{
"description": "type File requires special paramType and consumes",
"oneOf": [
{
"properties": {
"type": {
"not": {
"enum": [
"File"
]
}
}
}
},
{
"properties": {
"type": {
"enum": [
"File"
]
},
"paramType": {
"enum": [
"form"
]
},
"consumes": {
"enum": [
"multipart/form-data"
]
}
}
}
]
}
]
};
var operationObjectJson = {
"id": "http://wordnik.github.io/schemas/v1.2/operationObject.json#",
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"allOf": [
{
"$ref": "dataTypeBase.json#"
},
{
"required": [
"method",
"nickname",
"parameters"
],
"properties": {
"method": {
"enum": [
"GET",
"POST",
"PUT",
"PATCH",
"DELETE",
"OPTIONS"
]
},
"summary": {
"type": "string",
"maxLength": 120
},
"notes": {
"type": "string"
},
"nickname": {
"type": "string",
"pattern": "^[a-zA-Z0-9_]+$"
},
"authorizations": {
"type": "object",
"additionalProperties": {
"type": "array",
"items": {
"$ref": "authorizationObject.json#/definitions/oauth2Scope"
}
}
},
"parameters": {
"type": "array",
"items": {
"$ref": "parameterObject.json#"
}
},
"responseMessages": {
"type": "array",
"items": {
"$ref": "#/definitions/responseMessageObject"
}
},
"produces": {
"$ref": "#/definitions/mimeTypeArray"
},
"consumes": {
"$ref": "#/definitions/mimeTypeArray"
},
"deprecated": {
"enum": [
"true",
"false"
]
}
}
}
],
"definitions": {
"responseMessageObject": {
"type": "object",
"required": [
"code",
"message"
],
"properties": {
"code": {
"$ref": "#/definitions/rfc2616section10"
},
"message": {
"type": "string"
},
"responseModel": {
"type": "string"
}
}
},
"rfc2616section10": {
"type": "integer",
"minimum": 100,
"maximum": 600,
"exclusiveMaximum": true
},
"mimeTypeArray": {
"type": "array",
"items": {
"type": "string",
"format": "mime-type"
}
}
}
}
var apiDeclarationJson = {
"id": "http://wordnik.github.io/schemas/v1.2/apiDeclaration.json#",
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"required": [
"swaggerVersion",
"basePath",
"apis"
],
"properties": {
"swaggerVersion": {
"enum": [
"1.2"
]
},
"apiVersion": {
"type": "string"
},
"basePath": {
"type": "string",
"format": "uri",
"pattern": "^https?://"
},
"resourcePath": {
"type": "string",
"format": "uri",
"pattern": "^/"
},
"apis": {
"type": "array",
"items": {
"$ref": "#/definitions/apiObject"
}
},
"models": {
"type": "object",
"additionalProperties": {
"$ref": "modelsObject.json#"
}
},
"produces": {
"$ref": "#/definitions/mimeTypeArray"
},
"consumes": {
"$ref": "#/definitions/mimeTypeArray"
},
"authorizations": {
"$ref": "authorizationObject.json#"
}
},
"additionalProperties": false,
"definitions": {
"apiObject": {
"type": "object",
"required": [
"path",
"operations"
],
"properties": {
"path": {
"type": "string",
"format": "uri-template",
"pattern": "^/"
},
"description": {
"type": "string"
},
"operations": {
"type": "array",
"items": {
"$ref": "operationObject.json#"
}
}
},
"additionalProperties": false
},
"mimeTypeArray": {
"type": "array",
"items": {
"type": "string",
"format": "mime-type"
}
}
}
};
var ZSchema = require('z-schema');
var validator = new ZSchema();
var result = validator.compileSchema([
dataTypeBaseJson,
modelsObjectJson,
oauth2GrantTypeJson,
authorizationObjectJson,
parameterObjectJson,
operationObjectJson,
apiDeclarationJson
]);
if (result === false) {
console.dir(validator.getLastErrors());
}
The email format is pretty strict about checking for global Top-Level Domains:
(aero|arpa|biz|com|coop|edu|gov|info|int|mil|museum|name|net|org|pro|travel|mobi|[a-z][a-z])
The JSON schema spec is less strict about email, just saying they should comply with:
http://xml2rfc.ietf.org/public/rfc/html/rfc5322.html#addrspec
Although this seems useful the majority of the time, there are two problems with maintaining a strict list of gTLDs:
The expansion of generic Top-Level Domains (e.g. .COM, .ORG, .NET) in the Domain Name System is underway. Over 1,300 new names or "strings" could become available in the next few years.
http://newgtlds.icann.org/en/program-status/delegated-strings
FYI: The email address I was testing was [email protected]
.
Support sync version of compileSchema()
(see #19). It's convenient at server start-up
One of the projects I'm working on has a handful of schema files that get combined together to validate a complete JSON payload but there is also a need/desire to be able to treat these schema files individually and validate a JSON payload fragment. Below is an example structure:
var schemaCombinations = {
'authorizationObject.json': [
oauth2GrantType, // 'oauth2GrantType.json
authorizationObject // 'authorizationObject.json
],
'infoObject.json': [
infoObject // infoObject.json
],
'oauth2GrantType.json': [
oauth2GrantType // oauth2GrantType.json
],
'resourceObject.json': [
resourceObject // resourceObject.json
],
'resourceListing.json': [
resourceObject, // resourceObject.json
infoObject, // infoObject.json
oauth2GrantType, // oauth2GrantType.json
authorizationObject, // authorizationObject.json
resourceListing // resourceListing.json
]
};
So each of these schema combinations represent the array of schema fragments to compile for the corresponding schema file to be valid. So each array is basically a list of dependencies, including itself.
If I had code to create a validator for each schema file, the first 4 compile just fine but the last one fails due to the following references not resolving: resourceObject.json, infoObject.json and authorizationObject.json. I'm not sure why that would happen. On a whim, I updated the same code to avoid building the first four validators and only build the last one and it works. Below is the code to replicate this. To reproduce the current problem, which happens when all 5 validators are created in the same program, run it as-is. To see the scenario where the failing validator compiles properly when the first four validators are not created prior, comment out Block One
and uncomment Block Two
.
'use strict';
var ZSchema = require('z-schema');
var resourceObject = {
'id': 'resourceObject.json',
'$schema': 'http://json-schema.org/draft-04/schema#',
'type': 'object',
'required': [ 'path' ],
'properties': {
'path': { 'type': 'string', 'format': 'uri' },
'description': { 'type': 'string' }
},
'additionalProperties': false
};
var infoObject = {
'id': 'infoObject.json',
'$schema': 'http://json-schema.org/draft-04/schema#',
'description': 'info object (section 5.1.3)',
'type': 'object',
'required': [ 'title', 'description' ],
'properties': {
'title': { 'type': 'string' },
'description': { 'type': 'string' },
'termsOfServiceUrl': { 'type': 'string', 'format': 'uri' },
'contact': { 'type': 'string', 'format': 'email' },
'license': { 'type': 'string' },
'licenseUrl': { 'type': 'string', 'format': 'uri' }
},
'additionalProperties': false
};
var oauth2GrantType = {
'id': 'oauth2GrantType.json',
'$schema': 'http://json-schema.org/draft-04/schema#',
'type': 'object',
'minProperties': 1,
'properties': {
'implicit': { '$ref': '#/definitions/implicit' },
'authorization_code': { '$ref': '#/definitions/authorizationCode' }
},
'definitions': {
'implicit': {
'type': 'object',
'required': [ 'loginEndpoint' ],
'properties': {
'loginEndpoint': { '$ref': '#/definitions/loginEndpoint' },
'tokenName': { 'type': 'string' }
},
'additionalProperties': false
},
'authorizationCode': {
'type': 'object',
'required': [ 'tokenEndpoint', 'tokenRequestEndpoint' ],
'properties': {
'tokenEndpoint': { '$ref': '#/definitions/tokenEndpoint' },
'tokenRequestEndpoint': { '$ref': '#/definitions/tokenRequestEndpoint' }
},
'additionalProperties': false
},
'loginEndpoint': {
'type': 'object',
'required': [ 'url' ],
'properties': {
'url': { 'type': 'string', 'format': 'uri' }
},
'additionalProperties': false
},
'tokenEndpoint': {
'type': 'object',
'required': [ 'url' ],
'properties': {
'url': { 'type': 'string', 'format': 'uri' },
'tokenName': { 'type': 'string' }
},
'additionalProperties': false
},
'tokenRequestEndpoint': {
'type': 'object',
'required': [ 'url' ],
'properties': {
'url': { 'type': 'string', 'format': 'uri' },
'clientIdName': { 'type': 'string' },
'clientSecretName': { 'type': 'string' }
},
'additionalProperties': false
}
}
};
var authorizationObject = {
'id': 'authorizationObject.json',
'$schema': 'http://json-schema.org/draft-04/schema#',
'type': 'object',
'additionalProperties': {
'oneOf': [
{
'$ref': '#/definitions/basicAuth'
},
{
'$ref': '#/definitions/apiKey'
},
{
'$ref': '#/definitions/oauth2'
}
]
},
'definitions': {
'basicAuth': {
'required': [ 'type' ],
'properties': {
'type': { 'enum': [ 'basicAuth' ] }
},
'additionalProperties': false
},
'apiKey': {
'required': [ 'type', 'passAs', 'keyname' ],
'properties': {
'type': { 'enum': [ 'apiKey' ] },
'passAs': { 'enum': [ 'header', 'query' ] },
'keyname': { 'type': 'string' }
},
'additionalProperties': false
},
'oauth2': {
'type': 'object',
'required': [ 'type', 'grantTypes' ],
'properties': {
'type': { 'enum': [ 'oauth2' ] },
'scopes': {
'type': 'array',
'items': { '$ref': '#/definitions/oauth2Scope' }
},
'grantTypes': { '$ref': 'oauth2GrantType.json' }
},
'additionalProperties': false
},
'oauth2Scope': {
'type': 'object',
'required': [ 'scope' ],
'properties': {
'scope': { 'type': 'string' },
'description': { 'type': 'string' }
},
'additionalProperties': false
}
}
};
var resourceListing = {
'id': 'resourceListing.json',
'$schema': 'http://json-schema.org/draft-04/schema#',
'type': 'object',
'required': [ 'swaggerVersion', 'apis' ],
'properties': {
'swaggerVersion': { 'enum': [ '1.2' ] },
'apis': {
'type': 'array',
'items': { '$ref': 'resourceObject.json' }
},
'apiVersion': { 'type': 'string' },
'info': { '$ref': 'infoObject.json' },
'authorizations': { '$ref': 'authorizationObject.json' }
}
};
var schemaCombinations = {
'authorizationObject.json': [
oauth2GrantType,
authorizationObject
],
'infoObject.json': [
infoObject
],
'oauth2GrantType.json': [
oauth2GrantType
],
'resourceObject.json': [
resourceObject
],
'resourceListing.json': [
resourceObject,
infoObject,
oauth2GrantType,
authorizationObject,
resourceListing
]
};
// Block One
Object.keys(schemaCombinations).forEach(function (name) {
var validator = new ZSchema({sync: true});
var toCompile = schemaCombinations[name];
try {
validator.compileSchema(toCompile);
console.log(name +': success');
} catch (err) {
var vError = validator.getLastError();
if (!vError.errors) {
vError = err;
}
console.log(name +': failure');
if (vError.errors) {
vError.errors.forEach(function (error) {
console.log(' ' + error.message);
});
} else {
console.log(' ' + vError.message);
}
}
});
// Block Two
// new ZSchema({sync: true}).compileSchema(schemaCombinations['resourceListing.json']);
The example schema & data at http://json-schema.org/example2.html doesn't validate. It gives an error:
[ { code: 'OBJECT_REQUIRED',
message: 'Missing required property: storage',
path: '#/',
params: [Object] } ]
Test case in https://github.com/AXIOS-PAULM/Scratch/tree/master/zschema-issue
Note that to work round #8 the 'id' entry in entry-schema.json should be removed.
The Plugging this into our main schema
example of the JSON Schema - Advanced Example shows an example of a $ref
with a trailing #
at the end. If I have a schema id of mySchema
and I reference it from another document with a $ref
of mySchema#
, I'd expect that to work. But with z-schema, this does not work. For the reference to work, I either have to change my schema.id to mySchema#
or change my $ref
to be mySchema
. Below is an example that will result in an unresolvable reference. Is the #
suppose to be significant in the id/reference?
var ZSchema = require('z-schema');
var validator = new ZSchema({sync: true});
var schemaA = {
id: 'schemaA',
type: 'string'
};
var schemaB = {
id: 'schemaB',
properties: {
a: {
// '$ref': 'schemaA' // Works
'$ref': 'schemaA#' // Fails
}
}
};
try {
validator.compileSchema([schemaA, schemaB]);
} catch (err) {
var vError = validator.getLastError();
if (vError && vError.valid === false) {
console.log(validator.getLastError());
} else {
throw err;
}
}
It looks like the "validateSchema" method doesn't actually validate the given schema:
var ZSchema = require('z-schema');
var validator = new ZSchema();
validator.validateSchema('bogus schema here', function(err, report) {
if (err) throw err;
console.log(report); // { valid: true, errors: [], warnings: [] }
});
Attempting to validate a schema which has an id attribute and contains $refs (internal or remote) results in attempt to load the schema again remotely.
This seems to make it impossible to use a local schema with an id & $refs.
Test case at https://github.com/AXIOS-PAULM/Scratch/tree/master/zschema-issue based on http://json-schema.org/example2.html
I think this case should be valid, but currently throws an error. The current implementation only looks for type
on the anyOf
schemas and not the parent.
type: 'object',
properties: {
'prop1': {...}
'prop2': {...},
},
anyOf: [
{
required: ['prop1']
},
{
required: ['prop2']
}
]
Okay, if I validate this object it takes <1 ms.
{
firstname: 'First',
lastname: 'Last',
}
If I validate this object, it takes 32ms. What is happening that the ObjectID adds 31 ms processing time? Processing time goes up linearly, the more ObjectID's it has to check. Sometimes I need to check arrays of objects with ObjectIDs and that gets outrageous.
{
_id: new ObjectID(), // mongodb id
firstname: 'First',
lastname: 'Last',
}
I'm not sure if this is related to #44 but I used almost the same test to reproduce this issue. Long story short, if your schema id ends with a #
, references to the schema by id result in an UNRESOLVABLE_REFERENCE
:
var ZSchema = require('z-schema');
var validator = new ZSchema();
var schemaA = {
id: 'schemaA#',
type: 'string'
};
var schemaB = {
id: 'schemaB#',
properties: {
a: {
// '$ref': 'schemaA' // Fails
'$ref': 'schemaA#' // Fails
}
}
};
var result = validator.compileSchema([schemaA, schemaB]);
if (result === false) {
console.log(validator.getLastErrors());
}
The output of this is:
[ { code: 'UNRESOLVABLE_REFERENCE',
params: [ 'schemaB#schemaA#' ],
message: 'Reference could not be resolved: schemaB#schemaA#',
path: '#/properties/a' } ]
If I remove the trailing #
from the id, everything works fine:
var ZSchema = require('z-schema');
var validator = new ZSchema();
var schemaA = {
id: 'schemaA',
type: 'string'
};
var schemaB = {
id: 'schemaB',
properties: {
a: {
// '$ref': 'schemaA' // Works
'$ref': 'schemaA#' // Works
}
}
};
var result = validator.compileSchema([schemaA, schemaB]);
if (result === false) {
console.log(validator.getLastErrors());
}
String '127.0.0.1'
validates against format 'hostname' and 'ipv4' which is not correct!
{
"ipAddress": "127.0.0.1"
}
must be ok against
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"ipAddress": {
"type": "string",
"oneOf": [
{
"format": "hostname"
},
{
"format": "ipv4"
},
{
"format": "ipv6"
}
]
}
}
}
but is not with Z-Schema.
You can check with http://json-schema-validator.herokuapp.com/ or look at http://json-schema.org/example2.html. Also have a look at natesilva/jayschema#21.
{a: 4}
is validated successfully against
{
$schema: 'http://json-schema.org/draft-04/schema#',
id: "schemaA",
type: "object",
properties: {
a: {
type: "integer"
},
b: {
type: "string"
},
c: {
$ref: 'schemaB'
}
},
required: ['a']
}
node
REPLvar schema = {
"$schema": "http://json-schema.org/schema#",
"properties": { "text": { "type": "string" } },
"type": "object"
};
var json = { "text": "o"};
require("z-schema").validate(json, schema, console.log);
Successful validation.
.../node_modules/z-schema/src/ZSchema.js:318
throw new Error('Not a JSON data at: ' + url + ', ' + e);
^
Error: Not a JSON data at: http://json-schema.org/schema, SyntaxError: Unexpected end of input
at returnSchemaFromString (/Users/abj/Documents/LoveThis/git/antigua_api/service-dym/test/node_modules/z-schema/src/ZSchema.js:318:27)
at IncomingMessage.<anonymous> (/Users/abj/Documents/LoveThis/git/antigua_api/service-dym/test/node_modules/z-schema/src/ZSchema.js:344:21)
at IncomingMessage.EventEmitter.emit (events.js:117:20)
at _stream_readable.js:920:16
at process._tickCallback (node.js:415:13)
Hi,
First of all, thanks for this great library!
I've encountered some problems validating a schema with optional/non-required properties.
I get this error:
errors: Array[2]
0: ValidationError
code: "FORMAT"
message: "date format validation failed: "
path: "#/date_of_birth"
1: ValidationError
code: "PATTERN"
message: "String does not match pattern: ^[1-9]{1}[0-9]{3} ?[A-Z]{2}$"
params: Object
path: "#/postcode"
valid: false
on this schema:
"website_users":
{
"$schema": "http://json-schema.org/schema#",
"description": "Schema for the website users context",
"type": "object",
"self": {
"vendor": "xxxx",
"name": "website_users",
"format": "jsonschema",
"version": "1-0-0"
},
"properties": {
"date_of_birth": {
"type": "string",
"format": "date"
},
"dealer_postcode": {
"type": "string",
"pattern": "^[1-9]{1}[0-9]{3} ?[A-Z]{2}$"
},
"email": {
"type": "string",
"maxLength": 128
},
"email_id": {
"type": "string",
"maxLength": 64
},
"firstname": {
"type": "string",
"maxLength": 64
},
"gender": {
"type": "string", "enum":["man","vrouw"]
},
"housenumber": {
"type": "string",
"maxLength": 16
},
"initials": {
"type": "string",
"maxLength": 8
},
"kvk_nummer": {
"type": "string",
"maxLength": 32
},
"language": {
"type": "string",
"maxLength": 16
},
"lastname": {
"type": "string",
"maxLength": 64
},
"phonenumber": {
"type": "string",
"maxLength": 32
},
"postcode": {
"type": "string",
"pattern": "^[1-9]{1}[0-9]{3} ?[A-Z]{2}$"
},
"street": {
"type": "string",
"maxLength": 64
},
"tussenvoegsel": {
"type": "string",
"maxLength": 16
},
"user_id": {
"type": "string",
"maxLength": 32
}
},
"required": ["email"],
"additionalProperties": false
}
I understand that the validation fails on these fields (because they are empty) but they are optional.
Thanks in advance!
Tries to validate simple hyper-schemas with empty links
array, and got a warning telling me that links
is unknown key despite I set $schema
to hyper-schema url explicitly:
var ZSchema = require('z-schema');
var schema = {
$schema: "http://json-schema.org/draft-04/hyper-schema#",
links: []
};
var validator = new ZSchema();
validator.validateSchema(schema, function (err, report) {
console.log(report);
});
gives
{ valid: true,
errors: [],
warnings: [ { message: 'Unknown key "links" found in schema.', path: '#/' } ] }
Am I right, that for now schemas are not validated against schema specified by URI in $schema
key?
I've noticed that schema are automatically validated when you attempt to use them to validate data.
I'm writing unit tests for a project that uses JSON schema, and it would be terrific if I could access these validation methods easily to facilitate with my tests.
First of all, thank you for a great library. I've found it really useful and its 'options' features is the one which I could not find in other libraries.
I was working with different schema validations for a project. Let's say, my whole JSON body is empty and the schema defines all the fields are optional.
It may not be a bug, but I could find the documentation supporting such features.
Thank you for your time.
Neeraj
hi @zaggino ,
i have a question/issue.. having schema (taken from your example) formatted as object :
{
"id": "root.json",
"person": {
"id": "personDetails",
"type": "object",
"properties": {
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
}
},
"required": ["firstName", "lastName"]
},
"addr": {
"id": "addressDetails",
"type": "object",
"properties": {
"street": {
"type": "string"
},
"city": {
"type": "string"
}
},
"required": ["street", "city"]
},
"peraddr": {
"id": "personWithAddress",
"allOf": [{
"$ref": "#personDetails"
}, {
"$ref": "#addressDetails"
}, {
"$ref": "#/yy"
}, {
"$ref": "#xx"
}]
}
and code:
allSchemasValid = validator.validateSchema(rootschema);
// allSchemasValid === flase
comp_res = validator.compileSchema(rootschema);
// comp_res === flase
err = validator.getLastErrors()
/*
err == [
{
code: "UNRESOLVABLE_REFERENCE"
message: "Reference could not be resolved: #/yy"
params: [ "#/yy" ]
path: "#/peraddr/allOf/2"
}
]
*/
miss =validator.getMissingReferences()
/*
miss == [
""
]
*/
is validator.getMissingReferences()
return as it should be?
I just tried to follow your example, using [var validator = new ZSchema({ sync: true }); ] and I have this whole Failure Trace...
TypeError: Object true has no method 'forEach'
at ZSchema.InstanceValidators.required (\node_modules\z-schema\src\ZSchema.js:1905:29)
at step1 (\node_modules\z-schema\src\ZSchema.js:1223:48)
at Object.Utils.forEach (\node_modules\z-schema\src\ZSchema.js:195:34)
at ZSchema._validateObject (\node_modules\z-schema\src\ZSchema.js:1244:19)
at ZSchema.<anonymous> (\node_modules\z-schema\src\ZSchema.js:1383:26)
at Array.forEach (native)
at ZSchema.<anonymous> (\node_modules\z-schema\src\ZSchema.js:1380:15)
at Object.Utils.forEach (\node_modules\z-schema\src\ZSchema.js:195:34)
at ZSchema._recurseObject (\node_modules\z-schema\src\ZSchema.js:1354:15)
at step2 (\node_modules\z-schema\src\ZSchema.js:1232:29)
at ZSchema._validateObject (\node_modules\z-schema\src\ZSchema.js:1245:13)
at ZSchema.validate (\node_modules\z-schema\src\ZSchema.js:792:18)
I've been trying to use Z-Schema to validate a schema for the Swagger 2 specification.
I'm getting this error:
Error: Use .setRemoteReference to download references in sync mode: http://json-schema.org/draft-04/schema
I've tried it as sync, async, and explicitly using setRemoteReference on a downloaded copy of the schema. None have worked.
I was able to get it to work by altering the host of the $ref (e.g. "json-schema.org" to "json-schema.orgx") and doing a setRemoteReference. So I'm speculating, but I think that the "json-schema.org" schemas are probably being treated specially and download is being skipped, but then can't be found when we refer to a subschema. Example:
"title": { "$ref": "http://json-schema.org/draft-04/schema#/properties/title" }
I created a gist with a frozen copy of the schema and sample you can try, or you can check out reverb/swagger-spec.
Running the following code under Node.js
var ZSchema, main, schemaA;
ZSchema = require("z-schema");
schemaA = {
$schema: 'http://json-schema.org/draft-04/schema#',
id: "schemaA",
type: "object",
properties: {a: {type: "integer"}, b: {type: "string"}, c: {$ref: 'schemaB'}},
required: ['a', 'c']
};
var json, schema;
schema = schemaA;
json = {a: 4, c: 4};
console.info("#1: validate ...");
ZSchema.validate(json, schema, function(err, report) {
var _ref;
if (err) {
console.error("... not valid!");
if ("errors" in err) {
console.error(err.errors);
}
return;
}
console.info("... OK");
if ((_ref = report.warnings) != null ? _ref.length : void 0) {
return console.warn(report.warnings);
}
});
results to the following console output, which I don't expect:
#1: validate ...
... not valid!
[ { code: 'INVALID_TYPE',
message: 'invalid type: integer (expected object)',
path: '#/c',
params: { expected: 'object', type: 'integer' } } ]
The compiler throws a schema validation error when noTypeless
is set to true
and instead of the type
keyword any of the keywords oneOf
, anyOf
, not
, $ref
are present.
Is this the desired behaviour ? I think it would be more convenient if the error is not thrown if any one of those keywords are present on the schema since they all essentially define what the type of the object should be.
Hi, is there ability to cache schema by setRemoteReference and next - validate by it's uri? For example:
ZSchema.setRemoteReference('http://localhost:1234/integer.json', fileContent);
ZSchema.validate(myJsonData, 'http://localhost:1234/integer.json', function () {...})
Cheers
I'm trying to get z-schema to load the Swagger Schemas. I noticed that for the modelsObject.json
, I was getting a Maximum call stack size exceeded
. Below is a recipe that will reproduce the issue. schemaA
corresponds to dataTypeBase.json and schemaB
corresponds with modelsObject.json.
var schemaA = {
'id': 'schemaA',
'$schema': 'http://json-schema.org/draft-04/schema#',
'description': 'Data type fields (section 4.3.3)',
'type': 'object',
'oneOf': [
{ 'required': [ 'type' ] },
{ 'required': [ '$ref' ] }
],
'properties': {
'type': { 'type': 'string' },
'$ref': { 'type': 'string' },
'format': { 'type': 'string' },
'defaultValue': {
'not': { 'type': [ 'array', 'object', 'null' ] }
},
'enum': {
'type': 'array',
'items': { 'type': 'string' },
'uniqueItems': true,
'minItems': 1
},
'minimum': { 'type': 'string' },
'maximum': { 'type': 'string' },
'items': { '$ref': '#/definitions/itemsObject' },
'uniqueItems': { 'type': 'boolean' }
},
'dependencies': {
'format': {
'oneOf': [
{
'properties': {
'type': { 'enum': [ 'integer' ] },
'format': { 'enum': [ 'int32', 'int64' ] }
}
},
{
'properties': {
'type': { 'enum': [ 'number' ] },
'format': { 'enum': [ 'float', 'double' ] }
}
},
{
'properties': {
'type': { 'enum': [ 'string' ] },
'format': {
'enum': [ 'byte', 'date', 'date-time' ]
}
}
}
]
}
},
'definitions': {
'itemsObject': {
'oneOf': [
{
'type': 'object',
'required': [ '$ref' ],
'properties': {
'$ref': { 'type': 'string' }
},
'additionalProperties': false
},
{
'allOf': [
{ '$ref': '#' },
{
'required': [ 'type' ],
'properties': {
'type': {},
'format': {}
},
'additionalProperties': false
}
]
}
]
}
}
};
var schemaB = {
'id': 'schemaB',
'$schema': 'http://json-schema.org/draft-04/schema#',
'type': 'object',
'required': [ 'id', 'properties' ],
'properties': {
'id': { 'type': 'string' },
'description': { 'type': 'string' },
'properties': {
'type': 'object',
'additionalProperties': { '$ref': '#/definitions/propertyObject' }
},
'subTypes': {
'type': 'array',
'items': { 'type': 'string' },
'uniqueItems': true
},
'discriminator': { 'type': 'string' }
},
'dependencies': {
'subTypes': [ 'discriminator' ]
},
'definitions': {
'propertyObject': {
'allOf': [
{
'not': { '$ref': '#' }
},
{
'$ref': 'schemaA'
}
]
}
}
};
var ZSchema = require('z-schema');
var validator = new ZSchema({sync: true});
try {
validator.compileSchema([schemaA, schemaB]);
} catch (err) {
var vError = validator.getLastError();
if (vError && vError.valid === false) {
console.log(validator.getLastError());
} else {
throw err;
}
}
I'm working on a project that is using JSON schema. I currently set the id
attribute of my schema to the URI that they will be eventually deployed to, just like the upstream IETF draft schema: http://json-schema.org/draft-04/schema
Would it be possible to feed multiple schema into a single validator instance and have it use the id
attributes to build a local map of available schema?
My hope is that by feeding enough local schema into a validator, I can avoid all remote lookups. I haven't actually deployed my new JSON schema yet, and the remote lookups are making testing somewhat inconvenient.
What do you think about enabling, via some configuration, the representation of error paths? On the one hand, I like the JSON Pointer syntax for presentation but on the other, I find an array of path segments to be much easier to work with from a programmatic perspective.
Hello,
I have a nested hierarchy and I don't want to explicitly define the last item as was done in #22. When I remove the oneOf construct it seems to end in an infinite loop.
This is the json/schema exhibiting the issue:
JSON
{ "is_start": true,
"hierarchy": {
"is_and": false,
"filters": [
{
"is_and": false,
"filters": [
{
"is_and": true,
"filters": [
{
"is_and": true,
"filters": [
{
"is_and": true,
"filters": [
{
"is_and": true,
"filters": [
{
"is_and": true,
"filters": []
}
]
}
]
}
]
}
]
}
]
}
]
}}
SCHEMA
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Product set",
"is_start": "boolean",
"hierarchy": {
"$ref": "#/definitions/recursion"
},
"definitions": {
"recursion": {
"type": "object",
"additionalProperties": false,
"properties": {
"is_and": {
"type": "boolean"
},
"filters": {
"type": "array",
"additionalItems": false,
"items": {
"$ref": "#/definitions/recursion"
}
}
}
}
}
}
It would be really great if it was easier to do the following things with Z-Schema
The case for a customizable meta data value would be scenario where you may have to perform additional processing on the data before or after validation besides just putting a default value.
For example if we wish to sanitize html which is submitted to the server as a json request. I could simply implement a meta data boolean keyword called sanitize
which would then sanitize the input before validating it.
It could also be used for perhaps converting date-time strings to Date
or serialized mongoDB objectIDs to ObjectID
instances.
This bug reproduces through z-schema.
I'd like to know why development of this library was started although there are JSON schema validation libraries out there? What are the features of this library which make z-schema different from other libraries (i.e. natesilva/jayschema)? Is it the Promises/A+ based API?
Having a schema with $schema: 'http://json-schema.org/draft-04/schema#'
, setting remote schema
ZSchema.setRemoteReference('http://json-schema.org/draft-04/schema',
fs.readFileSync (path.join __dirname, 'json-schema-draft-04', 'schema.json'), 'utf8')
and validate something against that schema, leads to
{
code: 'UNKNOWN_FORMAT',
message: 'There is no validation function for format "regex"',
path: '#/properties[pattern]',
params: { format: 'regex' }
}
Hi @zaggino
I recently created yet another javascript json-schema library called jjv, hosted here:
https://github.com/acornejo/jjv
Due to security and performance reasons, it does not support downloading remote references. Aside from that it should be draft4 compatible (it passes all appropriate tests).
I haven't had time to create a benchmark script, but I would love to see how it compares with other available libraries.
Would you mind adding jjv to your list in your benchmark wiki? I believe it should be fairly easy to do, the following snippet should do the trick:
Tester.registerValidator({
name: 'jjv',
setup: function () {
return jjv();
},
test: function (instance, json, schema) {
return instance.validate(schema, json) === null;
}
})
The above assumes you did var jjv=require('jjv');
and that you added jjv 0.3.0 to the npm package list.
Thanks
Regexp in FormatValidators['uri']
is not properly anchored
I noticed today that my custom format is not having any effect on the end result. I always get successful validation. Is there more I need to do to register my custom format? Provide some kind of error message?
ZSchema.registerFormat('date-object', function (obj) {
//return obj instanceof Date;
return false; // Still passes
});
ZSchema.registerFormat('object-id', function (obj) {
//return obj instanceof ObjectID;
return false; // Still passes
});
Here is part of my schema:
'notes': {
type: 'array',
items: {
type: 'object',
properties: {
'note': { type: 'string', maxLength: 2048 },
'created': { type: 'object', format: 'date-object' },
'createdBy': { type: 'string', maxLength: 161 },
'_id': { type: 'object', format: 'object-id' }
}
}
}
In the same way you can register a validator, would it be possible to register a coercion function? The idea would be if you have a field you know is a timestamp, you could coerce it to a Date object, or if you had an attribute that was an array of Users which you have a class constructor for, you could have z-schema convert those to your local type.
Right now, the string path of an error is a mix of JSON Pointer and some JavaScript string you would eval. I would like to propose that error paths, when in string form (See #55), use JSON Pointer syntax. So instead of #/some/[1]/path[operation]
, it would be #/some/1/path/operation
.
I ran across this while working on #55. If you'd like, I an submit a PR for this as well once the PR for #55 is completed.
I work mostly in Node and front-end javascript. I like Z-Schema, but it forces me to convert the date to a String, then back to a Date after validation. It's a little cumbersome because mongodb allows storing Date instances into the db. How could I extend or modify z-schema to handle a Date instance? Or could we add the functionality into Z-Schema?
Having a schema with $schema: 'http://json-schema.org/draft-04/schema#'
, setting remote schema
ZSchema.setRemoteReference('http://json-schema.org/draft-04/schema',
fs.readFileSync (path.join __dirname, 'json-schema-draft-04', 'schema.json'), 'utf8')
and validate something against that schema, leads to
{
code: 'FORMAT',
message: 'uri format validation failed: schemaA',
path: '#/id',
params: { format: 'uri', error: 'schemaA' }
}
If I remove $schema: 'http://json-schema.org/draft-04/schema#'
from my schema validation is ok.
My schema is quite simple:
schemaA = {
$schema: 'http://json-schema.org/draft-04/schema#',
id: "schemaA",
type: "object",
properties: {
a: {
type: "integer"
},
b: {
type: "string"
}
},
required: ['a']
};
If I change the id
value from 'schemaA'
to 'http://my.company.de/project#mainSchema'
then validation is ok. Isn't 'schemaA'
a valid URI ?
Is there anything Node.js specific used in this module that is not possible to mock in the browser?
Hi,
I have nested hierarchy like this:
{
"is_and": false,
"filters": [
{
"is_and": false,
"filters": [
{
"is_and": true,
"filters": [
{
"is_and": true,
"filters": [
{
"is_and": true,
"filters": [
{
"is_and": true,
"filters": [
{
"text": 'ABC',
"is_last": true,
"filters": [
]
}
]
}
]
}
]
}
]
}
]
}
]
}
Now i want to validate the above json schema with self referencing but issue is that the last item in nested hierarchy has different properties & filter object being empty too, so having trouble for terminating the last item in hierarchy.
anyone suggest short validation rule.
Thanks
I'm not sure if this question is already answered.
If I have 3 schemas in memory, each of them has an id attribute, one of them is the main schema.
How can I do the following with z-schema:
I can do this with other libraries but do not see how to do this with z-schema. setRemoteReference
needs an url, which I'm not willing to provide because each of the schemas has an id attribute.
Here are the schemas, for example:
var schemaA = {id: "schemaA", type: "integer"};
var schemaB = {id: "schemaB", type: "string"};
var mainSchema = {
id: "mainSchema",
type: "object",
properties: {
a: {"$ref": "schemaA"},
b: {"$ref": "schemaB"},
c: {"enum": ["C"]}
}
};
I am working on a factory-girl type thing based on json/schema with your library.
Currently I am keeping inin a branch of your z-schema library
https://github.com/leapmotion/z-schema/tree/factory
which also features class files. To do so I have added a method or two to your library and exposed some of its internal componentry.
If you feel this is better put as a seperate (factory) branch I can spin it off, but I'd still need to expose the schema digestion elements as thier own thing.
Can we talk?
Dave Edelhart
Leapmotion
I'm still pretty new to JSON schema, but looking around at the other JSON Schema validation libraries out there, I have yet to find one that will support my use case. However judging by the z-schema API, it appears that you may be the most open to the ideas I have in mind were I to fork and submit pull requests.
Basically, I'm looking to add support for two features:
(1) the ability to register additional non-JSON-schema validations. For example, when validating an npm package.json file, it's easy to define a validation that checks if a string is a valid path. However, I would also like to be able to register a validation that checks if those paths actually exist on disk relative to the location of the package.json file itself. Another example would be checking if a homepage URL doesn't return a 404 not found error.
I reckon this feature would be implementable by allowing you to register pre and post validation functions that receive the value of the property being validated and returning true if additional validations succeed or errors otherwise. These functions would need access to the context in which they are called (so that they can get access via closures to details such as the directory in which a package.json exists).
(2) partial validation for performance reasons. For example, if I have already loaded a JSON into memory and validated it on load, I don't want to completely revalidate it on write. Instead I'd like the ability to only validate the properties that I am modifying.
validator.validate(partialJSON, "lib://package.json#/definitions/dependency-map", function(err, result) {
if (err) { /* .. handle err ... */ }
/* ... add partialJSON to full JSON and write to disk ... */
});
or alternatively schemas could have method support for getting definitions, like so:
compiledSchema.getDefinition("dependency-map")
or a validatePartial method could be added to ZSchema like so:
validator.validate(partialJSON, schema, definitionName, function(err, result) {
if (err) { /* .. handle err ... */ }
/* ... add partialJSON to full JSON and write to disk ... */
});
For this second feature the following features would be valuable:
As far as I can tell, suggestion two seems reasonable, but the first suggestion might be better as a separate module built on top of your validator or another one. However, to build feature (1) on top, it would be immensely useful to have partial validation.
I just started looking through the source and I'm still thinking through how these might be implementable, but I wanted to get your thoughts on them. Would you be open to accepting pull requests for these features?
Hi, I am working with schema files on a local filesystem, and am wondering how a schema file that is referenced should be entered in the main schema file?
example:
"schemas":{
"schemaA":{
"description":"description",
"id":"schemaA",
"type":"object",
"properties":{
"payments":{
"type":"array",
"description":"description",
"items":{
"$ref":"file-to-ref-same-directory.json"
}
}
What format should the value for $ref be if the json file is in the same directory as the primary json file?
Thanks!
Just a reminder for myself because it should be done sometime soon.
First of all, awesome library :) we are starting to use it and really like the robustness and how easy to use it is.
Now, onto the issue. If we have the following (partial) schema:
"name": {
"type": "string",
"pattern": "^[^<>]*$",
"description": "Name of the client. Invalid characters are < and >."
},
It would be useful to get a human friendly representation of the error which is better that the regex. Currently the error looks like (in z-schema 2.x.x but is seems to provide the same info in 3.x.x):
{ code: 'PATTERN',
message: 'String does not match pattern: ^[^<>]*$',
path: '#/name',
params: { pattern: '^[^<>]*$' } }
Ideally we would get:
{ code: 'PATTERN',
message: 'String does not match pattern: ^[^<>]*$',
path: '#/name',
params: { pattern: '^[^<>]*$', description: 'Name of the client. Invalid characters are < and >.' } }
This seems to only require a small change at https://github.com/zaggino/z-schema/blob/master/src/JsonValidation.js#L77 but would be really useful for reporting errors back to users, e.g. when using JSON schema to validate API calls.
Thoughts?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.