Skip to main content

bitwarden_api_base/
request.rs

1use http::header::CONTENT_TYPE;
2use serde::de::{DeserializeOwned, Error as _};
3
4use crate::{ContentType, Error, ResponseContent};
5
6fn content_type(response: &reqwest::Response) -> ContentType {
7    response
8        .headers()
9        .get(CONTENT_TYPE)
10        .and_then(|v| v.to_str().ok())
11        .unwrap_or("application/octet-stream")
12        .into()
13}
14
15/// [process_with_json_response] is generic, which means it gets monomorphized for every type it's
16/// used with. This function contains the non-generic logic for processing the response so that it
17/// doesn't get duplicated.
18#[inline(never)]
19async fn process_with_json_response_internal<E>(
20    request: reqwest_middleware::RequestBuilder,
21) -> Result<String, crate::Error<E>> {
22    let response = request.send().await?;
23    let status = response.status();
24    let content_type = content_type(&response);
25    let content = response.text().await?;
26
27    if !status.is_client_error() && !status.is_server_error() {
28        match content_type {
29            ContentType::Json => Ok(content),
30            ct => Err(Error::from(serde_json::Error::custom(format!(
31                "Received `{ct:?}` content type response when JSON was expected"
32            )))),
33        }
34    } else {
35        Err(Error::ResponseError(ResponseContent {
36            status,
37            content,
38            entity: None,
39        }))
40    }
41}
42
43/// Sends and processes a request expecting a JSON response, deserializing it into the type `T`.
44pub async fn process_with_json_response<T: DeserializeOwned, E>(
45    request: reqwest_middleware::RequestBuilder,
46) -> Result<T, crate::Error<E>> {
47    process_with_json_response_internal(request)
48        .await
49        .and_then(|content| serde_json::from_str(&content).map_err(Into::into))
50}
51
52/// Sends and processes a request expecting an empty response, returning `Ok(())` when successful.
53#[inline(never)]
54pub async fn process_with_empty_response<E>(
55    request: reqwest_middleware::RequestBuilder,
56) -> Result<(), crate::Error<E>> {
57    let response = request.send().await?;
58    let status = response.status();
59
60    if !status.is_client_error() && !status.is_server_error() {
61        Ok(())
62    } else {
63        let content = response.text().await?;
64        Err(Error::ResponseError(ResponseContent {
65            status,
66            content,
67            entity: None,
68        }))
69    }
70}