Giter VIP home page Giter VIP logo

ajv's Introduction

Ajv logo

ย 

Ajv JSON schema validator

The fastest JSON validator for Node.js and browser.

Supports JSON Schema draft-04/06/07/2019-09/2020-12 (draft-04 support requires ajv-draft-04 package) and JSON Type Definition RFC8927.

build npm npm downloads Coverage Status SimpleX Gitter GitHub Sponsors

Ajv sponsors

Mozilla

Microsoft

RetoolTideliftSimpleX

Contributing

More than 100 people contributed to Ajv, and we would love to have you join the development. We welcome implementing new features that will benefit many users and ideas to improve our documentation.

Please review Contributing guidelines and Code components.

Documentation

All documentation is available on the Ajv website.

Some useful site links:

Since I asked to support Ajv development 40 people and 6 organizations contributed via GitHub and OpenCollective - this support helped receiving the MOSS grant!

Your continuing support is very important - the funds will be used to develop and maintain Ajv once the next major version is released.

Please sponsor Ajv via:

Thank you.

Open Collective sponsors

Performance

Ajv generates code to turn JSON Schemas into super-fast validation functions that are efficient for v8 optimization.

Currently Ajv is the fastest and the most standard compliant validator according to these benchmarks:

Performance of different validators by json-schema-benchmark:

performance

Features

Install

To install version 8:

npm install ajv

Getting started

Try it in the Node.js REPL: https://runkit.com/npm/ajv

In JavaScript:

// or ESM/TypeScript import
import Ajv from "ajv"
// Node.js require:
const Ajv = require("ajv")

const ajv = new Ajv() // options can be passed, e.g. {allErrors: true}

const schema = {
  type: "object",
  properties: {
    foo: {type: "integer"},
    bar: {type: "string"},
  },
  required: ["foo"],
  additionalProperties: false,
}

const data = {
  foo: 1,
  bar: "abc",
}

const validate = ajv.compile(schema)
const valid = validate(data)
if (!valid) console.log(validate.errors)

Learn how to use Ajv and see more examples in the Guide: getting started

Changes history

See https://github.com/ajv-validator/ajv/releases

Please note: Changes in version 8.0.0

Version 7.0.0

Version 6.0.0.

Code of conduct

Please review and follow the Code of conduct.

Please report any unacceptable behaviour to [email protected] - it will be reviewed by the project team.

Security contact

To report a security vulnerability, please use the Tidelift security contact. Tidelift will coordinate the fix and disclosure. Please do NOT report security vulnerabilities via GitHub issues.

Open-source software support

Ajv is a part of Tidelift subscription - it provides a centralised support to open-source software users, in addition to the support provided by software maintainers.

License

MIT

ajv's People

Contributors

asaid-0 avatar b4h0-c4t avatar blakeembrey avatar boenrobot avatar brendo avatar dependabot-preview[bot] avatar dependabot[bot] avatar domoritz avatar efebarlas avatar epoberezkin avatar erikbrinkman avatar franciscomorais avatar gajus avatar grahamlea avatar greenkeeper[bot] avatar greenkeeperio-bot avatar igor-savin-ht avatar imbstack avatar jasoniangreen avatar meirotstein avatar pbug90 avatar pcwiek avatar pithu avatar realityking avatar rehanvdm avatar sambauers avatar spaced4ndy avatar tyharo1 avatar willfarrell avatar yume-chan 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  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

ajv's Issues

Missing releases/tags/changelog

It would be extremely helpful to consumers if you provided a changelog or did releases and tags with each version. I find npm version or mversion to be extremely simple to use for this.

Edit: Did just see it at the bottom of the README. I think this is still valid though.

Inline $ref validations

  • Inline only simple refs, not containing other refs
    or
  • Inline all refs without recursive references to previous refs and not refs that have recursive references to them.

Easily resolve type at JSONPath

Given a JSONPath (or similar structure) and a schema, is there a good way to determine the type ('string', 'object', etc) for a value at that path?

JSONPath store.book[0].title might resolve to 'string' against a schema for a book store record.

Would the best approach be to just navigate the schema structure directly?

AJV & Redis

We are working on Redis and I think it would be perfect if ajv can retrieve schemas from Redis async.

Resolve previously missing references when additional schemas are compiled

That will enable mutual (circular) references between schemas.
That is more complex than it seems because resolution could fail in the middle of resolution chain and the newly added schema may not contain the required reference but be inside some resolution chains.
So the resolutions that were stopped because they couldn't find the newly added schema (and also any IDs contained in it - another complication) have to be re-tried.

