rust_integration_services/http/
http_request.rs1use std::collections::HashMap;
2use std::marker::PhantomData;
3
4use bytes::Bytes;
5use futures::{Stream, TryStreamExt};
6use http_body_util::{BodyDataStream, Empty, Full, StreamBody};
7use http_body_util::{BodyExt, combinators::BoxBody};
8use hyper::HeaderMap;
9use hyper::body::Frame;
10use hyper::header::HeaderValue;
11use hyper::{Error, Request, body::Incoming};
12
13pub struct Final;
14pub struct SetMethod;
15
16#[derive(Debug)]
17pub struct HttpRequest {
18 body: BoxBody<Bytes, Error>,
19 parts: hyper::http::request::Parts,
20 params: HashMap<String, String>,
21}
22
23impl HttpRequest {
24
25 pub fn builder() -> HttpRequestBuilder<SetMethod> {
27 HttpRequestBuilder {
28 builder: Request::builder(),
29 _state: PhantomData
30 }
31 }
32
33 pub fn from_parts(body: BoxBody<Bytes, Error>, parts: hyper::http::request::Parts) -> HttpRequest {
35 HttpRequest {
36 body,
37 parts,
38 params: HashMap::new()
39 }
40 }
41
42 pub fn from_parts_with_params(body: BoxBody<Bytes, Error>, parts: hyper::http::request::Parts, params: HashMap<String, String>) -> HttpRequest {
44 HttpRequest {
45 body,
46 parts,
47 params
48 }
49 }
50
51 pub fn body(self) -> BoxBody<Bytes, Error> {
57 self.body
58 }
59
60 pub fn body_as_stream(self) -> BodyDataStream<BoxBody<Bytes, Error>> {
64 self.body.into_data_stream()
65 }
66
67 pub async fn body_as_bytes(self) -> anyhow::Result<Bytes> {
71 Ok(self.body.collect().await?.to_bytes())
72 }
73
74 pub fn method(&self) -> &str {
76 self.parts.method.as_str()
77 }
78
79 pub fn host(&self) -> Option<&str> {
81 self.parts.uri.host()
82 }
83
84 pub fn path(&self) -> &str {
86 self.parts.uri.path()
87 }
88
89 pub fn port(&self) -> Option<u16> {
91 self.parts.uri.port_u16()
92 }
93
94 pub fn scheme(&self) -> Option<&str> {
96 self.parts.uri.scheme_str()
97 }
98
99 pub fn headers(&self) -> &HeaderMap<HeaderValue> {
101 &self.parts.headers
102 }
103
104 pub fn params(&self) -> &HashMap<String, String> {
106 &self.params
107 }
108}
109
110pub struct HttpRequestBuilder<State> {
111 builder: hyper::http::request::Builder,
112 _state: PhantomData<State>
113}
114
115impl HttpRequestBuilder<SetMethod> {
116 pub fn get(mut self, uri: impl Into<String>) -> HttpRequestBuilder<Final> {
118 self.builder = self.builder.method("GET").uri(uri.into());
119 HttpRequestBuilder {
120 builder: self.builder,
121 _state: PhantomData
122 }
123 }
124
125 pub fn post(mut self, uri: impl Into<String>) -> HttpRequestBuilder<Final> {
127 self.builder = self.builder.method("POST").uri(uri.into());
128 HttpRequestBuilder {
129 builder: self.builder,
130 _state: PhantomData
131 }
132 }
133
134 pub fn put(mut self, uri: impl Into<String>) -> HttpRequestBuilder<Final> {
136 self.builder = self.builder.method("PUT").uri(uri.into());
137 HttpRequestBuilder {
138 builder: self.builder,
139 _state: PhantomData
140 }
141 }
142
143 pub fn patch(mut self, uri: impl Into<String>) -> HttpRequestBuilder<Final> {
145 self.builder = self.builder.method("PATCH").uri(uri.into());
146 HttpRequestBuilder {
147 builder: self.builder,
148 _state: PhantomData
149 }
150 }
151
152 pub fn delete(mut self, uri: impl Into<String>) -> HttpRequestBuilder<Final> {
154 self.builder = self.builder.method("DELETE").uri(uri.into());
155 HttpRequestBuilder {
156 builder: self.builder,
157 _state: PhantomData
158 }
159 }
160
161 pub fn options(mut self, uri: impl Into<String>) -> HttpRequestBuilder<Final> {
163 self.builder = self.builder.method("OPTIONS").uri(uri.into());
164 HttpRequestBuilder {
165 builder: self.builder,
166 _state: PhantomData
167 }
168 }
169
170 pub fn head(mut self, uri: impl Into<String>) -> HttpRequestBuilder<Final> {
172 self.builder = self.builder.method("OPTIONS").uri(uri.into());
173 HttpRequestBuilder {
174 builder: self.builder,
175 _state: PhantomData
176 }
177 }
178
179 pub fn connect(mut self, uri: impl Into<String>) -> HttpRequestBuilder<Final> {
181 self.builder = self.builder.method("CONNECT").uri(uri.into());
182 HttpRequestBuilder {
183 builder: self.builder,
184 _state: PhantomData
185 }
186 }
187
188 pub fn trace(mut self, uri: impl Into<String>) -> HttpRequestBuilder<Final> {
190 self.builder = self.builder.method("TRACE").uri(uri.into());
191 HttpRequestBuilder {
192 builder: self.builder,
193 _state: PhantomData
194 }
195 }
196}
197
198impl HttpRequestBuilder<Final> {
199
200 pub fn body_empty(self) -> anyhow::Result<HttpRequest> {
202 let body = Empty::new().map_err(|e| match e {}).boxed();
203 let request = self.builder.body(body)?;
204 Ok(HttpRequest::from(request))
205 }
206
207 pub fn body_boxed(self, body: BoxBody<Bytes, Error>) -> anyhow::Result<HttpRequest> {
211 let request = self.builder.body(body)?;
212 Ok(HttpRequest::from(request))
213 }
214
215 pub fn body_bytes(self, body: impl Into<Bytes>) -> anyhow::Result<HttpRequest> {
217 let body = Full::from(body.into()).map_err(|e| match e {}).boxed();
218 let request = self.builder.body(body)?;
219 Ok(HttpRequest::from(request))
220 }
221
222 pub fn body_stream<S>(self, stream: S) -> anyhow::Result<HttpRequest>
224 where
225 S: Stream<Item = Result<Bytes, hyper::Error>> + Send + Sync + 'static,
226 {
227 let frame_stream = stream.map_ok(Frame::data);
228 let body = StreamBody::new(frame_stream);
229 let body_ext = BodyExt::boxed(body);
230 let request = self.builder.body(body_ext)?;
231 Ok(HttpRequest::from(request))
232 }
233
234 pub fn header(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
236 self.builder = self.builder.header(key.into(), value.into());
237 self
238 }
239
240 pub fn headers(mut self, headers: &HeaderMap<HeaderValue>) -> Self {
242 for (key, value) in headers.iter() {
243 self.builder = self.builder.header(key, value);
244 }
245 self
246 }
247}
248
249impl From<HttpRequest> for Request<BoxBody<Bytes, Error>> {
250 fn from(req: HttpRequest) -> Self {
251 Request::from_parts(req.parts, req.body.boxed())
252 }
253}
254
255impl From<Request<BoxBody<Bytes, Error>>> for HttpRequest {
256 fn from(req: Request<BoxBody<Bytes, Error>>) -> Self {
257 let (parts, body) = req.into_parts();
258 HttpRequest::from_parts(body, parts)
259 }
260}
261
262impl From<Request<Incoming>> for HttpRequest {
263 fn from(req: Request<Incoming>) -> Self {
264 let (parts, body) = req.into_parts();
265 HttpRequest::from_parts(body.boxed(), parts)
266 }
267}
268