diff --git a/CHANGELOG.md b/CHANGELOG.md index e0f254df..6dfac873 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ## [Unreleased] +### Added + +- Re-export `referencing::Registry` as `jsonschema::Registry`. +- `ValidationOptions::with_registry` that allows for providing a predefined `referencing::Registry`. [#682](https://github.com/Stranger6667/jsonschema/issues/682) + ## [0.28.3] - 2025-01-24 ### Fixed diff --git a/crates/jsonschema-referencing/src/registry.rs b/crates/jsonschema-referencing/src/registry.rs index a8bc6a3b..3ab5122f 100644 --- a/crates/jsonschema-referencing/src/registry.rs +++ b/crates/jsonschema-referencing/src/registry.rs @@ -336,6 +336,12 @@ impl Registry { _ => unreachable!(), } } + + pub fn resources(&self) -> impl Iterator, Arc)> { + self.resources + .iter() + .map(|(uri, resource)| (uri, Arc::clone(resource))) + } } fn process_resources( diff --git a/crates/jsonschema/src/lib.rs b/crates/jsonschema/src/lib.rs index be2ec0f3..a1568492 100644 --- a/crates/jsonschema/src/lib.rs +++ b/crates/jsonschema/src/lib.rs @@ -516,7 +516,7 @@ pub use error::{ErrorIterator, MaskedValidationError, ValidationError}; pub use keywords::custom::Keyword; pub use options::ValidationOptions; pub use output::BasicOutput; -pub use referencing::{Draft, Error as ReferencingError, Resource, Retrieve, Uri}; +pub use referencing::{Draft, Error as ReferencingError, Registry, Resource, Retrieve, Uri}; pub use validator::Validator; use serde_json::Value; diff --git a/crates/jsonschema/src/options.rs b/crates/jsonschema/src/options.rs index 7a6b4fad..e0ec8125 100644 --- a/crates/jsonschema/src/options.rs +++ b/crates/jsonschema/src/options.rs @@ -311,6 +311,42 @@ impl ValidationOptions { } self } + + /// Use external schema resources from the registry, making them accessible via references + /// during validation. + /// + /// # Example + /// + /// ```rust + /// # use serde_json::json; + /// # fn main() -> Result<(), Box> { + /// use jsonschema::{Registry, Resource}; + /// + /// let registry = Registry::try_new( + /// "urn:name-schema", + /// Resource::from_contents(json!({"type": "string"}))? + /// )?; + /// let schema = json!({ + /// "properties": { + /// "name": { "$ref": "urn:name-schema" } + /// } + /// }); + /// let validator = jsonschema::options() + /// .with_registry(registry) + /// .build(&schema)?; + /// assert!(validator.is_valid(&json!({ "name": "Valid String" }))); + /// assert!(!validator.is_valid(&json!({ "name": 123 }))); + /// # Ok(()) + /// # } + /// ``` + pub fn with_registry(&mut self, registry: referencing::Registry) -> &mut Self { + // NOTE: This is not particularly efficient, and should be changed in the future + for (uri, resource) in registry.resources() { + self.resources + .insert(uri.as_str().to_string(), (*resource).clone()); + } + self + } /// Register a custom format validator. /// /// # Example @@ -467,6 +503,7 @@ impl fmt::Debug for ValidationOptions { #[cfg(test)] mod tests { + use referencing::{Registry, Resource}; use serde_json::json; fn custom(s: &str) -> bool { @@ -484,4 +521,24 @@ mod tests { assert!(!validator.is_valid(&json!("foo"))); assert!(validator.is_valid(&json!("foo42!"))); } + + #[test] + fn with_registry() { + let registry = Registry::try_new( + "urn:name-schema", + Resource::from_contents(json!({"type": "string"})).expect("Invalid resource"), + ) + .expect("Invalid URI"); + let schema = json!({ + "properties": { + "name": { "$ref": "urn:name-schema" } + } + }); + let validator = crate::options() + .with_registry(registry) + .build(&schema) + .expect("Invalid schema"); + assert!(validator.is_valid(&json!({ "name": "Valid String" }))); + assert!(!validator.is_valid(&json!({ "name": 123 }))); + } }