Incorrect fragment resolution in referenced schemas

When schemas are added to a validator using 'addSchema', referenced schemas that contain internal references result in 'can't resolve reference' errors. This does not happen if the schemas are added to the validator (in the correct order) using 'compile'.

Here is a test that demonstrates the behaviour:

describe.only("references with 'definitions'", function () {

    var ajv = require("ajv");

    function spec(name) {

        var method,
            result,
            validator;

        validator = ajv();
        method = validator[name];

        method.call(validator, {
            definitions: {
                name: { type: "string" }
            },
            id: "http://schemas.domain.xyz/test/person.json#",
            properties: {
                name: { $ref: "#/definitions/name"}
            },
            type: "object"
        });

        method.call(validator, {
            id: "http://schemas.domain.xyz/test/employee.json#",
            properties: {
                person: { $ref: "/test/person.json#" },
                role: { type: "string" }
            },
            type: "object"
        });

        result = validator.validate("http://schemas.domain.xyz/test/employee.json#", {
            person: {
                name: "Alice"
            },
            role: "Programmer"
        });

        expect(result).to.be.true;
        expect(validator.errors).to.be.null;
    }

    it("should be supported by 'addSchema'", function () {

        spec("addSchema");
    });

    it("should be supported by 'compile'", function () {

        spec("compile");
    });
});

I've looked through the source and the issue appears to have something to do with the root that's passed to the 'compile' function.

When the schemas are added with 'compile', they are compiled independently; no root is passed for the referenced schema and its internal reference is resolved correctly. The 'resolveRef' function receives:

baseId = http://schemas.domain.xyz/test/person.json#
ref = #/definitions/name

When the schemas are added with 'addSchema', the referenced schema is compiled when the referencing schema is compiled and the referencing schema is passed as the root. In this case, the root appears to be used to resolve the referenced schema's internal reference. That is, the 'resolveRef' function receives:

baseId = http://schemas.domain.xyz/test/employee.json#
ref = #/definitions/name

Resolve reference passed to validate and getSchema methods

Is is possible for validate function to resolve ids inside schemas ?
example :

var ajv = require('ajv')();

ajv.addSchema({
    id: 'my-schema',
    type: 'object',
    definitions: {
        foo: {
            id: 'foo',
            type: 'object',
            required: ['bar']
        }
    }
}, 'my-schema');


ajv.validate(
    'my-schema#/definitions/foo', {
        bar: true
    });

// throws Error: no schema with key or ref "my-schema#/definitions/foo"

how to use in browser

I am writing test cases using Jasmine and need to use ajv through my browser.

I have already attempted to use it with browserify but it doesn't seem to work. Please provide a quick example as to how to use it within browser after bundling the package using browserify.

Here is what I have done so far:

browserify node_modules/ajv/lib/ajv.js -o node_modules/ajv/lib/bundle.js

and added that into my jasmine Spec file using:

  <script src="../../node_modules/ajv/lib/bundle.js"></script>

Then??

strongly type data

I work with XML Soap calls quite a bit. So all the data comes back as strings. I was wondering if you would like your code to support strongly typing an object or if that would be better to do spin off. Or if some other library would be better suited for this?

final validation function and $refs

I have two feature requests that may not be standards based but I think they'll be really useful:

