pboettch / json-schema-validator

JSON schema validator for JSON for Modern C++
Other
466 stars 134 forks source link

Validating schema with nested schemas #7

Closed monstasat closed 6 years ago

monstasat commented 6 years ago

Hello!

Is it possible to use your library to validate schemas which contain not only root-level rules, but also rules for children, like this:

{"type":"object",
 "required": ["prop1"],
 "properties": {
           "prop1":{"type":"array"},
           "prop2":{"type":"object"},
           "prop3":{"type":"number"}}
}

I have tried such schema with your library, but it seems to work only for root-level, rules contained at prop1, prop2 and prop3 keys seems to be ignored. What do I need to do to validate my json with this kind of schema? Should I split my json and schema to simple objects and validate them separately or is there any more simple/correct approach?

pboettch commented 6 years ago

Yes, nested validation is supported by JSON schemas and thus by this library. Actually everything is nested in JSON schemas.

Could you give a json-document on which you would the validation to fail - based on your schema-snippet?

I tried the following json-documents, based on your schema:

{}

I got: required element 'prop1' not found in object 'root'

{
    "prop1": {}
}

Gave me: root.prop1 is object, but required type is array

{
    "prop1": [],
    "prop3": "string"
}

Resulted in: root.prop3 is string, but required type is number

By default JSON schemas are permissive. I.e. an empty schema {} will accept any json-document. Properties which are not explicitly defined in a schema will be accepted, unless "additionalProperties": "false" is specified.

monstasat commented 6 years ago

Here is my validation code. Json object j is a function argument.

    std::cout << "entered validation fn\n";

    using nlohmann::json_schema_draft4::json_validator;

    json_validator validator;
    json j_schema =
        json{{"comment", "JSON schema for test"},
             {"type", "object"},
             {"required", {"prop3"}},
             {"properties", {{"prop1", {"type", "array"}},
                             {"prop2", {"type", "object"}},
                             {"prop3", {"type", "number"}}}}};

    std::cout << "schema is: " << j_schema.dump() << "\n";
    std::cout << "json is: " << j.dump() << "\n";

    try {
        validator.set_root_schema(j_schema);
    } catch (const std::exception &e) {
        std::cout << "Validation failed, here is why: " << e.what() << "\n";
        return;
    }

    try {
        validator.validate(j);
    } catch (const std::exception &e) {
        std::cout << "Validation failed, here is why: " << e.what() << "\n";
        return;
    }

    std::cout << "Validation succeeded\n";

Here is the output:

entered validation fn                                                                                    
schema is: {"comment":"JSON schema for test","properties":{"prop1":["type","array"],"prop2":["type","object"],"prop3":["type","number"]},"required":["prop3"],"type":"object"}                           
json is: {"prop1":{},"prop3":[]}                                                                         
Validation succeeded

Json-document for validation is printed in the output, here it is: {"prop1":{},"prop3":[]} As you can see, neither prop1, nor prop3 meet the requirements of the provided schema, but the validation succeeded. But if I remove prop3 from the schema, it will result in an error as in your example. Where am I wrong with my code?

pboettch commented 6 years ago

Your JSON-schema is wrongly coded in C++. Look at the print of your schema:

"properties":{"prop1":["type","array"]}

prop1 is a property, its value needs to be an object, but is an array. This is due to your C++ code:

    json j_schema = json{{"prop1", {"type", "array"}}};

To make prop1s value an object you need an extra { }:

    json j_schema = json{{"prop1", {{"type", "array"}}}};

To quickly find this kind of problem, you could validate your schema against the json-schema.org's draft4 validation schema: Downloadable from http://json-schema.org/draft-04/schema# . This is what I did to find your problem.

monstasat commented 6 years ago

Btw, your second example

{
    "prop1": {}
}

gave me no errors. Here is the output:

entered validation fn
schema is: {"comment":"JSON schema for Options class","properties":{"prop1":["type","array"],"prop2":["type","object"],"prop3":["type","number"]},"required":["prop1"],"type":"object"} 
json is: {"prop1":{}}
Validation succeeded 

Also things are the same with the third example. Here is the output:

entered validation fn
schema is: {"comment":"JSON schema for Options class","properties":{"prop1":"type","array"],"prop2":["type","object"],"prop3":["type","number"]},"required":["prop1"],"type":"object"}
json is: {"prop1":[],"prop3":"string"}
Validation succeeded

There are rather strange differences in your and mine results. Seems that in my case nested structures are not validated. What am I doing wrong?

monstasat commented 6 years ago

Oh, my bad! Thank you for your help!

monstasat commented 6 years ago

By the way, is there a feature in your library to return all errors happened during validation or only first error found is thrown?

pboettch commented 6 years ago

If an invalid schema is used, there is nothing I can do. At one point in time I added the draft4-schema into the code to validate schemas before validating the document. But then I removed it, as it bloated the code and this can be done quite easily at the user-side.

Turning on all errors. This is not possible right now, but could be added I guess.

pboettch commented 6 years ago

Do not hesitate to close this issue, if you consider your problem to be solved.

monstasat commented 6 years ago

Thanks a lot! Closing.