Skip to main content

better_fetch/
api_response.rs

1//! Helpers for typed success vs error response bodies.
2
3use crate::error::Error;
4use crate::response::Response;
5use crate::Result;
6
7/// Deserializes a buffered response into success `T` or API error `E` by HTTP status.
8///
9/// Returns `Ok(Ok(T))` for 2xx, `Ok(Err(E))` when the body deserializes as `E` on non-success,
10/// or `Err(Error::...)` for transport/deserialize failures.
11#[cfg(feature = "json")]
12pub fn into_api_result<T, E>(response: Response) -> Result<std::result::Result<T, E>>
13where
14    T: serde::de::DeserializeOwned,
15    E: serde::de::DeserializeOwned,
16{
17    if response.is_success() {
18        return Ok(Ok(response.into_json()?));
19    }
20    let status = response.status();
21    let body = response.bytes().clone();
22    match serde_json::from_slice::<E>(&body) {
23        Ok(err_body) => Ok(std::result::Result::Err(err_body)),
24        Err(_) => Err(Error::http(
25            status,
26            "failed to deserialize error response body",
27            Some(body),
28        )),
29    }
30}
31
32/// Extension trait for [`Response`].
33#[cfg(feature = "json")]
34pub trait ApiResponseExt {
35    /// See [`into_api_result`].
36    fn into_api_result<T, E>(self) -> Result<std::result::Result<T, E>>
37    where
38        T: serde::de::DeserializeOwned,
39        E: serde::de::DeserializeOwned;
40}
41
42#[cfg(feature = "json")]
43impl ApiResponseExt for Response {
44    fn into_api_result<T, E>(self) -> Result<std::result::Result<T, E>>
45    where
46        T: serde::de::DeserializeOwned,
47        E: serde::de::DeserializeOwned,
48    {
49        into_api_result(self)
50    }
51}