does_it_json/
lib.rs

1use schema::validate_schema_object;
2use schemars::{schema::RootSchema, schema_for, JsonSchema};
3use serde::Serialize;
4use serde_json::Value;
5use thiserror::Error;
6
7mod schema;
8
9#[derive(Error, Debug)]
10pub enum Error {
11    #[error("error serializing item")]
12    SerializationError(#[from] serde_json::Error),
13    #[error("invalid schema at {path}: {details}")]
14    InvalidSchema { path: String, details: String },
15    #[error("{value} did not conform to the schema at {path}: {details}")]
16    InvalidValue {
17        path: String,
18        value: Value,
19        details: String,
20    },
21}
22
23/// Confirm that an item matches its schema.
24///
25/// The item's type must implement `Serialize` and `JsonSchema`. This function
26/// serializes the item and compares that serialization to the type's schema.
27pub fn validate<T: JsonSchema + Serialize>(item: &T) -> Result<(), Error> {
28    let value = serde_json::to_value(item)?;
29
30    let RootSchema {
31        schema,
32        definitions,
33        ..
34    } = schema_for!(T);
35
36    validate_schema_object("$", &schema, &definitions, &value)
37}
38
39/// Confirm that an item matches its schema and print on failure.
40///
41/// See [`validate`].
42pub fn validate_with_output<T: JsonSchema + Serialize>(item: &T) -> Result<(), String> {
43    validate(item).map_err(|e| {
44        let schema = schema_for!(T);
45        format!(
46            "error: {e}\nschema: {}\nvalue: {}",
47            serde_json::to_string_pretty(&schema).unwrap(),
48            serde_json::to_string_pretty(&item).unwrap(),
49        )
50    })
51}