Skip to main content

soup_sdk/
api.rs

1use reqwest::{Client, RequestBuilder, Response};
2use serde::de::DeserializeOwned;
3use std::time::Duration;
4
5use crate::error::{Error, Result};
6
7pub const USER_AGENT: &str = "Mozilla/5.0 (Linux; Android 15; Pixel 9) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Mobile Safari/537.36";
8pub const DEFAULT_HTTP_TIMEOUT: Duration = Duration::from_secs(15);
9
10pub fn with_user_agent(request: RequestBuilder) -> RequestBuilder {
11    request.header("User-Agent", USER_AGENT)
12}
13
14pub fn with_form_headers(request: RequestBuilder) -> RequestBuilder {
15    with_user_agent(request).header("Content-Type", "application/x-www-form-urlencoded")
16}
17
18pub async fn send(request: RequestBuilder) -> Result<Response> {
19    let response = request.send().await.map_err(Error::Transport)?;
20    ensure_success(response)
21}
22
23pub async fn send_json<T>(request: RequestBuilder) -> Result<T>
24where
25    T: DeserializeOwned,
26{
27    let response = send(request).await?;
28    response
29        .json::<T>()
30        .await
31        .map_err(|e| Error::Decode(e.to_string()))
32}
33
34pub async fn send_text(request: RequestBuilder) -> Result<String> {
35    let response = send(request).await?;
36    response
37        .text()
38        .await
39        .map_err(|e| Error::Decode(e.to_string()))
40}
41
42pub fn ensure_success(response: Response) -> Result<Response> {
43    if response.status().is_success() {
44        return Ok(response);
45    }
46
47    let status = response.status();
48    let url = response.url().to_string();
49    Err(Error::HttpStatus { status, url })
50}
51
52pub fn default_client() -> Client {
53    Client::builder()
54        .timeout(DEFAULT_HTTP_TIMEOUT)
55        .build()
56        .unwrap_or_else(|_| Client::new())
57}