1- An ajv function/method that can be provided with input data and returns TRUE or FALSE based on the input data as a first/final check, since there still are some things missing from JSON schema (or perhaps impossible the way I've written the schemas now).

2- A function that'd print the final JSON schema after replacing all $refs with actual content (ie. referenced schemas).

You can print warnings etc when they are used, so users know what they are doing.

Schema "pattern" keyword does not work properly

Hello, I'm using Node.js v4.1.1 and Ajv v1.4.2

Test case

var Ajv = require("ajv"),
    schema =  {
        "type": "object",
        "properties": {
            "name": {
                "type": "string",
                "pattern": "/^\w+$/"
            }   
        }
    };

var ajv = Ajv();
var validate = ajv.compile(schema);
validate({name: "John"}); // returns false

console.log(validate.errors)

[ { keyword: 'pattern',
dataPath: '.name',
message: 'should match pattern "/^w+$/"' } ]

Remote ref in definitions in remote ref with ids

"schema": {
  "id": "http://localhost:1234/issue14b.json",
  "type": "array",
  "items": { "$ref": "buu.json#/definitions/buu" }
}
{
  "id": "http://localhost:1234/buu.json",
  "definitions": {
    "buu": {
      "type": "object",
      "properties": {
        "bar": { "$ref": "bar.json" }
      }
    }
  }
}
{
  "id": "http://localhost:1234/bar.json",
  "type": "string"
}

Data:

[
  {
    "bar": "any string"
  }
]

Loses resolution scope when it gets in definitions

Cannot find module '../dotjs/ref'

The version 1.1.0 release yesterday is causing issues here:

Error: Cannot find module '../dotjs/ref'
    at Function.Module._resolveFilename (module.js:338:15)
    at Function.Module._load (module.js:280:25)
    at Module.require (module.js:364:17)
    at require (module.js:380:17)
    at Object.<anonymous> (/Users/ben/SiteTour/projects/api/node_modules/osprey-mock-service/node_modules/osprey/node_modules/osprey-method-handler/node_modules/ajv/lib/compile/_rules.js:5:11)
    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 Module.require (module.js:364:17)

What do you think - should I ask osprey-method-handler to lock AJV version to the old 1.0.x version, or perhaps AJV can release 1.1.0 as 2.0.0 instead in case other packages may hit the same issue?

Root ref in remote ref

Remote is added as http://localhost:1234/name.json:

{
  "definitions": {
    "orNull": {
      "anyOf": [
        { "type": "null" },
        { "$ref": "#" }
      ]
    }
  },
  "type": "string"
}

Schema:

{
  "id": "http://localhost:1234/object",
  "type": "object",
  "properties": {
    "name": { "$ref": "name.json#/definitions/orNull" }
  }
}

Data should be valid (and is invalid for ajv):

{  "name": "foo" }

Data should be invalid (and is valid for ajv):

{
  "name": {
    "name": null
  }
}

So essentially # in name.json refers to object.json instead of name.json.

AJV fails to compile schema with required properties that are not identifiers

The following schema fails to parse when using AJV but it does pass when pasted into http://jsonschemalint.com/draft4/

Is this a bug in AJV or am I doing something wrong with this schema that the linter isn't catching? I'm very new to AJV and JSON Schema so would definitely not rule out user error here. Thanks!

{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "title": "Create User",
    "description": "Create User POST Request",
    "type": "object",
    "properties": {
        "data": {
            "description": "Top level data object",
            "type": "object",
            "properties":{
                "type": {"type":"string"},
                "attributes": {
                    "type":"object",
                    "properties": {
                        "username":{"type":"string"},
                        "email":{"type":"string"},
                        "full-name":{"type":"string"},
                        "password":{"type":"string"},
                        "is-admin":{"type":"boolean"},
                        "enabled":{"type":"boolean"}
                    },
                    "required":["username", "email", "full-name", "password", "is-admin", "enabled"],
                    "additionalProperties": false
                }
            },
            "required":["type", "attributes"],
            "additionalProperties": false
        }
    },
    "required": ["data"],
    "additionalProperties": false
}

The error I get is:

SyntaxError: Unexpected identifier
    at Ajv.compile (/Users/sarus/workspace/rest/node_modules/ajv/lib/compile/index.js:52:10)
    at _addSchema (/Users/sarus/workspace/rest/node_modules/ajv/lib/ajv.js:163:38)
    at Ajv.compile (/Users/sarus/workspace/rest/node_modules/ajv/lib/ajv.js:75:16)
    at Object.<anonymous> (/Users/sarus/workspace/rest/lib/routes.js:20:20)
    at Module._compile (module.js:460:26)
    at Object.Module._extensions..js (module.js:478:10)
    at Module.load (module.js:355:32)
    at Function.Module._load (module.js:310:12)
    at Module.require (module.js:365:17)
    at new require (module.js:384:17)
    at Object.module.exports.start (/Users/sarus/workspace/rest/lib/server.js:13:23)
    at Object.<anonymous> (/Users/sarus/workspace/rest/hamachi.js:1:87)
    at Module._compile (module.js:460:26)
    at Object.Module._extensions..js (module.js:478:10)
    at Module.load (module.js:355:32)
    at Function.Module._load (module.js:310:12)
Error compiling schema, function code:  validate = function (data, dataPath) { 'use strict'; validate.errors = null; var errors = 0;         if ((data && typeof data === "object" && !Array.isArray(data))) {    var missing0;  if (  ( data.data === undefined && (missing0 = '.data') ) ) {  validate.errors = [ { keyword: 'required', dataPath: (dataPath || '') + "" + missing0, message: 'property ' + missing0 + ' is required'  }]; return false;  } else {    var errs0 = errors;var valid1 = true; var propertiesSchema0 = validate.schema.properties || {}; for (var key0 in data) { var isAdditional0 = propertiesSchema0[key0] === undefined;  if (isAdditional0) {  valid1 = false;   validate.errors = [ { keyword: 'additionalProperties', dataPath: (dataPath || '') + "['" + key0 + "']", message: 'additional properties NOT allowed'  }]; return false;  break;  } }   if (valid1) {  var data1 = data.data;  if (data1 === undefined) { valid1 = true; } else {   var errs_1 = errors; if ((data1 && typeof data1 === "object" && !Array.isArray(data1))) {    var missing1;  if (  ( data1.type === undefined && (missing1 = '.type') )  ||  ( data1.attributes === undefined && (missing1 = '.attributes') ) ) {   var err =   { keyword: 'required', dataPath: (dataPath || '') + ".data" + missing1, message: 'property ' + missing1 + ' is required'  }; if (validate.errors === null) validate.errors = [err]; else validate.errors.push(err); errors++;  } else {    var errs1 = errors;var valid2 = true; var propertiesSchema1 = validate.schema.properties.data.properties || {}; for (var key1 in data1) { var isAdditional1 = propertiesSchema1[key1] === undefined;  if (isAdditional1) {  valid2 = false;    var err =   { keyword: 'additionalProperties', dataPath: (dataPath || '') + ".data['" + key1 + "']", message: 'additional properties NOT allowed'  }; if (validate.errors === null) validate.errors = [err]; else validate.errors.push(err); errors++;  break;  } }   if (valid2) {  if (data1.type === undefined) { valid2 = true; } else {   var errs_2 = errors; if (typeof data1.type !== "string") {    var err =   { keyword: 'type', dataPath: (dataPath || '') + ".data.type", message: 'should be string'  }; if (validate.errors === null) validate.errors = [err]; else validate.errors.push(err); errors++;  }   var valid2 = errors === errs_2; }  if (valid2) {  var data2 = data1.attributes;  if (data2 === undefined) { valid2 = true; } else {   var errs_2 = errors; if ((data2 && typeof data2 === "object" && !Array.isArray(data2))) {    var missing2;  if (  ( data2.username === undefined && (missing2 = '.username') )  ||  ( data2.email === undefined && (missing2 = '.email') )  ||  ( data2['full-name'] === undefined && (missing2 = '['full-name']') )  ||  ( data2.password === undefined && (missing2 = '.password') )  ||  ( data2['is-admin'] === undefined && (missing2 = '['is-admin']') )  ||  ( data2.enabled === undefined && (missing2 = '.enabled') ) ) {   var err =   { keyword: 'required', dataPath: (dataPath || '') + ".data.attributes" + missing2, message: 'property ' + missing2 + ' is required'  }; if (validate.errors === null) validate.errors = [err]; else validate.errors.push(err); errors++;  } else {    var errs2 = errors;var valid3 = true; var propertiesSchema2 = validate.schema.properties.data.properties.attributes.properties || {}; for (var key2 in data2) { var isAdditional2 = propertiesSchema2[key2] === undefined;  if (isAdditional2) {  valid3 = false;    var err =   { keyword: 'additionalProperties', dataPath: (dataPath || '') + ".data.attributes['" + key2 + "']", message: 'additional properties NOT allowed'  }; if (validate.errors === null) validate.errors = [err]; else validate.errors.push(err); errors++;  break;  } }   if (valid3) {  if (data2.username === undefined) { valid3 = true; } else {   var errs_3 = errors; if (typeof data2.username !== "string") {    var err =   { keyword: 'type', dataPath: (dataPath || '') + ".data.attributes.username", message: 'should be string'  }; if (validate.errors === null) validate.errors = [err]; else validate.errors.push(err); errors++;  }   var valid3 = errors === errs_3; }  if (valid3) {  if (data2.email === undefined) { valid3 = true; } else {   var errs_3 = errors; if (typeof data2.email !== "string") {    var err =   { keyword: 'type', dataPath: (dataPath || '') + ".data.attributes.email", message: 'should be string'  }; if (validate.errors === null) validate.errors = [err]; else validate.errors.push(err); errors++;  }   var valid3 = errors === errs_3; }  if (valid3) {  if (data2['full-name'] === undefined) { valid3 = true; } else {   var errs_3 = errors; if (typeof data2['full-name'] !== "string") {    var err =   { keyword: 'type', dataPath: (dataPath || '') + ".data.attributes['full-name']", message: 'should be string'  }; if (validate.errors === null) validate.errors = [err]; else validate.errors.push(err); errors++;  }   var valid3 = errors === errs_3; }  if (valid3) {  if (data2.password === undefined) { valid3 = true; } else {   var errs_3 = errors; if (typeof data2.password !== "string") {    var err =   { keyword: 'type', dataPath: (dataPath || '') + ".data.attributes.password", message: 'should be string'  }; if (validate.errors === null) validate.errors = [err]; else validate.errors.push(err); errors++;  }   var valid3 = errors === errs_3; }  if (valid3) {  if (data2['is-admin'] === undefined) { valid3 = true; } else {   var errs_3 = errors; if (typeof data2['is-admin'] !== "boolean") {    var err =   { keyword: 'type', dataPath: (dataPath || '') + ".data.attributes['is-admin']", message: 'should be boolean'  }; if (validate.errors === null) validate.errors = [err]; else validate.errors.push(err); errors++;  }   var valid3 = errors === errs_3; }  if (valid3) {  if (data2.enabled === undefined) { valid3 = true; } else {   var errs_3 = errors; if (typeof data2.enabled !== "boolean") {    var err =   { keyword: 'type', dataPath: (dataPath || '') + ".data.attributes.enabled", message: 'should be boolean'  }; if (validate.errors === null) validate.errors = [err]; else validate.errors.push(err); errors++;  }   var valid3 = errors === errs_3; }  }}}}}} }  }  else {    var err =   { keyword: 'type', dataPath: (dataPath || '') + ".data.attributes", message: 'should be object'  }; if (validate.errors === null) validate.errors = [err]; else validate.errors.push(err); errors++;  }    var valid2 = errors === errs_2; }  }} }  }  else {    var err =   { keyword: 'type', dataPath: (dataPath || '') + ".data", message: 'should be object'  }; if (validate.errors === null) validate.errors = [err]; else validate.errors.push(err); errors++;  }    var valid1 = errors === errs_1; }  } }  }  else {   validate.errors = [ { keyword: 'type', dataPath: (dataPath || '') + "", message: 'should be object'  }]; return false;  }    return errors === 0; }

Caching limit and strategy

Hey, just wanted to say nice work on the performance improvements! It's great to see there's no upper limit in how fast a JSON validator for node can go. Caching the validator code internally is great and I guess does the trick for the benchmarks out there.

I was wondering, do you plan on introducing some caching configuration? A limit on the size/number of cached validator code, maybe together with some policy for purging stale validators (e.g. least recently used)? That would help a great deal in large-scale projects with lots of schemas, or when schemas are dynamically generated and can change a lot.

Keep up the good work!

Errors for 'required' validation should include missing property

Hi, I'm trying to get some clarity on a potential issue I'm seeing. In running the following:

const ajv = Ajv({verbose: false, allErrors: true});

ajv.addSchema([
   require('./schemas/Currency.json'),
   require('./schemas/PositiveFloatString.json'),
   require('./schemas/Amount.json'),
   require('./schemas/Party.json'),
])

function isValid(object, schemaName) {
  return ajv.validate(schemaName, object);
}

function validate(object, schemaName) {
  if (!isValid(object, schemaName)) {
    return {
      isValid: false,
      errors: ajv.errors
    };
  }
  return {
    isValid: true
  };
}

console.log(validator.validate({
        entity: 'acct:[email protected]',
        amount: {
          currency: 'USD'
        }
      }, 'Party'));

I get the following:

{ 
  isValid: false,
  errors: [{ 
    keyword: 'required',
     dataPath: '.amount',
     message: 'properties value, currency are required' 
  }]
}

Ideally I would like to see something more along the lines of:

{ 
  isValid: false,
  errors: [{ 
    keyword: 'required',
    dataPath: '.amount.value',
    message: 'property value is required' 
  }]
}

I was wondering if this was an issue with my implementation / schemas or if it is a shortcoming of ajv?

Thanks in advance.

My schemas are as follows:
Party.json

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "id": "Party",
  "title": "Party",
  "description": "Represents a single party to a payment.",
  "type": "object",
  "properties": {
    "name": {
      "$ref": "Account"
    },
    "amount": {
      "description": "How much this party will send or receive in the payment.",
      "$ref": "Amount"
    }
  },
  "additionalProperties": false,
  "required": ["name", "amount"]
}

