jsonschema_valid_compat/
lib.rs

1//! # jsonschema-valid
2//!
3//! A simple crate to perform [JSON Schema](https://json-schema.org/) validation.
4//!
5//! Supports JSON Schema drafts 4, 6, and 7.
6//!
7//! ## Example:
8//!
9//! The following example validates some JSON data against a draft 6 JSON schema.
10//!
11//! ```rust
12//! # extern crate serde_json;
13//! # extern crate lazy_static;
14//! # extern crate jsonschema_valid_compat as jsonschema_valid;
15//! # fn main() -> Result<(), Box<dyn std::error::Error + 'static>> {
16//! # use serde_json::Value;
17//! # use jsonschema_valid::schemas;
18//! # let schema_json = "{}";
19//! # let your_json_data = "{}";
20//! let schema: Value = serde_json::from_str(schema_json)?;
21//! let data: Value = serde_json::from_str(your_json_data)?;
22//! let cfg = jsonschema_valid::Config::from_schema(&schema, Some(schemas::Draft::Draft6))?;
23//! // Validate the schema itself
24//! assert!(cfg.validate_schema().is_ok());
25//! // Validate a JSON instance against the schema
26//! assert!(cfg.validate(&data).is_ok());
27//!
28//! # Ok(()) }
29//! ````
30#![warn(missing_docs)]
31
32extern crate serde_json;
33extern crate lazy_static;
34extern crate itertools;
35extern crate regex;
36extern crate url;
37extern crate chrono;
38extern crate iri_string;
39extern crate json_ptr as json_pointer;
40extern crate percent_encoding;
41extern crate textwrap;
42
43
44use serde_json::Value;
45
46mod config;
47mod context;
48mod error;
49mod format;
50mod resolver;
51pub mod schemas;
52mod unique;
53mod util;
54mod validators;
55
56pub use crate::config::Config;
57use crate::context::Context;
58pub use crate::error::{ErrorIterator, ValidationError};
59
60/// Validates a given JSON instance against a given JSON schema, returning the
61/// errors, if any. draft may provide the schema draft to use. If not provided,
62/// it will be determined automatically from the schema.
63///
64/// # Arguments
65///
66/// * `cfg`: The configuration object to use
67/// * `instance`: The JSON document to validate
68///
69/// # Returns
70///
71/// * `errors`: A `Result` indicating whether there were any validation errors.
72///   If `Ok(())`, the `instance` is valid against `schema`. If `Err(e)`, `e` is
73///   an iterator over all of the validation errors.
74///
75/// ## Example:
76///
77/// The following example validates some JSON data against a draft 6 JSON schema.
78///
79/// ```rust
80/// # extern crate serde_json;
81/// # extern crate lazy_static;
82/// # extern crate jsonschema_valid_compat as jsonschema_valid;
83/// # fn main() -> Result<(), Box<dyn std::error::Error + 'static>> {
84/// # use serde_json::Value;
85/// # use jsonschema_valid::{schemas, Config};
86/// # let schema_json = "{\"type\": \"integer\"}";
87/// # let your_json_data = "\"string\"";
88/// let schema: Value = serde_json::from_str(schema_json)?;
89/// let data: Value = serde_json::from_str(your_json_data)?;
90/// let cfg = jsonschema_valid::Config::from_schema(&schema, Some(schemas::Draft::Draft6))?;
91///
92/// let mut validation = jsonschema_valid::validate(&cfg, &data);
93/// if let Err(errors) = validation {
94///     for error in errors {
95///         println!("Error: {}", error);
96///     }
97/// }
98///
99/// # Ok(()) }
100/// ````
101pub fn validate<'a>(
102    cfg: &'a config::Config<'a>,
103    instance: &'a Value,
104) -> Result<(), ErrorIterator<'a>> {
105    let mut errors = validators::descend(
106        cfg,
107        instance,
108        cfg.get_schema(),
109        None,
110        Context::new_from(cfg.get_schema()),
111    )
112    .peekable();
113
114    if errors.peek().is_none() {
115        Ok(())
116    } else {
117        Err(Box::new(errors))
118    }
119}
120
121#[cfg(test)]
122mod tests {
123    use super::*;
124
125    use std::fs;
126    use std::path::PathBuf;
127
128    // Test files we know will fail.
129    const KNOWN_FAILURES: &'static [&'static str] = &["refRemote.json"];
130
131    fn test_draft(dirname: &str, draft: schemas::Draft) {
132        let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
133        path.push("JSON-Schema-Test-Suite/tests");
134        path.push(dirname);
135
136        let paths = fs::read_dir(path).unwrap();
137
138        for entry in paths {
139            let dir_entry = &entry.unwrap();
140            if KNOWN_FAILURES.contains(&dir_entry.file_name().to_str().unwrap()) {
141                continue;
142            }
143
144            let path = dir_entry.path();
145            if path.extension().map_or_else(|| "", |x| x.to_str().unwrap()) == "json" {
146                println!("Testing {:?}", path.display());
147                let file = fs::File::open(path).unwrap();
148                let json: Value = serde_json::from_reader(file).unwrap();
149                for testset in json.as_array().unwrap().iter() {
150                    println!(
151                        "  Test set {}",
152                        testset.get("description").unwrap().as_str().unwrap()
153                    );
154                    let schema = testset.get("schema").unwrap();
155                    let tests = testset.get("tests").unwrap();
156                    for test in tests.as_array().unwrap().iter() {
157                        println!(
158                            "    Test {}",
159                            test.get("description").unwrap().as_str().unwrap()
160                        );
161                        let data = test.get("data").unwrap();
162                        let valid = test.get("valid").unwrap();
163                        if let Value::Bool(expected_valid) = valid {
164                            let cfg = config::Config::from_schema(&schema, Some(draft)).unwrap();
165                            assert!(cfg.validate_schema().is_ok());
166                            let result = validate(&cfg, &data);
167                            assert_eq!(result.is_ok(), *expected_valid);
168                            let cfg2 = config::Config::from_schema(&schema, Some(draft)).unwrap();
169                            let result2 = cfg2.validate(&data);
170                            assert!(cfg2.validate_schema().is_ok());
171                            assert_eq!(result2.is_ok(), *expected_valid);
172                        }
173                    }
174                }
175            }
176        }
177    }
178
179    #[test]
180    fn test_draft7() {
181        test_draft("draft7", schemas::Draft::Draft7);
182    }
183
184    #[test]
185    fn test_draft6() {
186        test_draft("draft6", schemas::Draft::Draft6);
187    }
188
189    #[test]
190    fn test_draft4() {
191        test_draft("draft4", schemas::Draft::Draft4);
192    }
193}