1use std::sync::Arc;
2
3use bytes::Bytes;
4use http::{HeaderMap, HeaderName, HeaderValue, Method};
5use serde::Serialize;
6
7use crate::{HttpClient, HttpError, HttpResponse};
8
9#[derive(Debug, Clone)]
10pub struct HttpRequest {
11 pub method: Method,
12 pub url: String,
13 pub headers: HeaderMap,
14 pub body: Option<Bytes>,
15}
16
17impl HttpRequest {
18 pub fn new(method: Method, url: impl Into<String>) -> Self {
19 Self {
20 method,
21 url: url.into(),
22 headers: HeaderMap::new(),
23 body: None,
24 }
25 }
26}
27
28pub struct HttpRequestBuilder {
29 client: Arc<dyn HttpClient>,
30 request: Result<HttpRequest, HttpError>,
31}
32
33impl HttpRequestBuilder {
34 pub fn new(client: Arc<dyn HttpClient>, method: Method, url: impl Into<String>) -> Self {
35 Self {
36 client,
37 request: Ok(HttpRequest::new(method, url)),
38 }
39 }
40
41 pub fn header<K, V>(mut self, key: K, value: V) -> Self
42 where
43 HeaderName: TryFrom<K>,
44 <HeaderName as TryFrom<K>>::Error: std::fmt::Display,
45 HeaderValue: TryFrom<V>,
46 <HeaderValue as TryFrom<V>>::Error: std::fmt::Display,
47 {
48 if let Ok(req) = self.request.as_mut() {
49 match (HeaderName::try_from(key), HeaderValue::try_from(value)) {
50 (Ok(name), Ok(val)) => {
51 req.headers.append(name, val);
52 }
53 (Err(e), _) => {
54 self.request = Err(HttpError::InvalidHeader(format!("header name: {e}")));
55 }
56 (_, Err(e)) => {
57 self.request = Err(HttpError::InvalidHeader(format!("header value: {e}")));
58 }
59 }
60 }
61 self
62 }
63
64 pub fn headers(mut self, headers: HeaderMap) -> Self {
65 if let Ok(req) = self.request.as_mut() {
66 req.headers.extend(headers);
67 }
68 self
69 }
70
71 pub fn bearer_auth(self, token: impl std::fmt::Display) -> Self {
72 self.header(http::header::AUTHORIZATION, format!("Bearer {token}"))
73 }
74
75 pub fn body(mut self, body: impl Into<Bytes>) -> Self {
76 if let Ok(req) = self.request.as_mut() {
77 req.body = Some(body.into());
78 }
79 self
80 }
81
82 pub fn json<T: Serialize + ?Sized>(mut self, value: &T) -> Self {
83 if let Ok(req) = self.request.as_mut() {
84 match serde_json::to_vec(value) {
85 Ok(bytes) => {
86 if !req.headers.contains_key(http::header::CONTENT_TYPE) {
87 req.headers.insert(
88 http::header::CONTENT_TYPE,
89 HeaderValue::from_static("application/json"),
90 );
91 }
92 req.body = Some(Bytes::from(bytes));
93 }
94 Err(e) => {
95 self.request = Err(HttpError::Serialize(e));
96 }
97 }
98 }
99 self
100 }
101
102 pub fn build(self) -> Result<HttpRequest, HttpError> {
103 self.request
104 }
105
106 pub async fn send(self) -> Result<HttpResponse, HttpError> {
107 let Self { client, request } = self;
108 let request = request?;
109 client.execute(request).await
110 }
111}