Amount.json

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "id": "Amount",
  "title": "Amount",
  "type": "object",
  "properties": {
    "value": {
      "$ref": "PositiveFloatString"
    },
    "currency": {
      "type": "string",
      "$ref": "Currency"
    }
  },
  "additionalProperties": false,
  "required": ["value", "currency"]
}

PositiveFloatString.json

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "id": "PositiveFloatString",
  "title": "PositiveFloatString",
  "description": "A string representation of a floating point number",
  "type": "string",
  "pattern": "^[+]?[0-9]*[.]?[0-9]+([eE][-+]?[0-9]+)?$"
}

Currency.json

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "id": "Currency",
  "title": "Currency",
  "type": "string",
  "pattern": "^(([a-zA-Z0-9]{3})|([a-fA-F0-9]{40}))$"
}

default object creation

It would be perfect if ajv can create default object from the schema. Is there any way to put this feature on this lovely, fastest almost perfect ;) beauty?

With removeAdditional schemas can't be validated against schema different from draft 4 meta-schema

When schema is added, before it is compiled, it is validated against schema in $schema property (unless validateSchema option is false). If $schema property is not present draft 4 meta-schema is used.

If validator instance has removeAdditional option this schema validation may cause changing the schema (for draft 4 meta-schema it is prevented - it is compiled without this option even if this option is present).

