A fast, simple, and user-friendly JSON Schema validator for Rust, with Python bindings.
In the world of data validation, ensuring your data conforms to a specified structure is crucial.
At hiop, we sought a language-agnostic format to define how data should be structured, and JSON Schema stood out as the perfect solution.
This inspired the creation of rsonschema, a fast,
simple, and user-friendly JSON Schema validator for Rust.
Rust is celebrated for its performance and safety capabilities. These attributes make it an excellent choice for building a fast, user-friendly, secure, and efficient validator.
-
jsonschema: was previously our choice, offering robust validation but suffering from complex error handling. For example:
jsonschema::error::ValidationErrorborrows theinstanceattribute, adding complexity.- it lacks useful error messages for end users, especially when validating schemas with Schema Composition failures.
-
valico: like
jsonschema, it has complex error handling. Moreover it is not actively maintained. -
schemars: a de facto standard for schema generation with over 19 million downloads. However, it lacks validation APIs.
Add rsonschema to your Cargo.toml:
cargo add rsonschemaHere's how you can start using rsonschema in your Rust project:
let schema = serde_json::json!({
"$schema": "https://json-schema.org/draft/2020-12/schema",
"minLength": 3
});
let instance = serde_json::json!("foo");
let report = rsonschema::validate(
&instance,
schema.clone(),
);
assert!(report.is_valid());
let instance = serde_json::json!("a");
let report = rsonschema::validate(
&instance,
schema,
);
assert_eq!(
report,
rsonschema::ValidationReport {
errors: Some(
rsonschema::error::ValidationErrors::from([
rsonschema::error::ValidationError {
instance: serde_json::json!("a"),
type_: rsonschema::error::type_::ValidationErrorType::MinLength {
limit: 3.into(),
},
..Default::default()
}
])
),
..Default::default()
}
);Install from PyPI (requires Python >= 3.10):
pip install rsonschemaimport rsonschema
schema = {"$schema": "https://json-schema.org/draft/2020-12/schema", "minLength": 3}
# validate(instance, schema, pointer=None, ref_resolver=None)
errors = rsonschema.validate("foo", schema, None, None)
assert errors == []
errors = rsonschema.validate("a", schema, None, None)
assert len(errors) == 1
assert str(errors[0]) # human-readable error descriptionOne of rsonschema's key strengths is the quality of its human-readable error messages.
Each error includes the failing value, the full path to it within the document,
and a precise description — making them suitable to display directly to end users.
let schema = serde_json::json!({
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "string",
"minLength": 5
});
let report = rsonschema::validate(&serde_json::json!("hi"), schema);
let error = report.errors.unwrap().into_iter().min().unwrap();
println!("{error}");
// "hi": must be longer than `5` charactersThe pointer tracks the full path from the document root to the failing value:
let schema = serde_json::json!({
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"user": {
"required": ["name", "email"]
}
}
});
let report = rsonschema::validate(
&serde_json::json!({"user": {"name": "Alice"}}),
schema,
);
let error = report.errors.unwrap().into_iter().min().unwrap();
println!("{error}");
// {"name":"Alice"} at `user`: missing required: `email`When validation fails on a composition keyword,
rsonschema surfaces the most relevant inner error
rather than a generic "did not match any schema" message.
Relevance is determined by how closely the instance resembles each branch,
using string similarity on values and property names.
let schema = serde_json::json!({
"$schema": "https://json-schema.org/draft/2020-12/schema",
"anyOf": [
{"type": "string", "minLength": 5},
{"type": "integer", "minimum": 10}
]
});
let report = rsonschema::validate(&serde_json::json!("hi"), schema);
let error = report.errors.unwrap().into_iter().min().unwrap();
println!("{error}");
// "hi": must be longer than `5` characters"hi" is clearly closer to the string branch,
so the minLength error from that branch is surfaced
instead of a generic composition failure.
The same messages are available via the .message attribute on each error object:
import rsonschema
schema = {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"user": {"required": ["name", "email"]}
},
}
errors = rsonschema.validate({"user": {"name": "Alice"}}, schema, None, None)
print(str(errors[0]))
# {"name":"Alice"} at `user`: missing required: `email`rsonschema is benchmarked against jsonschema across representative scenarios.
Selected results on Apple M3 (lower is better):
| Scenario | rsonschema | jsonschema (cold) |
|---|---|---|
| Simple string validation | 738 ns | 2.14 µs |
| Complex object (5 fields) | 6.85 µs | 8.95 µs |
| Array of 50 objects | 54.0 µs | 7.74 µs |
anyOf composition |
3.25 µs | 4.91 µs |
Cold means the competitor also compiles the schema on every call, matching rsonschema's usage model.
See BENCHMARKS.md for the full methodology and results, including Python bindings.
rsonschema targets a specific, well-defined subset of JSON Schema:
- Draft: only the latest
(
2020-12) specification is supported. Older drafts are not. - Validation only: the library validates instances against schemas and reports errors — it does not generate schemas or produce annotation output.
- All standard keywords are implemented, including schema composition
(
allOf,anyOf,oneOf,not), conditionals (if/then/else), references ($ref,$anchor), unevaluated keywords (unevaluatedProperties,unevaluatedItems), and format assertions. - Intentionally unsupported: dynamic keywords
$dynamicAnchorand$dynamicRefare excluded because they introduce significant complexity with limited practical benefit.
All official JSON Schema Test Suite tests,
located in the tests folder, pass — except for the
unsupported dynamic keywords above.
We firmly believe that collaboration is the key to innovation!
If you find a bug or have a feature request, please open an issue. If you want to go further and tackle it, open a pull request on our GitHub repository.
See CONTRIBUTING.md for development guidelines.
rsonschema is licensed under the Apache-2.0 License.
See the LICENSE file for more details.