1
1
2
2
[ ![ Build Status] ( https://travis-ci.org/pboettch/json-schema-validator.svg?branch=master )] ( https://travis-ci.org/pboettch/json-schema-validator )
3
3
4
- # Modern C++ JSON schema validator
4
+ # JSON schema validator for JSON for Modern C++
5
5
6
6
# What is it?
7
7
8
8
This is a C++ library for validating JSON documents based on a
9
9
[ JSON Schema] ( http://json-schema.org/ ) which itself should validate with
10
- [ draft-4 of JSON Schema Validation] ( http://json-schema.org/schema ) .
10
+ [ draft-7 of JSON Schema Validation] ( http://json-schema.org/schema ) .
11
11
12
12
First a disclaimer: * It is work in progress and
13
- contributions or hints or discussions are welcome.*
13
+ contributions or hints or discussions are welcome.* Even though a 2.0.0 release is immenent.
14
14
15
15
Niels Lohmann et al develop a great JSON parser for C++ called [ JSON for Modern
16
16
C++] ( https://github.com/nlohmann/json ) . This validator is based on this
17
17
library, hence the name.
18
18
19
- The name is for the moment purely marketing, because there is, IMHO, not so much
20
- modern C++ inside. There is plenty of space to make it more modern.
21
-
22
19
External documentation is missing as well. However the API of the validator
23
- will be rather simple.
20
+ is rather simple.
21
+
22
+ # New in version 2
23
+
24
+ Although significant changes have been coorporate to the 2 version
25
+ (a complete rewrite) the API is compatible with the 1.0.0 release. Except for
26
+ the namespace which is now `nlohmann::json_schema.
27
+
28
+ Version ** 2** supports JSON schema draft 7, whereas 1 was supporting draft 4
29
+ only. Please update your schemas.
30
+
31
+ The primary change in 2 is the way a schema is used. While in version 1 the schema was
32
+ kept as a JSON-document and used again and again during validation, in versin 2 the schema
33
+ is parsed into compiled C++ objects which are then used during validation. There are surely
34
+ still optimizations to be done, but validation speed has improved by factor 100
35
+ or more.
36
+
37
+ In JSON-schema one sub-schema can be
24
38
25
39
# Design goals
26
40
27
41
The main goal of this validator is to produce * human-comprehensible* error
28
- messages if a JSON-document/instance does not comply with its schema. This is
29
- done with exceptions thrown at the users with a helpful message telling what's
30
- wrong with the document while validating.
42
+ messages if a JSON-document/instance does not comply to its schema.
43
+
44
+ By default this is done with exceptions thrown at the users with a helpful
45
+ message telling what's wrong with the document while validating.
46
+
47
+ With ** 2.0.0** the user can passed a ` json_scheam::basic_error_handler ` derived object
48
+ along with the instance to validate to receive a each time a validation error occurs
49
+ and decice what to do (throwing, counting, collecting).
31
50
32
51
Another goal was to use Niels Lohmann's JSON-library. This is why the validator
33
52
lives in his namespace.
34
53
35
54
# Weaknesses
36
55
37
- Schema-reference resolution is not recursivity-proven: If there is a nested
38
- cross-schema reference, it will not stop. (Though I haven't tested it)
39
-
40
- Numerical validation uses ` int64_t ` , ` uint64_t ` or ` double ` , depending on if
56
+ Numerical validation uses nlohmann integer, unsigned and floating point types, depending on if
41
57
the schema type is "integer" or "number". Bignum (i.e. arbitrary precision and
42
58
range) is not supported at this time.
43
59
44
- Unsigned integer validation will only take place if the following two conditions are true:
45
- - The nlohmann ` type() ` of the json object under validation is ` nlohmann::json::value_t::number_unsigned `
46
- - The schema specifies a numerical minimum greater than or equal to 0
60
+ Currently JSON-URI with "plain name fragments" are not supported. So referring to an URI
61
+ with ` $ref: "file.json#plain" ` will not work.
47
62
48
63
# How to use
49
64
50
- The current state of the build-system needs at least version ** 3.1.1 ** of NLohmann's
65
+ The current state of the build-system needs at least version ** 3.5.0 ** of NLohmann's
51
66
JSON library. It is looking for the ` json.hpp ` within a ` nlohmann/ ` -path.
52
67
53
68
When build the library you need to provide the path to the directory where the include-file
@@ -66,7 +81,7 @@ cmake .. \
66
81
-DNLOHMANN_JSON_DIR=< path/to/> nlohmann/json.hpp \
67
82
-DJSON_SCHEMA_TEST_SUITE_PATH=< path/to/JSON-Schema-test-suite> # optional
68
83
make # install
69
- ctest # if test-suite has been given
84
+ ctest # run unit, non-regression and test-suite tests
70
85
```
71
86
### As a subdirectory from within
72
87
@@ -93,7 +108,6 @@ In your initial call to cmake simply add:
93
108
``` bash
94
109
cmake -DBUILD_SHARED_LIBS=ON
95
110
```
96
-
97
111
## Code
98
112
99
113
See also ` app/json-schema-validate.cpp ` .
@@ -104,13 +118,12 @@ See also `app/json-schema-validate.cpp`.
104
118
#include " json-schema.hpp"
105
119
106
120
using nlohmann::json;
107
- using nlohmann::json_uri;
108
- using nlohmann::json_schema_draft4::json_validator;
121
+ using nlohmann::json_schema::json_validator;
109
122
110
123
// The schema is defined based upon a string literal
111
124
static json person_schema = R"(
112
125
{
113
- "$schema": "http://json-schema.org/draft-04 /schema#",
126
+ "$schema": "http://json-schema.org/draft-07 /schema#",
114
127
"title": "A person",
115
128
"properties": {
116
129
"name": {
@@ -137,55 +150,74 @@ static json person_schema = R"(
137
150
static json bad_person = {{"age", 42}};
138
151
static json good_person = {{"name", "Albert"}, {"age", 42}};
139
152
140
- int main(){
141
-
142
- /* json-parse the schema */
143
-
144
- json_validator validator; // create validator
145
-
146
- try {
147
- validator.set_root_schema(person_schema); // insert root-schema
148
- } catch (const std::exception &e) {
149
- std::cerr << "Validation of schema failed, here is why: " << e.what() << "\n";
150
- return EXIT_FAILURE;
151
- }
152
-
153
- /* json-parse the people */
154
-
155
- for (auto &person : {bad_person, good_person})
156
- {
157
- std::cout << "About to validate this person:\n" << std::setw(2) << person << std::endl;
158
- try {
159
- validator.validate(person); // validate the document
160
- std::cout << "Validation succeeded\n";
161
- } catch (const std::exception &e) {
162
- std::cerr << "Validation failed, here is why: " << e.what() << "\n";
163
- }
164
- }
165
- return EXIT_SUCCESS;
153
+ int main()
154
+ {
155
+ /* json-parse the schema */
156
+
157
+ json_validator validator; // create validator
158
+
159
+ try {
160
+ validator.set_root_schema(person_schema); // insert root-schema
161
+ } catch (const std::exception &e) {
162
+ std::cerr << "Validation of schema failed, here is why: " << e.what() << "\n";
163
+ return EXIT_FAILURE;
164
+ }
165
+
166
+ /* json-parse the people - API of 1.0.0, default throwing error handler */
167
+
168
+ for (auto &person : {bad_person, good_person}) {
169
+ std::cout << "About to validate this person:\n"
170
+ << std::setw(2) << person << std::endl;
171
+ try {
172
+ validator.validate(person); // validate the document
173
+ std::cout << "Validation succeeded\n";
174
+ } catch (const std::exception &e) {
175
+ std::cerr << "Validation failed, here is why: " << e.what() << "\n";
176
+ }
177
+ }
178
+
179
+ /* json-parse the people - with custom error handler */
180
+ class custom_error_handler : public nlohmann::json_schema::basic_error_handler
181
+ {
182
+ void error(const std::string &path, const json &instance, const std::string &message) override
183
+ {
184
+ nlohmann::json_schema::basic_error_handler::error (path, instance, message);
185
+ std::cerr << "ERROR: '" << path << "' - '" << instance << "': " << message << "\n";
186
+ }
187
+ };
188
+
189
+
190
+ for (auto &person : {bad_person, good_person}) {
191
+ std::cout << "About to validate this person:\n"
192
+ << std::setw(2) << person << std::endl;
193
+
194
+ custom_error_handler err;
195
+ validator.validate(person, err); // validate the document - uses the default throwing error-handler
196
+
197
+ if (err)
198
+ std::cerr << "Validation failed\n";
199
+ else
200
+ std::cout << "Validation succeeded\n";
201
+ }
202
+
203
+ return EXIT_SUCCESS;
166
204
}
167
-
168
205
```
169
206
170
207
# Compliance
171
208
172
209
There is an application which can be used for testing the validator with the
173
210
[JSON-Schema-Test-Suite](https://github.com/json-schema-org/JSON-Schema-Test-Suite).
211
+ In order to simplify the testing, the test-suite is included in the repository.
174
212
175
213
If you have cloned this repository providing a path the repository-root via the
176
214
cmake-variable `JSON_SCHEMA_TEST_SUITE_PATH` will enable the test-target(s).
177
215
178
216
All required tests are **OK**.
179
217
180
- **12** optional tests of **305** total (required + optional) tests are failing:
181
-
182
- - 10 of them are `format`-strings which are not supported.
183
- - big numbers are not working (2)
184
-
185
218
# Additional features
186
219
187
220
## Default values
188
221
189
222
The goal is to create an empty document, based on schema-defined
190
223
default-values, recursively populated.
191
-
0 commit comments