The solution is to add removeAdditional option to validate method rather than to validator instance.

es6 / yield

How use ajv with yield ?
have you an example ?
Thanks Ami44

Pattern property is not escaped

Hi ! I have an issue with the following code :

var ajvFissiles = new Ajv().compile({
        "type" : "object",
        "patternProperties": {
            "^.+$" : {
                "type" : "object",
                "properties" :  {
                    "unit" : { "type" : "string", "enum" : ["ap", "ac", "ap", "af"]},
                    "density" : { "type" : ["string", "number"]},
                    "compositions" : { "type" : "array"}
                },
                "required" : ["unit", "compositions"],
                "additionalProperties": false
            }
        },
        "additionalProperties" : false
    });

I get the following message :

Error compiling schema, function code:   validate = function (data, dataPath) { 'use strict'; validate.errors = null; var errors = 0;              if ((data && typeof data === "object" && !Array.isArray(data))) {               var errs0 = errors;var valid1 = true; var propertiesSchema0 = validate.schema.properties || {}; for (var key0 in data) { var isAdditional0 = propertiesSchema0[key0] === undefined;  if (isAdditional0) {  if (/^.+$/.test(key0)) isAdditional0 = false;   }  if (isAdditional0) {   valid1 = false;   validate.errors = [ { keyword: 'additionalProperties', dataPath: (dataPath || '') + "['" + key0 + "']", message: 'additional properties NOT allowed'  }]; return false;   break;    } }   if (valid1) {      for (var key0 in data) { if (/^.+$/.test(key0)) {     var data1 = data[key0];    var errs_1 = errors;      if ((data1 && typeof data1 === "object" && !Array.isArray(data1))) {           if (   data1.unit === undefined   ||  data1.compositions === undefined ) {   var err =   { keyword: 'required', dataPath: (dataPath || '') + "['" + key0 + "']", message: 'properties unit, compositions are required'  }; if (validate.errors === null) validate.errors = [err]; else validate.errors.push(err); errors++;  }  else {             var errs1 = errors;var valid2 = true; var propertiesSchema1 = validate.schema.patternProperties.^.+$.properties || {}; for (var key1 in data1) { var isAdditional1 = propertiesSchema1[key1] === undefined;  if (isAdditional1) {   valid2 = false;   var err =   { keyword: 'additionalProperties', dataPath: (dataPath || '') + "['" + key0 + "']['" + key1 + "']", message: 'additional properties NOT allowed'  }; if (validate.errors === null) validate.errors = [err]; else validate.errors.push(err); errors++;   break;    } }   if (valid2) {          var data2 = data1.unit;   if (data2 === undefined) { valid2 = true; } else {     var errs_2 = errors;             var enumSchema2 = validate.schema.patternProperties.^.+$.properties['unit'].enum , valid2 = false;for (var i2=0; i2<enumSchema2.length; i2++) if (equal(data2, enumSchema2[i2])) { valid2 = true; break; } if (!valid2) {   var err =   { keyword: 'enum', dataPath: (dataPath || '') + "['" + key0 + "'].unit", message: 'should be equal to one of values'  }; if (validate.errors === null) validate.errors = [err]; else validate.errors.push(err); errors++;  }      if (errors === errs_2) {     if (typeof data2 !== "string") {   var err =   { keyword: 'type', dataPath: (dataPath || '') + "['" + key0 + "'].unit", message: 'should be string'  }; if (validate.errors === null) validate.errors = [err]; else validate.errors.push(err); errors++;  } }  var valid2 = errors === errs_2;   }     if (valid2) {          var data2 = data1.density;   if (data2 === undefined) { valid2 = true; } else {     var errs_2 = errors;       if (typeof data2 !== "string" && typeof data2 !== "number") {   var err =   { keyword: 'type', dataPath: (dataPath || '') + "['" + key0 + "'].density", message: 'should be string,number'  }; if (validate.errors === null) validate.errors = [err]; else validate.errors.push(err); errors++;  }   var valid2 = errors === errs_2;   }     if (valid2) {            if (data1.compositions === undefined) { valid2 = true; } else {     var errs_2 = errors;       if (!Array.isArray(data1.compositions)) {   var err =   { keyword: 'type', dataPath: (dataPath || '') + "['" + key0 + "'].compositions", message: 'should be array'  }; if (validate.errors === null) validate.errors = [err]; else validate.errors.push(err); errors++;  }   var valid2 = errors === errs_2;   }     }}} }    }   else {   var err =   { keyword: 'type', dataPath: (dataPath || '') + "['" + key0 + "']", message: 'should be object'  }; if (validate.errors === null) validate.errors = [err]; else validate.errors.push(err); errors++;  }      var valid1 = errors === errs_1;     if (!valid1) break;  }  else valid1 = true;  }   }     }   else {   validate.errors = [ { keyword: 'type', dataPath: (dataPath || '') + "", message: 'should be object'  }]; return false;  }      return errors === 0; }    

