Handle a response: check status, parse `ApiResponse `, unwrap data.
(
&self,
resp: reqwest::Response,
)
| 240 | |
| 241 | /// Handle a response: check status, parse `ApiResponse<T>`, unwrap data. |
| 242 | async fn handle_response<T: DeserializeOwned>( |
| 243 | &self, |
| 244 | resp: reqwest::Response, |
| 245 | ) -> Result<T, RemoteError> { |
| 246 | crate::check_min_version_header(resp.headers()); |
| 247 | let status = resp.status(); |
| 248 | let body = resp |
| 249 | .text() |
| 250 | .await |
| 251 | .map_err(|e| RemoteError::other(format!("failed to read response: {}", e)))?; |
| 252 | |
| 253 | if !status.is_success() { |
| 254 | return Err(self.parse_error_body(status.as_u16(), &body)); |
| 255 | } |
| 256 | |
| 257 | let api_resp: ApiResponse<T> = serde_json::from_str(&body).map_err(|e| { |
| 258 | // The whole body goes to the log; the error message carries a |
| 259 | // bounded preview so a large payload cannot flood the terminal. |
| 260 | log::debug!("Undeserializable response body: {}", body); |
| 261 | RemoteError::other(format!( |
| 262 | "invalid response JSON: {} (body: {})", |
| 263 | e, |
| 264 | preview(&body, BODY_PREVIEW_BYTES) |
| 265 | )) |
| 266 | })?; |
| 267 | |
| 268 | if !api_resp.success { |
| 269 | if let Some(err) = api_resp.error { |
| 270 | return Err(RemoteError::other(format!("{}: {}", err.code, err.message))); |
| 271 | } |
| 272 | return Err(RemoteError::other("request failed with no error details")); |
| 273 | } |
| 274 | |
| 275 | api_resp |
| 276 | .data |
| 277 | .ok_or_else(|| RemoteError::other("response had success=true but no data")) |
| 278 | } |
| 279 | |
| 280 | fn parse_error_body(&self, status: u16, body: &str) -> RemoteError { |
| 281 | // Try to parse as ApiResponse first. |
no test coverage detected