Files
alknet/crates/alknet-core/src/call/response.rs
glm-5.1 619a6dcc77 feat(api): add #[non_exhaustive] to public types likely to evolve
ForwardingAction, TargetPattern, ForwardingRule, OperationType,
InterfaceConfig, InterfaceKind, DynamicConfig, and CallError are all
likely to gain variants/fields in future phases. Marking them
#[non_exhaustive] now prevents downstream breakage when new
variants/fields are added. Added constructor methods for types that
are constructed from other crates.
2026-06-08 05:34:15 +00:00

109 lines
3.1 KiB
Rust

use serde::{Deserialize, Serialize};
use serde_json::Value;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct CallError {
pub code: String,
pub message: String,
pub retryable: bool,
}
impl CallError {
pub fn new(code: impl Into<String>, message: impl Into<String>, retryable: bool) -> Self {
Self {
code: code.into(),
message: message.into(),
retryable,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResponseEnvelope {
pub request_id: String,
pub result: Result<Value, CallError>,
}
impl ResponseEnvelope {
pub fn ok(request_id: impl Into<String>, value: Value) -> Self {
Self {
request_id: request_id.into(),
result: Ok(value),
}
}
pub fn err(
request_id: impl Into<String>,
code: impl Into<String>,
message: impl Into<String>,
retryable: bool,
) -> Self {
Self {
request_id: request_id.into(),
result: Err(CallError {
code: code.into(),
message: message.into(),
retryable,
}),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn call_error_fields() {
let err = CallError {
code: "NOT_FOUND".to_string(),
message: "operation not found".to_string(),
retryable: false,
};
assert_eq!(err.code, "NOT_FOUND");
assert_eq!(err.message, "operation not found");
assert!(!err.retryable);
}
#[test]
fn response_envelope_ok() {
let env = ResponseEnvelope::ok("req-1", json!({"status": "ok"}));
assert_eq!(env.request_id, "req-1");
assert!(env.result.is_ok());
assert_eq!(env.result.unwrap(), json!({"status": "ok"}));
}
#[test]
fn response_envelope_err() {
let env = ResponseEnvelope::err("req-1", "NOT_FOUND", "operation not found", false);
assert_eq!(env.request_id, "req-1");
assert!(env.result.is_err());
let err = env.result.unwrap_err();
assert_eq!(err.code, "NOT_FOUND");
assert_eq!(err.message, "operation not found");
assert!(!err.retryable);
}
#[test]
fn response_envelope_serialization() {
let env = ResponseEnvelope::ok("req-1", json!({"key": "value"}));
let serialized = serde_json::to_string(&env).unwrap();
let deserialized: ResponseEnvelope = serde_json::from_str(&serialized).unwrap();
assert_eq!(deserialized.request_id, "req-1");
assert!(deserialized.result.is_ok());
}
#[test]
fn response_envelope_err_serialization() {
let env = ResponseEnvelope::err("req-2", "TIMEOUT", "timed out", true);
let serialized = serde_json::to_string(&env).unwrap();
let deserialized: ResponseEnvelope = serde_json::from_str(&serialized).unwrap();
assert_eq!(deserialized.request_id, "req-2");
let err = deserialized.result.unwrap_err();
assert_eq!(err.code, "TIMEOUT");
assert!(err.retryable);
}
}