Do you have any idee ?

Array indices in dataPath of error messages are in quotes

Everything is working great, I'm just wondering what's the best way to make the errors easier to track down and fix in the data object.

For example, I get an error that looks like this:

{ keyword: "required",
  dataPath: ".assetGroups['166'].previewUrl",
  message: "should have required property .previewUrl" }

Tracking down assetGroup object 166 in an array of 200 of them, is not that easy. Maybe if I used some sort of a good JSON editor it would help. However, would it be possible to instead of showing number 166 perhaps use another property that is available on that assetGroup.

So let's say that my assetGroup object 166 looks like this:

{ id: "cats" }

Could the error message look more like

{ keyword: "required",
  dataPath: ".assetGroups['166'].previewUrl",
  prettyDataPath: "assetGroups[cats].previewUrl",
  message: "should have required property .previewUrl" }

It would make it a lot easier for me to find the object if I search for "cats".

Or maybe there could be a way to use the dataPath to programatically work backwords in the data to get the full objects that relate to the error?

Any suggestions are welcome :)

removeAdditional: 'all' is not working

It seems like removeAdditional can be failing in many cases unless the option validateSchema is false.

The problem is that the schema used for schema validation (meta-schema in most cases) is compiled with this option too.

Bug with allErrors: true and larger required list

