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 {
29 let http_client = reqwest::Client::new();
30
31 return Client {
32 http_client,
33 api_base_url: "https://api.postmarkapp.com",
34 account_api_token,
35 };
36 }
37
38 pub(crate) async fn send_request<B: Serialize, R: DeserializeOwned>(
39 &self,
40 input: SendRequestInput<B>,
41 ) -> Result<R, ApiError> {
42 let mut headers: HeaderMap<HeaderValue> = HeaderMap::new();
45 headers.insert(header::ACCEPT, HeaderValue::from_str("application/json").unwrap());
46 headers.insert(header::CONTENT_TYPE, HeaderValue::from_str("application/json").unwrap());
47
48 if let Some(server_api_token) = input.server_token {
49 headers.insert("X-Postmark-Server-Token", HeaderValue::from_str(&server_api_token).unwrap());
50 } else if let Some(account_api_token) = &self.account_api_token {
51 headers.insert(
52 "X-Postmark-Account-Token",
53 HeaderValue::from_str(account_api_token.as_str()).unwrap(),
54 );
55 }
56
57 let url = format!("{}{}", &self.api_base_url, input.url);
58 let res = self
59 .http_client
60 .request(input.method, url)
61 .headers(headers)
62 .json(&input.body)
63 .send()
64 .await
65 .map_err(|err| ApiError {
66 error_code: 0,
67 message: format!("postmark: error sending request: {err}"),
68 })?;
69
70 if res.status().as_u16() > 399 {
71 let err: ApiError = res.json().await.map_err(|err| ApiError {
72 error_code: 0,
73 message: format!("postmark: error parsing error response: {err}"),
74 })?;
75 return Err(err);
76 }
77
78 let res: R = res.json().await.map_err(|err| ApiError {
79 error_code: 0,
80 message: format!("postmark: error parsing response: {err}"),
81 })?;
82
83 return Ok(res);
84 }
85}