jules_api/response/
mod.rs1use crate::http::HttpResponse;
4use jules_core::errors::{ApiError, SDKError};
5use jules_core::response::ClientResponse;
6use serde::de::DeserializeOwned;
7use serde::Deserialize;
8
9#[derive(Debug, Deserialize)]
11struct ErrorResponse {
12 error: Option<ErrorDetail>,
13}
14
15#[derive(Debug, Deserialize)]
16struct ErrorDetail {
17 message: String,
18}
19
20pub(crate) fn map_error_response(response: &HttpResponse) -> SDKError {
23 let message = match serde_json::from_slice::<ErrorResponse>(&response.body) {
24 Ok(err_resp) => err_resp.error.map_or_else(
25 || String::from_utf8_lossy(&response.body).into_owned(),
26 |e| e.message,
27 ),
28 Err(_) => String::from_utf8_lossy(&response.body).into_owned(),
29 };
30
31 let mut msg = message.trim().to_string();
32 if msg.is_empty() {
33 msg = format!("HTTP {}", response.status);
34 }
35
36 SDKError::Api(ApiError::with_status(msg, response.status))
37}
38
39pub(crate) fn deserialize_json<R: DeserializeOwned>(
47 response: &HttpResponse,
48) -> Result<R, SDKError> {
49 if response.status >= 200 && response.status < 300 {
50 serde_json::from_slice::<R>(&response.body).map_err(|e| {
51 SDKError::Api(ApiError::with_status(
52 format!("Failed to deserialize response: {e}"),
53 response.status,
54 ))
55 })
56 } else {
57 Err(map_error_response(response))
58 }
59}
60
61pub fn deserialize_response(response: &HttpResponse) -> Result<ClientResponse, SDKError> {
68 deserialize_json::<ClientResponse>(response)
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74 use jules_core::message::Role;
75
76 #[test]
77 fn test_deserialize_success() {
78 let body = r#"{
79 "message": {
80 "role": "assistant",
81 "content": "Hello, world!"
82 }
83 }"#
84 .as_bytes()
85 .to_vec();
86
87 let http_resp = HttpResponse::new(200, vec![], body);
88 let result = deserialize_response(&http_resp).unwrap();
89
90 assert_eq!(*result.message.role(), Role::Assistant);
91 assert_eq!(result.message.content(), "Hello, world!");
92 }
93
94 #[test]
95 fn test_deserialize_api_error_json() {
96 let body = r#"{
97 "error": {
98 "message": "Invalid API key"
99 }
100 }"#
101 .as_bytes()
102 .to_vec();
103
104 let http_resp = HttpResponse::new(401, vec![], body);
105 let err = deserialize_response(&http_resp).unwrap_err();
106
107 match err {
108 SDKError::Api(e) => {
109 assert_eq!(e.status_code, Some(401));
110 assert_eq!(e.message, "Invalid API key");
111 }
112 _ => panic!("Expected SDKError::Api"),
113 }
114 }
115
116 #[test]
117 fn test_deserialize_api_error_raw() {
118 let body = "Internal Server Error".as_bytes().to_vec();
119
120 let http_resp = HttpResponse::new(500, vec![], body);
121 let err = deserialize_response(&http_resp).unwrap_err();
122
123 match err {
124 SDKError::Api(e) => {
125 assert_eq!(e.status_code, Some(500));
126 assert_eq!(e.message, "Internal Server Error");
127 }
128 _ => panic!("Expected SDKError::Api"),
129 }
130 }
131
132 #[test]
133 fn test_deserialize_api_error_empty_body() {
134 let body = vec![];
135
136 let http_resp = HttpResponse::new(500, vec![], body);
137 let err = deserialize_response(&http_resp).unwrap_err();
138
139 match err {
140 SDKError::Api(e) => {
141 assert_eq!(e.status_code, Some(500));
142 assert_eq!(e.message, "HTTP 500");
143 }
144 _ => panic!("Expected SDKError::Api"),
145 }
146 }
147}