rust_integration_services/http/
http_response.rs1use std::marker::PhantomData;
2
3use bytes::Bytes;
4use futures::{Stream, TryStreamExt};
5use http_body_util::{BodyDataStream, BodyExt, Empty, Full, StreamBody, combinators::BoxBody};
6use hyper::{Error, HeaderMap, Response, body::{Frame, Incoming}, header::HeaderValue};
7
8pub struct Final;
9pub struct SetStatus;
10
11#[derive(Debug)]
12pub struct HttpResponse {
13 body: BoxBody<Bytes, Error>,
14 parts: hyper::http::response::Parts,
15}
16
17impl HttpResponse {
18
19 pub fn builder() -> HttpResponseBuilder<SetStatus> {
21 HttpResponseBuilder {
22 builder: Response::builder(),
23 _state: PhantomData
24 }
25 }
26
27 pub fn from_parts(body: BoxBody<Bytes, Error>, parts: hyper::http::response::Parts) -> HttpResponse {
29 HttpResponse {
30 body,
31 parts
32 }
33 }
34
35 pub fn body(self) -> BoxBody<Bytes, Error> {
41 self.body
42 }
43
44 pub fn body_as_stream(self) -> BodyDataStream<BoxBody<Bytes, Error>> {
48 self.body.into_data_stream()
49 }
50
51 pub async fn body_as_bytes(self) -> anyhow::Result<Bytes> {
55 Ok(self.body.collect().await?.to_bytes())
56 }
57
58 pub fn status(&self) -> u16 {
60 self.parts.status.as_u16()
61 }
62
63 pub fn headers(&self) -> &HeaderMap<HeaderValue> {
65 &self.parts.headers
66 }
67}
68
69pub struct HttpResponseBuilder<State> {
70 builder: hyper::http::response::Builder,
71 _state: PhantomData<State>
72}
73
74impl HttpResponseBuilder<SetStatus> {
75 pub fn status(mut self, status: u16) -> HttpResponseBuilder<Final> {
76 self.builder = self.builder.status(status);
77 HttpResponseBuilder {
78 builder: self.builder,
79 _state: PhantomData
80 }
81 }
82}
83
84impl HttpResponseBuilder<Final> {
85
86 pub fn body_empty(self) -> anyhow::Result<HttpResponse> {
88 let body = Empty::new().map_err(|e| match e {}).boxed();
89 let response = self.builder.body(body)?;
90 Ok(HttpResponse::from(response))
91 }
92
93 pub fn body_boxed(self, body: BoxBody<Bytes, Error>) -> anyhow::Result<HttpResponse> {
97 let response = self.builder.body(body)?;
98 Ok(HttpResponse::from(response))
99 }
100
101 pub fn body_bytes(self, body: impl Into<Bytes>) -> anyhow::Result<HttpResponse> {
103 let body = Full::from(body.into()).map_err(|e| match e {}).boxed();
104 let response = self.builder.body(body)?;
105 Ok(HttpResponse::from(response))
106 }
107
108 pub fn body_stream<S>(self, stream: S) -> anyhow::Result<HttpResponse>
110 where
111 S: Stream<Item = Result<Bytes, hyper::Error>> + Send + Sync + 'static,
112 {
113 let frame_stream = stream.map_ok(Frame::data);
114 let body = StreamBody::new(frame_stream);
115 let body_ext = BodyExt::boxed(body);
116 let response = self.builder.body(body_ext)?;
117 Ok(HttpResponse::from(response))
118 }
119
120 pub fn header(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
122 self.builder = self.builder.header(key.into(), value.into());
123 self
124 }
125
126 pub fn headers(mut self, headers: &HeaderMap<HeaderValue>) -> Self {
128 for (key, value) in headers.iter() {
129 self.builder = self.builder.header(key, value);
130 }
131 self
132 }
133}
134
135impl From<HttpResponse> for Response<BoxBody<Bytes, Error>> {
136 fn from(res: HttpResponse) -> Self {
137 Response::from_parts(res.parts, res.body)
138 }
139}
140
141impl From<Response<BoxBody<Bytes, Error>>> for HttpResponse {
142 fn from(res: Response<BoxBody<Bytes, Error>>) -> Self {
143 let (parts, body) = res.into_parts();
144 HttpResponse::from_parts(body, parts)
145 }
146}
147
148impl From<Response<Incoming>> for HttpResponse {
149 fn from(req: Response<Incoming>) -> Self {
150 let (parts, body) = req.into_parts();
151 HttpResponse::from_parts(body.boxed(), parts)
152 }
153}
154