validator: update API so that the root-schema-insertion can be located in a try-catch-block

This commit is contained in:
Patrick Boettcher 2016-12-27 13:50:45 +01:00
parent 8939ba9b05
commit 5e9605b055
5 changed files with 80 additions and 41 deletions

View File

@ -2,23 +2,38 @@
# What is it? # What is it?
This is a C++ header-only library for validating JSON documents based on a This is a C++ library for validating JSON documents based on a
[JSON Schema](http://json-schema.org/) which itself should validate with [JSON Schema](http://json-schema.org/) which itself should validate with
[draft-4 of JSON Schema Validation](http://json-schema.org/schema). [draft-4 of JSON Schema Validation](http://json-schema.org/schema).
First a disclaimer: *Everything here should be considered work in progress and First a disclaimer: *It is work in progress and
contributions or hints or discussions are welcome.* contributions or hints or discussions are welcome.*
Niels Lohmann et al develop a great JSON parser for C++ called [JSON for Modern Niels Lohmann et al develop a great JSON parser for C++ called [JSON for Modern
C++](https://github.com/nlohmann/json). This validator is based on this C++](https://github.com/nlohmann/json). This validator is based on this
library, hence the name. library, hence the name.
The name is for the moment purely marketing, because there is, IMHO, not much The name is for the moment purely marketing, because there is, IMHO, not so much
modern C++ inside. But I think the whole thing could be rewritten mode "modern". modern C++ inside. There is plenty of space to make it more modern.
External documentation is missing as well. However the API of the validator External documentation is missing as well. However the API of the validator
will be rather simple. will be rather simple.
# Design goals
The main goal of this validator is to produce *human-comprehensible* error
messages if a JSON-document/instance does not comply with its schema. This is
done with exceptions thrown at the users with a helpful message telling what's
wrong with the document while validating.
Another goal was to use Niels Lohmann's JSON-library. This is why the validator
lives in his namespace.
# Weaknesses
Schema-reference resolution is not recursivity-proven: If there is a nested
cross-schema reference, it will not stop. (Though I haven't tested it)
# How to use # How to use
## Build ## Build
@ -44,9 +59,11 @@ add_library(json-hpp INTERFACE)
target_include_directories(json-hpp target_include_directories(json-hpp
INTERFACE INTERFACE
path/to/json.hpp) path/to/json.hpp)
set(JSON_SCHEMA_TEST_SUITE_PATH "path/to/json-schema-test-suite")
# set this path to schema-test-suite to get tests compiled - optional
set(JSON_SCHEMA_TEST_SUITE_PATH "path/to/json-schema-test-suite")
enable_testing() # if you want to inherit tests enable_testing() # if you want to inherit tests
add_subdirectory(path-to-this-project json-schema-validator) add_subdirectory(path-to-this-project json-schema-validator)
``` ```
@ -58,20 +75,37 @@ See also `app/json-schema-validate.cpp`.
#include "json-schema-validator.hpp" #include "json-schema-validator.hpp"
using nlohmann::json; using nlohmann::json;
using nlohmann::json_validator; using nlohmann::json_uri;
using nlohmann::json_schema_draft4::json_validator;
static void loader(const json_uri &uri, json &schema)
{
// get the schema from uri and feed it into schema
// if not possible, otherwise, throw an excpetion
}
int main(void) int main(void)
{ {
json schema, document; json schema;
/* fill in the schema */ /* json-parse the schema */
/* fill in the document */
json_validator validator; json_validator validator(loader); // create validator with a loader-callback
try { try {
validator.validate(document, scheam); validator.set_root_schema(schema); // insert root-schema
} catch (const std::out_of_range &e) { } catch (const std::exception &e) {
std::cerr << "Validation failed, here is why: " << e.what() << "\n";
return EXIT_FAILURE;
}
json document;
/* json-parse the document */
try {
validator.validate(document); // validate the document
} catch (const std::exception &e) {
std::cerr << "Validation failed, here is why: " << e.what() << "\n"; std::cerr << "Validation failed, here is why: " << e.what() << "\n";
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@ -84,15 +118,19 @@ int main(void)
There is an application which can be used for testing the validator with the There is an application which can be used for testing the validator with the
[JSON-Schema-Test-Suite](https://github.com/json-schema-org/JSON-Schema-Test-Suite). [JSON-Schema-Test-Suite](https://github.com/json-schema-org/JSON-Schema-Test-Suite).
Currently **72** of ~**308** tests are still failing, because simply not all keywords and If you have cloned this repository providing a path the repository-root via the
their functionalities have been implemented. Some of the missing feature will cmake-variable `JSON_SCHEMA_TEST_SUITE_PATH` will enable the test-target(s).
require a rework. Some will only work with external libraries. (remote references)
Currently **31** of **304** tests are failing:
- 22 of them are `format`-strings which are not supported.
- 3 of them are because `pattern` is not implemented for strings
- and 6 bugs
# Additional features # Additional features
## Default value population ## Default values
For my use case I need something to populate default values into the JSON The goal is to create an empty document, based on schema-defined
instance of properties which are not set by the user. default-values, recursively populated.
This feature can be enable by setting the `default_value_insertion` to true.

View File

@ -80,7 +80,9 @@ int main(void)
const auto &schema = test_group["schema"]; const auto &schema = test_group["schema"];
json_validator validator(schema, loader); json_validator validator(loader);
validator.set_root_schema(schema);
for (auto &test_case : test_group["tests"]) { for (auto &test_case : test_group["tests"]) {
std::cout << " Testing Case " << test_case["description"] << "\n"; std::cout << " Testing Case " << test_case["description"] << "\n";

View File

@ -80,9 +80,17 @@ int main(int argc, char *argv[])
return EXIT_FAILURE; return EXIT_FAILURE;
} }
// 2) insert this schema to the validator // 2) create the validator and
json_validator validator(loader);
try {
// insert this schema as the root to the validator
// this resolves remote-schemas, sub-schemas and references via the given loader-function // this resolves remote-schemas, sub-schemas and references via the given loader-function
json_validator validator(schema, loader); validator.set_root_schema(schema);
} catch (std::exception &e) {
std::cerr << "setting root schema failed\n";
std::cerr << e.what() << "\n";
}
// 3) do the actual validation of the document // 3) do the actual validation of the document
json document; json document;

View File

@ -170,24 +170,16 @@ class json_validator
void insert_schema(const json &input, const json_uri &id); void insert_schema(const json &input, const json_uri &id);
public: public:
json_validator(const json &schema, std::function<void(const json_uri &, json &)> loader); json_validator(std::function<void(const json_uri &, json &)> loader = nullptr)
: schema_loader_(loader)
{
}
// insert and set a root-schema
void set_root_schema(const json &);
// validate a json-document based on the root-schema
void validate(json &instance); void validate(json &instance);
// insert default values items into object
// if the key is not present before checking their
// validity in regards to their schema
//
// breaks JSON-Schema-Test-Suite if true
// *PARTIALLY IMPLEMENTED* only for properties of objects
bool default_value_insertion = false;
// recursively insert default values and create parent objects if
// they would be empty
//
// breaks JSON-Schema-Test-Suite if true
// *NOT YET IMPLEMENTED* -> maybe the same as the above option, need more thoughts
bool recursive_default_value_insertion = false;
}; };
} // json_schema_draft4 } // json_schema_draft4

View File

@ -326,8 +326,7 @@ void json_validator::validate(json &instance)
validate(instance, *root_schema_, "root"); validate(instance, *root_schema_, "root");
} }
json_validator::json_validator(const json &schema, std::function<void(const json_uri &, json &)> loader) void json_validator::set_root_schema(const json &schema)
: schema_loader_(loader)
{ {
insert_schema(schema, json_uri("#")); insert_schema(schema, json_uri("#"));
} }