relay_knowledge/api/
error.rs1use serde::{Deserialize, Serialize};
2
3use super::ApiMetadata;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
7#[serde(rename_all = "snake_case")]
8pub enum ErrorKind {
9 InvalidArgument,
10 StorageUnavailable,
11 QosRejected,
12 Timeout,
13 Internal,
14}
15
16#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
18pub struct ApiError {
19 pub error_kind: ErrorKind,
20 pub message: String,
21 #[serde(skip_serializing_if = "Option::is_none")]
22 pub metadata: Option<ApiMetadata>,
23}
24
25impl ApiError {
26 pub fn invalid_argument(message: impl Into<String>) -> Self {
28 Self {
29 error_kind: ErrorKind::InvalidArgument,
30 message: message.into(),
31 metadata: None,
32 }
33 }
34
35 pub fn storage_unavailable(message: impl Into<String>) -> Self {
37 Self {
38 error_kind: ErrorKind::StorageUnavailable,
39 message: message.into(),
40 metadata: None,
41 }
42 }
43
44 pub fn qos_rejected(message: impl Into<String>) -> Self {
46 Self {
47 error_kind: ErrorKind::QosRejected,
48 message: message.into(),
49 metadata: None,
50 }
51 }
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57
58 #[test]
59 fn builds_stable_error_shapes() {
60 let invalid = ApiError::invalid_argument("bad input");
61 let storage = ApiError::storage_unavailable("database busy");
62 let qos = ApiError::qos_rejected("request budget exhausted");
63
64 assert_eq!(invalid.error_kind, ErrorKind::InvalidArgument);
65 assert_eq!(invalid.message, "bad input");
66 assert_eq!(storage.error_kind, ErrorKind::StorageUnavailable);
67 assert_eq!(storage.message, "database busy");
68 assert_eq!(qos.error_kind, ErrorKind::QosRejected);
69 assert_eq!(qos.message, "request budget exhausted");
70 }
71}