1use thiserror::Error;
2
3#[derive(Error, Debug)]
4pub enum Error {
5 #[error(transparent)]
7 FluentUriParse(#[from] fluent_uri::error::ParseError<String>),
8
9 #[error(transparent)]
11 JsonschemaValidation(#[from] Box<jsonschema::ValidationError<'static>>),
12
13 #[error(transparent)]
14 Reqwest(#[from] reqwest::Error),
16
17 #[error("json value is not an object or an array")]
19 ScalarJson(serde_json::Value),
20
21 #[error(transparent)]
22 SerdeJson(#[from] serde_json::Error),
24
25 #[error(transparent)]
26 Stac(#[from] stac::Error),
28
29 #[error("{} validation error(s)", .0.len())]
31 Validation(Vec<Validation>),
32}
33
34#[derive(Debug)]
36pub struct Validation {
37 id: Option<String>,
39
40 r#type: Option<stac::Type>,
42
43 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 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}