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 Timeout,
12 Internal,
13}
14
15#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
17pub struct ApiError {
18 pub error_kind: ErrorKind,
19 pub message: String,
20 #[serde(skip_serializing_if = "Option::is_none")]
21 pub metadata: Option<ApiMetadata>,
22}
23
24impl ApiError {
25 pub fn invalid_argument(message: impl Into<String>) -> Self {
27 Self {
28 error_kind: ErrorKind::InvalidArgument,
29 message: message.into(),
30 metadata: None,
31 }
32 }
33
34 pub fn storage_unavailable(message: impl Into<String>) -> Self {
36 Self {
37 error_kind: ErrorKind::StorageUnavailable,
38 message: message.into(),
39 metadata: None,
40 }
41 }
42}
43
44#[cfg(test)]
45mod tests {
46 use super::*;
47
48 #[test]
49 fn builds_stable_error_shapes() {
50 let invalid = ApiError::invalid_argument("bad input");
51 let storage = ApiError::storage_unavailable("database busy");
52
53 assert_eq!(invalid.error_kind, ErrorKind::InvalidArgument);
54 assert_eq!(invalid.message, "bad input");
55 assert_eq!(storage.error_kind, ErrorKind::StorageUnavailable);
56 assert_eq!(storage.message, "database busy");
57 }
58}