JSON Schema for C++
The corvus-json-schema C library ships a header-only C17 wrapper, corvus_json_schema.hpp: the Corvus JSON Schema
evaluator for C, draft 4, 6, 7, 2019-09 and 2020-12. It wraps the C library in RAII classes and
exceptions, and gives the same results and annotations as every other Corvus implementation.
- Conformant. Passes the whole JSON-Schema-Test-Suite (required, optional and
optional/format, every draft) exceptdraft4/optional/zeroTerminatedFloats.json. - Fast. Over the jsonschema-benchmark corpora, parsing and validating takes 0.24 of the time of Blaze, and it is faster on all 37 corpora.
- Results and annotations. Basic, Detailed and Verbose results, and annotations.
- Idiomatic. Each class owns its handle through
std::unique_ptr; errors are exceptions, or status codes withtry_validatefor code built without exceptions; format validators and resolvers arestd::functions.
Install
The wrapper is in every C library package, beside the C header. With CMake:
find_package(corvus_json_schema REQUIRED)
target_link_libraries(app PRIVATE corvus_json_schema::corvus_json_schema_static) # or the shared library
Validate
#include <iostream>
#include "corvus_json_schema.hpp"
namespace cjs = corvus::json_schema;
int main() {
cjs::validator validator = cjs::validator::compile(R"({
"type": "object",
"required": ["id"],
"properties": {"id": {"type": "integer"}}
})");
std::cout << validator.is_valid(R"({"id": 3})") << '\n'; // 1
std::cout << validator.is_valid(R"({"id": "3"})") << '\n'; // 0
}
is_valid parses the text into per-thread buffers and validates it in place. To validate the same text more than
once, parse it into a cjs::document (document::parse, or document::parse_borrowed to keep the text unchanged
instead of copying it) and pass the document to is_valid. A validator and a document are immutable and can be
shared between threads.
Options
cjs::options options;
options.default_dialect(cjs::dialect::draft2019_09)
.assert_format(true)
.format("even", [](std::string_view s) { return s.size() % 2 == 0; })
.resolver([](std::string_view uri) -> std::optional<std::string> {
return std::nullopt; // the document's JSON text, or nullopt when unknown
});
cjs::validator validator = cjs::validator::compile(schema, options);
The options are those of the C library: default_dialect, assert_format, assert_format_in_legacy_drafts,
assert_content, format, resolver, base_uri, entry_point, max_depth and pattern_match_limit. Failures
throw corvus::json_schema::error, with the C library's status, the message and, for invalid JSON, the byte offset.
pattern_match_limit(std::chrono::milliseconds) is the time one match of a regular expression against one string may
take. The default is one second, and zero turns the limit off. A validation whose match reaches it throws an error
whose status() is CJS_PATTERN_MATCH_LIMIT, and the instance is then neither valid nor not valid. A schema with a
regular expression over a limit of size throws one whose status is CJS_PATTERN_TOO_LARGE. See
JSON Schema for C.
Results and annotations
cjs::collector collector(cjs::results_level::detailed);
bool valid = validator.evaluate(R"({"id": "3"})", collector);
for (std::size_t i = 0; i < collector.size(); i++) {
cjs::result_row row = collector[i];
// row.is_match, row.message, row.evaluation_location, row.schema_location, row.instance_location
}
cjs::collector verbose(cjs::results_level::verbose);
validator.evaluate(R"({"id": 3})", verbose);
std::string_view annotations = verbose.annotations_json(); // instance location -> keyword -> schema location -> value
basic records the failures without messages, detailed adds the messages, and verbose records every keyword,
passing ones and annotations included.
Links
- Releases: capi-v releases
- Source and design: src-rs/corvus-json-schema-capi
- The other languages: see Other languages