k2db_api_contract/
error.rs1use serde::{Deserialize, Serialize};
5use serde_json::Value;
6
7#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8pub struct ErrorChainItem {
9 pub error: String,
10 #[serde(rename = "error_description")]
11 pub error_description: String,
12 pub stage: Option<String>,
13 pub at: u64,
14}
15
16#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
17pub struct ProblemDetailsPayload {
18 #[serde(rename = "type")]
19 pub type_uri: Option<String>,
20 pub title: Option<String>,
21 pub status: Option<u16>,
22 pub detail: Option<String>,
23 pub trace: Option<String>,
24 pub chain: Option<Vec<ErrorChainItem>>,
25 #[serde(flatten)]
26 pub extra: serde_json::Map<String, Value>,
27}
28
29#[cfg(test)]
30mod tests {
31 use serde_json::json;
32
33 use super::*;
34
35 #[test]
36 fn problem_details_preserves_standard_fields() {
37 let payload = ProblemDetailsPayload {
38 type_uri: Some("urn:service-error:not_found".to_owned()),
39 title: Some("not_found".to_owned()),
40 status: Some(404),
41 detail: Some("Document not found".to_owned()),
42 trace: Some("sys_mdb_get_not_found".to_owned()),
43 chain: Some(vec![ErrorChainItem {
44 error: "not_found".to_owned(),
45 error_description: "Document not found".to_owned(),
46 stage: Some("api.get-by-id".to_owned()),
47 at: 1,
48 }]),
49 extra: serde_json::Map::new(),
50 };
51
52 let value = serde_json::to_value(payload).expect("serialize problem details");
53 assert_eq!(
54 value,
55 json!({
56 "type": "urn:service-error:not_found",
57 "title": "not_found",
58 "status": 404,
59 "detail": "Document not found",
60 "trace": "sys_mdb_get_not_found",
61 "chain": [
62 {
63 "error": "not_found",
64 "error_description": "Document not found",
65 "stage": "api.get-by-id",
66 "at": 1,
67 }
68 ],
69 })
70 );
71 }
72}