Skip to main content

feignhttp/
http.rs

1use crate::FeignContext;
2#[cfg(feature = "multipart")]
3use crate::multipart::MultipartForm;
4use crate::{ClientConfig, ClientWrapper, RequestConfig, RequestWrapper, error::Result};
5use async_trait::async_trait;
6use http::StatusCode;
7use once_cell::sync::Lazy;
8use std::collections::HashMap;
9
10/// Define a trait for code generation.
11pub trait FeignClientBuilder: Sized {
12    type Target;
13
14    fn new() -> Self;
15
16    fn config(self, config: ClientConfig) -> Self;
17
18    fn context<C>(self, context: C) -> Self
19    where
20        C: FeignContext + 'static;
21
22    fn build(self) -> Result<Self::Target>;
23}
24
25/// A trait for HTTP client.
26pub trait Client: Sized + Clone {
27    type Inner;
28
29    fn new() -> Result<Self>;
30
31    fn with_config(config: ClientConfig) -> Result<Self>;
32
33    fn with_client(client: Self::Inner) -> Result<Self>;
34
35    fn get_client(&self) -> &Self::Inner;
36}
37
38/// A trait of HTTP request.
39#[async_trait]
40pub trait HttpRequest {
41    type Response: HttpResponse;
42
43    fn headers(self, headers: HashMap<&str, String>) -> Self;
44
45    fn query(self, query: Vec<(&str, String)>) -> Self;
46
47    async fn send(self) -> Result<Self::Response>;
48
49    async fn send_text(self, text: String) -> Result<Self::Response>;
50
51    async fn send_form<T>(self, form: &T) -> Result<Self::Response>
52    where
53        T: serde::ser::Serialize + Sync;
54
55    #[cfg(feature = "json")]
56    async fn send_json<T>(self, json: &T) -> Result<Self::Response>
57    where
58        T: serde::ser::Serialize + Sync;
59
60    #[cfg(feature = "multipart")]
61    async fn send_multipart(self, form: MultipartForm) -> Result<Self::Response>;
62
63    async fn send_vec(self, vec: Vec<u8>) -> Result<Self::Response>;
64}
65
66/// A trait of HTTP response.
67#[async_trait]
68pub trait HttpResponse {
69    fn status(&self) -> StatusCode;
70
71    async fn none(self) -> Result<()>;
72
73    async fn text(self) -> Result<String>;
74
75    async fn vec(self) -> Result<Vec<u8>>;
76
77    #[cfg(feature = "json")]
78    async fn json<T>(self) -> Result<T>
79    where
80        T: serde::de::DeserializeOwned;
81}
82
83/// An HTTP client to create ClientWrapper.
84pub struct HttpClient;
85
86impl HttpClient {
87    pub fn new() -> Result<ClientWrapper> {
88        ClientWrapper::with_config(ClientConfig {
89            connect_timeout: Some(10000),
90            timeout: Some(10000),
91            read_timeout: None,
92        })
93    }
94
95    pub fn with_config(config: ClientConfig) -> Result<ClientWrapper> {
96        ClientWrapper::with_config(config)
97    }
98
99    pub fn shared() -> &'static ClientWrapper {
100        static SHARED: Lazy<ClientWrapper> =
101            Lazy::new(|| HttpClient::new().expect("shared http client failed to initialize"));
102
103        &SHARED
104    }
105}
106
107/// An HTTP requet builder to make requests.
108pub struct RequestBuilder<'a> {
109    client: ClientWrapper,
110    url: &'a str,
111    method: &'a str,
112    headers: Option<HashMap<&'a str, String>>,
113    query: Option<Vec<(&'a str, String)>>,
114    config: Option<RequestConfig>,
115}
116
117impl<'a> RequestBuilder<'a> {
118    pub fn new(client: ClientWrapper) -> Self {
119        Self {
120            client,
121            url: "",
122            method: "",
123            headers: None,
124            query: None,
125            config: None,
126        }
127    }
128    pub fn url(mut self, url: &'a str) -> Self {
129        self.url = url;
130        self
131    }
132
133    pub fn method(mut self, method: &'a str) -> Self {
134        self.method = method;
135        self
136    }
137
138    pub fn config(mut self, config: RequestConfig) -> Self {
139        self.config = Some(config);
140        self
141    }
142
143    pub fn headers(mut self, headers: HashMap<&'a str, String>) -> Self {
144        self.headers = Some(headers);
145        self
146    }
147
148    pub fn query(mut self, query: Vec<(&'a str, String)>) -> Self {
149        self.query = Some(query);
150        self
151    }
152
153    pub fn build(self) -> Result<RequestWrapper> {
154        let mut request = match self.config {
155            Some(config) => {
156                RequestWrapper::with_config(self.client, self.url, self.method, config)?
157            }
158            None => RequestWrapper::new(self.client, self.url, self.method)?,
159        };
160        if let Some(header_map) = self.headers {
161            request = request.headers(header_map);
162        }
163        if let Some(query_vec) = self.query {
164            request = request.query(query_vec);
165        }
166        Ok(request)
167    }
168}