use std::fmt::Display;
use crate::namespace::ErrorNamespaceUrl;
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Error {
#[serde(rename = "type")]
pub namespace: ErrorNamespaceUrl,
pub message: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub debug: Option<String>,
#[serde(default, flatten)]
pub extensions: serde_json::Map<String, serde_json::Value>,
}
impl Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.message.fmt(f)
}
}
impl Error {
pub fn not_found(kind: String) -> Self {
Self {
namespace: ErrorNamespaceUrl::Identifier,
message: format!("not found: {kind}"),
debug: None,
extensions: Default::default(),
}
}
pub fn internal_server_error(description: String) -> Self {
Self {
namespace: ErrorNamespaceUrl::Identifier,
message: format!("internal server error: {description}"),
debug: None,
extensions: Default::default(),
}
}
}
#[cfg(test)]
mod serde_tests {
use pretty_assertions::assert_eq;
use serde_json::json;
use super::Error;
use crate::namespace::ErrorNamespaceUrl;
fn example_error() -> Error {
Error {
namespace: ErrorNamespaceUrl::Identifier,
message: "Something went wrong".into(),
debug: Some("Could not connect to database".into()),
extensions: serde_json::Map::new(),
}
}
fn example_error_json() -> serde_json::Value {
json!( {
"type": "https://schema.oparl.org/1.1/Error",
"message": "Something went wrong",
"debug": "Could not connect to database",
})
}
#[test]
fn serialize() {
assert_eq!(json!(example_error()), example_error_json());
}
#[test]
fn deserialize_good() {
let deserialized: Error = serde_json::from_value(example_error_json())
.expect("value must be deserializable as Error");
assert_eq!(deserialized, example_error());
}
#[test]
fn deserialize_bad() {
assert!(serde_json::from_value::<Error>(json!("xyzabcd")).is_err());
assert!(serde_json::from_value::<Error>(json!(true)).is_err());
assert!(serde_json::from_value::<Error>(json!(123)).is_err());
}
}