forgejo_sdk/
lib.rs

1#![forbid(unsafe_code)]
2
3pub mod api;
4
5mod error;
6use error::ApiError;
7pub use error::{Error, Result};
8use reqwest::{
9    header::{self, HeaderMap},
10    Method, RequestBuilder, Response, StatusCode, Url,
11};
12use serde::de::DeserializeOwned;
13
14pub struct Client {
15    http: reqwest::Client,
16    token: Option<String>,
17    base_url: Url,
18}
19
20impl Client {
21    pub fn new(token: String, base_url: Url) -> Self {
22        let mut headers = HeaderMap::new();
23        headers.insert(header::AUTHORIZATION, format!("Bearer {token}").try_into().expect("the token is not a valid header value"));
24
25        Self {
26            http: reqwest::Client::builder().default_headers(headers).build().expect("the client was not constructed"),
27            token: Some(token),
28            base_url,
29        }
30    }
31
32    pub fn new_unauth(base_url: Url) -> Self {
33        Self {
34            http: reqwest::Client::new(),
35            token: None,
36            base_url,
37        }
38    }
39
40    pub fn token(&self) -> Option<&str> {
41        self.token.as_deref()
42    }
43
44    pub async fn execute(&self, request: RequestBuilder) -> Result<Response> {
45        let response = request.send().await?;
46        match response.status() {
47            StatusCode::UNAUTHORIZED => Err(Error::Api(ApiError::Unauthorized)),
48            StatusCode::NOT_FOUND => Err(Error::Api(ApiError::NotFound)),
49            StatusCode::FORBIDDEN => Err(Error::Api(ApiError::Forbidden(response.json().await?))),
50            _ => Ok(response),
51        }
52    }
53
54    pub async fn get<T: DeserializeOwned>(&self, url: &str) -> Result<T> {
55        Ok(self
56            .execute(
57                self.http.request(
58                    Method::GET,
59                    Url::options()
60                        .base_url(Some(&self.base_url))
61                        .parse(url)
62                        .expect("invalid url"),
63                ),
64            )
65            .await?
66            .json()
67            .await?)
68    }
69
70    pub async fn delete<T: DeserializeOwned>(&self, url: &str) -> Result<T> {
71        Ok(self
72            .execute(
73                self.http.request(
74                    Method::DELETE,
75                    Url::options()
76                        .base_url(Some(&self.base_url))
77                        .parse(url)
78                        .expect("invalid url"),
79                ),
80            )
81            .await?
82            .json()
83            .await?)
84    }
85}
86