stac_validate/
error.rs

1use thiserror::Error;
2
3#[derive(Error, Debug)]
4pub enum Error {
5    /// [fluent_uri::error::ParseError]
6    #[error(transparent)]
7    FluentUriParse(#[from] fluent_uri::error::ParseError<String>),
8
9    /// [jsonschema::ValidationError]
10    #[error(transparent)]
11    JsonschemaValidation(#[from] Box<jsonschema::ValidationError<'static>>),
12
13    #[error(transparent)]
14    /// [reqwest::Error]
15    Reqwest(#[from] reqwest::Error),
16
17    /// JSON is a scalar when an array or object was expected
18    #[error("json value is not an object or an array")]
19    ScalarJson(serde_json::Value),
20
21    #[error(transparent)]
22    /// [serde_json::Error]
23    SerdeJson(#[from] serde_json::Error),
24
25    #[error(transparent)]
26    /// [stac::Error]
27    Stac(#[from] stac::Error),
28
29    /// A list of validation errors.
30    #[error("{} validation error(s)", .0.len())]
31    Validation(Vec<Validation>),
32}
33
34/// A validation error
35#[derive(Debug)]
36pub struct Validation {
37    /// The ID of the STAC object that failed to validate.
38    id: Option<String>,
39
40    /// The type of the STAC object that failed to validate.
41    r#type: Option<stac::Type>,
42
43    /// The validation error.
44    error: jsonschema::ValidationError<'static>,
45}
46
47impl Validation {
48    pub(crate) fn new(
49        error: jsonschema::ValidationError<'_>,
50        value: Option<&serde_json::Value>,
51    ) -> Validation {
52        let mut id = None;
53        let mut r#type = None;
54        if let Some(value) = value.and_then(|v| v.as_object()) {
55            id = value.get("id").and_then(|v| v.as_str()).map(String::from);
56            r#type = value
57                .get("type")
58                .and_then(|v| v.as_str())
59                .and_then(|s| s.parse::<stac::Type>().ok());
60        }
61        Validation {
62            id,
63            r#type,
64            error: error.to_owned(),
65        }
66    }
67
68    /// Converts this validation error into a [serde_json::Value].
69    pub fn into_json(self) -> serde_json::Value {
70        let error_description = jsonschema::output::ErrorDescription::from(self.error);
71        serde_json::json!({
72            "id": self.id,
73            "type": self.r#type,
74            "error": error_description,
75        })
76    }
77}
78
79impl super::Error {
80    pub(crate) fn from_validation_errors<'a, I>(
81        errors: I,
82        value: Option<&serde_json::Value>,
83    ) -> super::Error
84    where
85        I: Iterator<Item = jsonschema::ValidationError<'a>>,
86    {
87        super::Error::Validation(errors.map(|error| Validation::new(error, value)).collect())
88    }
89}
90
91impl std::fmt::Display for Validation {
92    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93        if let Some(r#type) = self.r#type {
94            if let Some(id) = self.id.as_ref() {
95                write!(f, "{}[id={id}]: {}", r#type, self.error)
96            } else {
97                write!(f, "{}: {}", r#type, self.error)
98            }
99        } else if let Some(id) = self.id.as_ref() {
100            write!(f, "[id={id}]: {}", self.error)
101        } else {
102            write!(f, "{}", self.error)
103        }
104    }
105}