1use reqwest::{
2 header::{HeaderMap, HeaderValue},
3 Client as HttpClient, StatusCode, Url,
4};
5use serde::Serialize;
6use std::time::Duration;
7
8mod builders;
9mod error;
10mod types;
11
12use builders::*;
13pub use error::Error;
14use error::Result;
15pub use types::Format;
16use types::{Request, Response};
17
18#[derive(Debug)]
20pub struct Client {
21 client: HttpClient,
22 base_url: Url,
23}
24
25impl Client {
26 pub fn new(base_url: Url) -> Self {
28 let mut headers = HeaderMap::new();
30 headers.insert("Content-Type", HeaderValue::from_static("application/json"));
31
32 let client = HttpClient::builder()
34 .default_headers(headers)
35 .timeout(Duration::from_secs(10))
36 .build()
37 .unwrap();
38
39 Client { client, base_url }
40 }
41
42 pub(crate) async fn dispatch<T>(&self, path: &str, req: Request<'_, T>) -> Result<()>
44 where
45 T: Serialize,
46 {
47 let resp = self
48 .client
49 .post(self.base_url.join(path).unwrap())
50 .json(&req)
51 .send()
52 .await?;
53
54 let status = resp.status();
55 if status == StatusCode::OK {
56 Ok(())
57 } else {
58 let body: Response = resp.json().await?;
59 if status == StatusCode::BAD_REQUEST {
60 Err(Error::InvalidArgument(body.message))
61 } else {
62 Err(Error::Unknown(body.message))
63 }
64 }
65 }
66
67 pub async fn send<'s>(
69 &'s self,
70 to: &'s str,
71 from: &'s str,
72 subject: &'s str,
73 body: &'s str,
74 ) -> SendBuilder<'s> {
75 SendBuilder::new(self, to, from, subject, body)
76 }
77
78 pub async fn send_batch<'s>(
80 &'s self,
81 from: &'s str,
82 subject: &'s str,
83 body: &'s str,
84 ) -> SendBatchBuilder<'s> {
85 SendBatchBuilder::new(self, from, subject, body)
86 }
87
88 pub async fn send_template<'s>(
90 &'s self,
91 from: &'s str,
92 subject: &'s str,
93 body: &'s str,
94 ) -> SendTemplateBuilder<'s> {
95 SendTemplateBuilder::new(self, from, subject, body)
96 }
97}