1use reqwest::{
2 Method,
3 header::{self, HeaderMap, HeaderValue},
4};
5use serde::{Deserialize, Serialize, de::DeserializeOwned};
6
7pub struct Client {
8 pub http_client: reqwest::Client,
9 pub api_base_url: &'static str,
10 pub account_api_token: Option<String>,
11}
12
13#[derive(Clone, Debug, Deserialize, Serialize)]
14#[serde(rename_all = "PascalCase")]
15pub struct ApiError {
16 pub error_code: i64,
17 pub message: String,
18}
19
20pub struct SendRequestInput<B: Serialize> {
21 pub method: Method,
22 pub url: String,
23 pub body: B,
24 pub server_token: Option<String>,
25}
26
27impl Client {
28 pub fn new(account_api_token: Option<String>) -> Client {
35 crypto_rustls::install_default_rustls_provider();
36 let http_client = reqwest::Client::new();
37
38 return Client {
39 http_client,
40 api_base_url: "https://api.postmarkapp.com",
41 account_api_token,
42 };
43 }
44
45 pub(crate) async fn send_request<B: Serialize, R: DeserializeOwned>(
46 &self,
47 input: SendRequestInput<B>,
48 ) -> Result<R, ApiError> {
49 let mut headers: HeaderMap<HeaderValue> = HeaderMap::new();
52 headers.insert(header::ACCEPT, HeaderValue::from_str("application/json").unwrap());
53 headers.insert(header::CONTENT_TYPE, HeaderValue::from_str("application/json").unwrap());
54
55 if let Some(server_api_token) = input.server_token {
56 headers.insert("X-Postmark-Server-Token", HeaderValue::from_str(&server_api_token).unwrap());
57 } else if let Some(account_api_token) = &self.account_api_token {
58 headers.insert(
59 "X-Postmark-Account-Token",
60 HeaderValue::from_str(account_api_token.as_str()).unwrap(),
61 );
62 }
63
64 let url = format!("{}{}", &self.api_base_url, input.url);
65 let res = self
66 .http_client
67 .request(input.method, url)
68 .headers(headers)
69 .json(&input.body)
70 .send()
71 .await
72 .map_err(|err| ApiError {
73 error_code: 0,
74 message: format!("postmark: error sending request: {err}"),
75 })?;
76
77 if res.status().as_u16() > 399 {
78 let err: ApiError = res.json().await.map_err(|err| ApiError {
79 error_code: 0,
80 message: format!("postmark: error parsing error response: {err}"),
81 })?;
82 return Err(err);
83 }
84
85 let res: R = res.json().await.map_err(|err| ApiError {
86 error_code: 0,
87 message: format!("postmark: error parsing response: {err}"),
88 })?;
89
90 return Ok(res);
91 }
92}