Hi,

I have a rather complex JSON schema, with a required list of a sub object that has 19 items.

When I validate a JSON with the option allErrors turned on, the validation will fail, giving me a whole List of required Items which ajv claims to be missing, although I am sure they are there.

When I turn off allErrors OR reduce the required list to 10 or less items, the validation will pass.

Best regards M

Repository structure

A couple of minor (subjective) things that would go a bit to helping out others (like me) get started committing.

  • Rename bin/ to scripts/, node modules normally reserve bin/ for CLIs that the module exposes
  • Use pre-commit node module and remove bin/git-hook - it would do very similar things in the end, except the pre-commit module just works automatically (by default it'll run the tests, but you can change that if you only want to compile templates - I usually do both in my test script and I made that change with #33)
  • Make aliases for other scripts in package.json "scripts" - makes script discovery much easier and you can probably remove half the one liners you have in bin/ right now in favour of npm run bundle, npm run pretest, etc.
  • Super subjective. Look at using something like standard for linting
  • Make linting run as part of the test suite so PRs match your style
  • Add karma tests to the npm test script - I only just discovered that it's even an option and I've glanced over it a dozen times

I can make a PR with these options enabled/disabled - just let me know which you don't want.

RangeError: Maximum call stack size exceeded when using recursive reference

Correct me if I'm doing something wrong. Wrote this based on: http://spacetelescope.github.io/understanding-json-schema/index.html

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "id": "testrec",
  "type": "object",
  "properties": {
    "layout": {
      "id": "layout",
      "type": "object",
      "properties": {
        "layout": { "type": "string" },
        "panels": {
          "type": "array",
          "items": {
            "oneOf": [
              { "type": "string" },
              { "$ref": "layout" }
            ]
          }
        }
      },
      "required": [
        "layout",
        "panels"
      ]
    }
  }
}

