generic_async_http_client/request.rs
1use crate::{imp, Body, Error, HeaderName, HeaderValue, Response};
2use serde::Serialize;
3use std::{convert::TryInto, fmt::Debug};
4
5/// Builds a HTTP request, poll it to query
6/// ```
7/// # use generic_async_http_client::{Request, Response, Error};
8/// # async fn get() -> Result<(), Error> {
9/// let req = Request::get("http://example.com/");
10/// let resp = req.exec().await?;
11/// # Ok(())
12/// # }
13/// ```
14///
15/// Depending on the chosen implementation, `Request` implements `TryFrom<(TryInto<Method>, TryInto<Url>)>`.
16pub struct Request(pub(crate) imp::Req);
17impl Request {
18 //auth
19 //proxy - should be set by bin
20 //cookies
21 //timeout
22 //tls validation
23 //tls client certa
24 //session (ref + cookies)
25 pub fn get(uri: &str) -> Request {
26 Request(imp::Req::get(uri))
27 }
28 pub fn post(uri: &str) -> Request {
29 Request(imp::Req::post(uri))
30 }
31 pub fn put(uri: &str) -> Request {
32 Request(imp::Req::put(uri))
33 }
34 pub fn delete(uri: &str) -> Request {
35 Request(imp::Req::delete(uri))
36 }
37 pub fn head(uri: &str) -> Request {
38 Request(imp::Req::head(uri))
39 }
40 pub fn options(uri: &str) -> Request {
41 Request(imp::Req::options(uri))
42 }
43 pub fn new(meth: &str, uri: &str) -> Result<Request, Error> {
44 Ok(imp::Req::new(meth, uri).map(Request)?)
45 }
46 /// Add a JSON body to the request
47 /// ```
48 /// # use generic_async_http_client::{Request, Response, Error};
49 /// # use serde::Serialize;
50 /// #[derive(Serialize)]
51 /// struct JoseBody {
52 /// protected: String,
53 /// payload: String,
54 /// signature: String,
55 /// }
56 /// async fn jose(jose: &JoseBody) -> Result<Response, Error> {
57 /// let req = Request::put("http://example.com/").json(jose)?;
58 /// req.exec().await
59 /// }
60 /// ```
61 pub fn json<T: Serialize + ?Sized>(mut self, json: &T) -> Result<Self, Error> {
62 self.0.json(json)?;
63 Ok(self)
64 }
65 /// Add a form data body to the request
66 /// ```
67 /// # use generic_async_http_client::{Request, Response, Error};
68 /// # use serde::Serialize;
69 /// #[derive(Serialize)]
70 /// struct ContactForm {
71 /// email: String,
72 /// text: String,
73 /// }
74 /// async fn post_form(form: &ContactForm) -> Result<Response, Error> {
75 /// let req = Request::post("http://example.com/").form(form)?;
76 /// req.exec().await
77 /// }
78 /// ```
79 pub fn form<T: Serialize + ?Sized>(mut self, form: &T) -> Result<Self, Error> {
80 self.0.form(form)?;
81 Ok(self)
82 }
83 /// Add query parameter to the request
84 pub fn query<T: Serialize + ?Sized>(mut self, query: &T) -> Result<Self, Error> {
85 self.0.query(query)?;
86 Ok(self)
87 }
88 /// Add a body to the request
89 /// ```
90 /// # use generic_async_http_client::{Request, Response, Error};
91 /// # async fn body() -> Result<Response, Error> {
92 /// let req = Request::post("http://example.com/").body("some body")?;
93 /// # req.exec().await
94 /// # }
95 /// ```
96 pub fn body(mut self, body: impl Into<Body>) -> Result<Self, Error> {
97 self.0.body(body.into())?;
98 Ok(self)
99 }
100 /// Add a single header to the request
101 /// If the map did have this key present, the new value is associated with the key
102 /// ```
103 /// # use generic_async_http_client::{Request, Response, Error};
104 /// # async fn ua() -> Result<Response, Error> {
105 /// let req = Request::get("http://example.com/").set_header("User-Agent", "generic_async_http_client v0.2")?;
106 /// # req.exec().await
107 /// # }
108 /// ```
109 pub fn set_header<N, V, E1, E2>(mut self, name: N, value: V) -> Result<Self, Error>
110 where
111 N: TryInto<HeaderName, Error = E1>,
112 V: TryInto<HeaderValue, Error = E2>,
113 Error: From<E1>,
114 Error: From<E2>,
115 {
116 let val: HeaderValue = value.try_into()?;
117 let name: HeaderName = name.try_into()?;
118 self.0.set_header(name.into(), val.into())?;
119
120 Ok(self)
121 }
122 /// Add a single header to the request
123 /// If the map did have this key present, the new value is pushed to the end of the list of values
124 pub fn add_header<N, V, E1, E2>(mut self, name: N, value: V) -> Result<Self, Error>
125 where
126 N: TryInto<HeaderName, Error = E1>,
127 V: TryInto<HeaderValue, Error = E2>,
128 Error: From<E1>,
129 Error: From<E2>,
130 {
131 let val: HeaderValue = value.try_into()?;
132 let name: HeaderName = name.try_into()?;
133 self.0.add_header(name.into(), val.into())?;
134
135 Ok(self)
136 }
137 /*
138 TODO stream body
139 body(Body::from_reader)
140 */
141 //TODO multipart
142
143 /// Send the request to the webserver
144 pub async fn exec(self) -> Result<Response, Error> {
145 #[cfg(all(feature = "mock_tests", test))]
146 let r = if crate::Mock::uses_mock() {
147 Response(crate::Mock::check(self.0)?)
148 } else {
149 self.0.send_request().await?
150 };
151 #[cfg(not(all(feature = "mock_tests", test)))]
152 let r = self.0.send_request().await?;
153 //https://crates.io/crates/hreq
154
155 match r.status_code() {
156 100..300 => Ok(r),
157 300..400 => {
158 if let Some(loc) = r.header("Location").and_then(|l| l.try_into().ok()) {
159 let _l: String = loc;
160 //TODO redirect
161 }
162 Ok(r)
163 }
164 s @ 400..500 => Err(Error::HTTPClientErr(s, r)),
165 //s @ 500..600 => Err(Error::HTTPServerErr(s, r)),
166 s => Err(Error::HTTPServerErr(s, r)),
167 }
168 }
169}
170impl Debug for Request {
171 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
172 std::fmt::Debug::fmt(&self.0, f)
173 }
174}
175
176pub trait Requests: Debug {
177 fn get(uri: &str) -> Self;
178 fn post(uri: &str) -> Self;
179 fn put(uri: &str) -> Self;
180 fn delete(uri: &str) -> Self;
181 fn head(uri: &str) -> Self;
182 fn options(uri: &str) -> Self;
183 fn new(meth: &str, uri: &str) -> Result<Self, imp::Error>
184 where
185 Self: std::marker::Sized;
186 async fn send_request(self) -> Result<Response, imp::Error>
187 where
188 Self: std::marker::Sized;
189 fn json<T: Serialize + ?Sized>(&mut self, json: &T) -> Result<(), imp::Error>;
190 fn form<T: Serialize + ?Sized>(&mut self, data: &T) -> Result<(), imp::Error>;
191 fn query<T: Serialize + ?Sized>(&mut self, query: &T) -> Result<(), imp::Error>;
192 fn body<B: Into<imp::Body>>(&mut self, body: B) -> Result<(), imp::Error>;
193 fn set_header(
194 &mut self,
195 name: imp::HeaderName,
196 values: imp::HeaderValue,
197 ) -> Result<(), imp::Error>;
198 fn add_header(
199 &mut self,
200 name: imp::HeaderName,
201 values: imp::HeaderValue,
202 ) -> Result<(), imp::Error>;
203}
204
205/*
206enum State{
207 Build(imp::Req),
208 Fetch(Pin<Box<dyn Future<Output=Result<imp::Resp, Error>>>>)
209}
210struct Request2{
211 state: std::cell::Cell<State>
212}
213impl Future for Request2{
214 type Output = Result<Response, Error>;
215
216 fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
217 println!("poll");
218 let pin = self.get_mut();
219
220 match pin.state.get_mut() {
221 State::Build(req) => {
222 let fut = req.send_request();
223 pin.state.set(State::Fetch(fut.boxed()));
224 Poll::Pending
225 },
226 State::Fetch(mut fut) => {
227 match fut.poll_unpin(cx) {
228 Poll::Ready(Ok(resp)) => Poll::Ready(Ok(Response(resp))),
229 Poll::Pending => Poll::Pending,
230 Poll::Ready(Err(e)) => Poll::Ready(Err(e))
231 }
232 },
233 }
234 }
235}*/