1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
//! An implementation of [JSON Type Definition](https://jsontypedef.com), [RFC //! 8927](https://tools.ietf.org/html/rfc8927). //! //! `jtd` lets you parse and ensure the validity of JSON Typedef schemas, and //! then validate JSON data against those schemas. If your goal is instead to //! generate Rust types from JSON Typedef schemas, see //! [`jtd-codegen`](https://github.com/jsontypedef/json-typedef-codegen). //! //! # Quick start //! //! Here's how you can parse a JSON Typedef schema and then use it to validate //! data against that schema. //! //! ``` //! use jtd::Schema; //! use serde_json::json; //! //! let schema = Schema::from_serde_schema( //! serde_json::from_value(json!({ //! "properties": { //! "foo": { "type": "string" }, //! "bar": { "type": "boolean" } //! } //! })) //! .expect("Parse schema"), //! ) //! .expect("Construct schema from JSON data"); //! //! schema.validate().expect("Invalid schema"); //! //! // This input is ok, so validate comes back empty. //! let input_ok = json!({ "foo": "xxx", "bar": true }); //! assert!(jtd::validate(&schema, &input_ok, Default::default()).unwrap().is_empty()); //! //! // This input is bad (bar has type string, not boolean), so validate does //! // not come back empty. //! let input_bad = json!({ "foo": "xxx", "bar": "false" }); //! assert!(!jtd::validate(&schema, &input_bad, Default::default()).unwrap().is_empty()); //! ``` //! //! Or, at a high level: //! //! 1. Use `serde_json` to parse JSON data into a [`SerdeSchema`]. //! 2. Convert that into a [`Schema`] using [`Schema::from_serde_schema`]. //! 3. Optionally, ensure that schema is "valid" using [`Schema::validate`]. //! 4. Verify data against that schema using [`validate()`]. //! //! # Common usage //! //! The example above shows you how you can quickly use JSON Typedef to check //! whether data is valid. But in the real world, you usually want to know what //! the validation errors were, rather than just flatly rejecting input as //! "invalid" without any further details. //! //! One benefit of JSON Type Definition is that the exact data inside the //! validation errors is part of the specification; that means validation errors //! are portable. Here's an example of what those validation errors look like, //! and how you can access them with this crate. //! //! ``` //! use jtd::{Schema, ValidationErrorIndicator}; //! use serde_json::json; //! //! let schema = Schema::from_serde_schema( //! serde_json::from_value(json!({ //! "properties": { //! "name": { "type": "string" }, //! "age": { "type": "uint32" }, //! "phones": { //! "elements": { //! "type": "string" //! } //! } //! } //! })) //! .expect("Parse schema"), //! ) //! .expect("Construct schema from JSON data"); //! //! schema.validate().expect("Invalid schema"); //! //! // Since this first example is valid, we'll get back an empty list of //! // validation errors. //! let input_ok = json!({ //! "name": "John Doe", //! "age": 43, //! "phones": ["+44 1234567", "+44 2345678"] //! }); //! //! assert_eq!( //! Vec::<ValidationErrorIndicator>::new(), //! jtd::validate(&schema, &input_ok, Default::default()).unwrap(), //! ); //! //! // This example is invalid, so we'll get back three validation errors: //! // //! // 1. "name" is required but not present, //! // 2. "age" has the wrong type //! // 3. "phones[1]" has the wrong type //! let input_bad = json!({ //! "age": "43", //! "phones": ["+44 1234567", 442345678] //! }); //! //! // Each error indicator has two pieces of information: the path to the part //! // of the input that was rejected (the "instance path"), and the part of the //! // schema that rejected it (the "schema path"). //! // //! // The exact values of the instance path and schema path is specified in the //! // JSON Type Definition spec. //! assert_eq!( //! vec![ //! // "age" has the wrong type (required by "/properties/age/type") //! ValidationErrorIndicator { //! instance_path: vec!["age".into()], //! schema_path: vec!["properties".into(), "age".into(), "type".into()], //! }, //! //! // "name" is missing (required by "/properties/name") //! ValidationErrorIndicator { //! instance_path: vec![], //! schema_path: vec!["properties".into(), "name".into()], //! }, //! //! // "phones/1" has the wrong type (required by "/properties/phones/elements/type") //! ValidationErrorIndicator { //! instance_path: vec!["phones".into(), "1".into()], //! schema_path: vec![ //! "properties".into(), //! "phones".into(), //! "elements".into(), //! "type".into() //! ], //! }, //! ], //! jtd::validate(&schema, &input_bad, Default::default()).unwrap(), //! ); //! ``` //! //! # Advanced usage //! //! The examples above skim over some details of how you can use this crate. //! Here are pieces of documentation that you may find relevant: //! //! * If you want to convert JSON Type Defintion schemas to/from JSON, and //! validate whether a schema is valid, see [`SerdeSchema`], //! [`Schema::from_serde_schema`], and [`Schema::validate`]. //! //! * If you want better performance out of [`validate()`], see //! [`ValidateOptions`] to see how you can make validation faster. //! //! # Security considerations //! //! If you're running [`validate()`] with untrusted schemas (untrusted inputs is //! fine), then be aware of this security consideration from RFC 8927: //! //! > Implementations that evaluate user-inputted schemas SHOULD implement //! > mechanisms to detect and abort circular references that might cause a //! > naive implementation to go into an infinite loop. Without such //! > mechanisms, implementations may be vulnerable to denial-of-service //! > attacks. //! //! This crate supports that "detect and abort" mechanism via //! [`ValidateOptions::with_max_depth`]. Please see that documentation if you're //! validating data against untrusted schemas. mod schema; mod serde_schema; mod validate; pub use schema::*; pub use serde_schema::*; pub use validate::*;