URN wrongly reported as non-URI

var Ajv = require('ajv');
var schema = {
    "$schema": "http://json-schema.org/draft-04/schema#",
    "properties": { "id": { "type": "string", "format": "uri" } }
};
var ajv = Ajv({verbose:1});
var valid  = ajv.compile(schema);

console.log(valid({"id": "urn:isbn:978-3-531-18621-4"}));
console.log(ajv.errorsText());

I get the following output

false
No errors

compileAsync race condition

If a schema has a $ref and compileAsync is called on it while another compileAsync is running on it then ajv randomly throws. Here is an example:

var Ajv = require('ajv');

var schemas =  {
  "http://example.com/parent.json": {
    "id": "http://example.com/parent.json",
    "required": [
      "a"
    ],
    "properties": {
      "a": { "$ref": "child.json" }
    }
  },
  "http://example.com/child.json": {
    "id": "http://example.com/child.json",
    "required": [
      "b"
    ],
    "properties": {
      "b": { "type": "string" }
    }
  }
};

var ajv = Ajv({
  loadSchema: function(uri, callback) {
    setTimeout(function() {
      callback(null, schemas[uri]);
    });
  }
});

ajv.compileAsync(schemas["http://example.com/parent.json"], function(err, validate) {
  console.log(validate({a: { b: "test"} }));
});

ajv.compileAsync(schemas["http://example.com/parent.json"], function(err, validate) {
  console.log(validate({a: { b: "test"} }));
});

Which typically results in the exception:

Error: schema with key or id "http://example.com/child.json" already exists

Are there any plans for i18n-support?

We want to use ajv to validate complex configurations against predefined schemas, but our application is in German and English, so we would like to translate the error messages.
I guess the error messages are coming from def._errorMessages in lib/dot/definitions.def, so maybe we could choose one set of translations there, dependent of some variable, but I have no experience with dot-templating.

Sorry for the premature issue-creation, I accidentally hit some kind of github-shortcut.

Option to merge defaults

In JSON schema it's often useful for declare defaults, with the default value for an optional property. This is powerful for documentation, and many validators supports inserting the default into the validated object, this way you don't hardcode defaults into your code, but declare the defaults in your input schema.

Example A)

var Ajv = require('ajv');
var ajv = Ajv({mergeDefaults: true}); // Specify that we want defaults merged

var validate = ajv.compile({
  type: "object",
  properties: {
    myProp: { // optional property
      type: "string",
      default: "Hello World" // default value
    }
  }
});

var data = {
  someOtherProp: "another value"
};

validate(data); // true
console.log(data)
// {someOtherProp: "another value", myProp: "Hello World"}

This would be extremely useful, and doing this outside of the schema validation is hard, as you want to do this on all sub-objects as well, some of which may exist under an anyOf, so you can't insert the defaults until you're sure which anyOf branch is satisfied.

It's quite possible that this is a post processing step, as nested anyOf branches means you sometimes can't do this until after everything is validated. A possible work around might be to insert the defaults into a clone of the existing object, that way multiple anyOf branches shouldn't be a problem.

Note, this only really relevant for objects, but could also be done for arrays which has items: [{default: ...}, {default: ...}] (though this is a corner case). It doesn't really make sense to do this when the top-level schema type is a value type like integer as the input is either valid (ie. an integer) or invalid (ie. another type or null).

Remark, after inserting a default value, validator should validate the default value too. This should ideally be done a schema compile-time. It is important to do this, because the default value of a property which has type: 'object' may be {} and the schema for that object may specify properties for this that has additional default values. It would also be nice to get errors about inconsistencies at compile-time.

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.