cdk_http_client/
response.rs1use core::fmt;
4
5use serde::de::DeserializeOwned;
6
7use crate::error::HttpError;
8
9pub type Response<R, E = HttpError> = Result<R, E>;
12
13pub struct RawResponse {
15 status: u16,
16 pub(crate) body: Vec<u8>,
17}
18
19impl fmt::Debug for RawResponse {
20 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21 f.debug_struct("RawResponse")
22 .field("status", &self.status)
23 .field("body_len", &self.body.len())
24 .finish()
25 }
26}
27
28impl RawResponse {
29 pub fn new(status: u16, body: Vec<u8>) -> Self {
31 Self { status, body }
32 }
33
34 pub fn status(&self) -> u16 {
36 self.status
37 }
38
39 pub fn is_success(&self) -> bool {
41 (200..300).contains(&self.status)
42 }
43
44 pub fn is_client_error(&self) -> bool {
46 (400..500).contains(&self.status)
47 }
48
49 pub fn is_server_error(&self) -> bool {
51 (500..600).contains(&self.status)
52 }
53
54 pub fn body_lossy(&self) -> String {
56 String::from_utf8_lossy(&self.body).into_owned()
57 }
58
59 pub fn json_or_status_error<T: DeserializeOwned>(self) -> Response<T> {
61 if !self.is_success() {
62 return Err(HttpError::Status {
63 status: self.status,
64 message: self.body_lossy(),
65 });
66 }
67 serde_json::from_slice(&self.body).map_err(HttpError::from)
68 }
69
70 pub async fn text(self) -> Response<String> {
72 String::from_utf8(self.body).map_err(|e| HttpError::Other(e.to_string()))
73 }
74
75 pub async fn json<T: DeserializeOwned>(self) -> Response<T> {
77 serde_json::from_slice(&self.body).map_err(HttpError::from)
78 }
79
80 pub async fn bytes(self) -> Response<Vec<u8>> {
82 Ok(self.body)
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89
90 #[test]
94 fn test_response_type_is_result() {
95 let success: Response<i32> = Ok(42);
97 assert!(success.is_ok());
98 assert!(matches!(success, Ok(42)));
99
100 let error: Response<i32> = Err(HttpError::Timeout);
101 assert!(error.is_err());
102 assert!(matches!(error, Err(HttpError::Timeout)));
103 }
104
105 #[test]
106 fn raw_response_debug_redacts_body_and_reports_length() {
107 let secret = "response-body-secret";
108 let response = RawResponse::new(200, secret.as_bytes().to_vec());
109
110 let debug = format!("{response:?}");
111
112 assert!(debug.contains("status: 200"));
113 assert!(debug.contains(&format!("body_len: {}", secret.len())));
114 assert!(!debug.contains(secret));
115 }
116}