stac_validate/
error.rs

1use thiserror::Error;
2
3#[derive(Error, Debug)]
4#[non_exhaustive]
5pub enum Error {
6    /// [fluent_uri::ParseError]
7    #[error(transparent)]
8    FluentUriParse(#[from] fluent_uri::ParseError),
9
10    /// [jsonschema::ValidationError]
11    #[error(transparent)]
12    JsonschemaValidation(#[from] Box<jsonschema::ValidationError<'static>>),
13
14    #[error(transparent)]
15    /// [reqwest::Error]
16    Reqwest(#[from] reqwest::Error),
17
18    /// JSON is a scalar when an array or object was expected
19    #[error("json value is not an object or an array")]
20    ScalarJson(serde_json::Value),
21
22    #[error(transparent)]
23    /// [serde_json::Error]
24    SerdeJson(#[from] serde_json::Error),
25
26    #[error(transparent)]
27    /// [stac::Error]
28    Stac(#[from] stac::Error),
29
30    /// A list of validation errors.
31    #[error("{} validation error(s)", .0.len())]
32    Validation(Vec<Validation>),
33}
34
35/// A validation error
36#[derive(Debug)]
37pub struct Validation {
38    /// The ID of the STAC object that failed to validate.
39    id: Option<String>,
40
41    /// The type of the STAC object that failed to validate.
42    r#type: Option<stac::Type>,
43
44    /// The validation error.
45    error: jsonschema::ValidationError<'static>,
46}
47
48impl Validation {
49    pub(crate) fn new(
50        error: jsonschema::ValidationError<'_>,
51        value: Option<&serde_json::Value>,
52    ) -> Validation {
53        let mut id = None;
54        let mut r#type = None;
55        if let Some(value) = value.and_then(|v| v.as_object()) {
56            id = value.get("id").and_then(|v| v.as_str()).map(String::from);
57            r#type = value
58                .get("type")
59                .and_then(|v| v.as_str())
60                .and_then(|s| s.parse::<stac::Type>().ok());
61        }
62        Validation {
63            id,
64            r#type,
65            error: error.to_owned(),
66        }
67    }
68
69    /// Converts this validation error into a [serde_json::Value].
70    pub fn into_json(self) -> serde_json::Value {
71        serde_json::json!({
72            "id": self.id,
73            "type": self.r#type,
74            "error": self.error.to_string(),
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}