parco_lob/create_postcard/
request.rs

1use std::borrow::Cow;
2
3use reqwest::header::CONTENT_TYPE;
4use serde::Serialize;
5
6use crate::{
7    CreatePostcardError, CreatePostcardResponse, WrapperApiError,
8    constants::{APPLICATION_JSON, IDEMPOTENCY_KEY},
9};
10
11pub struct CreatePostcardRequest<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k, 'l, Merge> {
12    pub(crate) client: reqwest::Client,
13    pub(crate) api_key: &'a str,
14    pub(crate) url: Cow<'b, str>,
15    pub(crate) idempotency_key: &'c str,
16    pub(crate) json_request: JsonRequest<'d, 'e, 'f, 'g, 'h, 'i, 'j, 'k, 'l, Merge>,
17}
18
19pub struct CreatePostcardRequestNoMerge<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k, 'l> {
20    pub(crate) client: reqwest::Client,
21    pub(crate) api_key: &'a str,
22    pub(crate) url: Cow<'b, str>,
23    pub(crate) idempotency_key: &'c str,
24    pub(crate) json_request: JsonRequestNoMerge<'d, 'e, 'f, 'g, 'h, 'i, 'j, 'k, 'l>,
25}
26
27#[derive(Serialize)]
28pub struct JsonRequest<'d, 'e, 'f, 'g, 'h, 'i, 'j, 'k, 'l, Merge> {
29    pub(crate) to: To<'d, 'e, 'f, 'g, 'h, 'i>,
30    pub(crate) front: &'j str,
31    pub(crate) back: &'k str,
32    pub(crate) size: Size,
33    pub(crate) mail_type: MailType,
34    pub(crate) merge_variables: Merge,
35    pub(crate) description: &'l str,
36    pub(crate) use_type: UseType,
37}
38
39#[derive(Serialize)]
40pub struct JsonRequestNoMerge<'d, 'e, 'f, 'g, 'h, 'i, 'j, 'k, 'l> {
41    pub(crate) to: To<'d, 'e, 'f, 'g, 'h, 'i>,
42    pub(crate) front: &'j str,
43    pub(crate) back: &'k str,
44    pub(crate) size: Size,
45    pub(crate) mail_type: MailType,
46    pub(crate) description: &'l str,
47    pub(crate) use_type: UseType,
48}
49
50#[derive(Serialize)]
51pub struct To<'d, 'e, 'f, 'g, 'h, 'i> {
52    pub(crate) name: &'d str,
53    #[serde(rename = "address_line1")]
54    pub(crate) address_line_1: &'e str,
55    #[serde(rename = "address_line2")]
56    pub(crate) address_line_2: Option<&'f str>,
57    pub(crate) address_city: &'g str,
58    pub(crate) address_state: &'h str,
59    pub(crate) address_zip: &'i str,
60}
61
62#[derive(Serialize)]
63#[serde(rename_all = "lowercase")]
64/// Identifying your mail use type helps Lob populate the right mail settings and postage options to ensure your mail is produced and delivered in an optimal way. Lob requires that you identify—or tag—your mail with one of the following use type options:
65pub enum UseType {
66    /// Marketing mail: Any mailers that are sent for marketing, advertising, and promotional purposes
67    Marketing,
68
69    /// Operational mail: All other mail, typically transactional or functional in nature, such as invoices, adverse action notices, statements, and other confidential mail that include sensitive PII/PHI data
70    Operational,
71}
72
73#[derive(Serialize)]
74/// Specifies the size of the postcard. Only 4x6 postcards can be sent to international destinations.
75pub enum Size {
76    #[serde(rename = "4x6")]
77    FourBySix,
78    #[serde(rename = "6x9")]
79    SixByNine,
80    #[serde(rename = "6x11")]
81    SixByEleven,
82}
83
84/// An enum designating the mail postage type
85#[derive(Serialize)]
86#[serde(rename_all = "snake_case")]
87pub enum MailType {
88    /// usps_first_class - (default)
89    UspsFirstClass,
90    /// usps_standard - a cheaper option which is less predictable and takes longer to deliver. usps_standard cannot be used with 4x6 postcards or for any postcards sent outside of the United States.
91    UspsStandard,
92}
93
94impl<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k, 'l, Merge: Serialize>
95    CreatePostcardRequest<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k, 'l, Merge>
96{
97    pub async fn send(self) -> Result<CreatePostcardResponse, CreatePostcardError> {
98        let request = serde_json::to_string(&self.json_request)?;
99
100        let src = self
101            .client
102            .post(self.url.as_ref())
103            .header(CONTENT_TYPE, APPLICATION_JSON)
104            .header(IDEMPOTENCY_KEY, self.idempotency_key)
105            .basic_auth::<_, &str>(self.api_key, None)
106            .body(request)
107            .send()
108            .await?
109            .text()
110            .await?;
111
112        if let Ok(wrapper_api_error) = serde_json::from_str::<WrapperApiError>(src.as_str()) {
113            return Err(CreatePostcardError::Api(wrapper_api_error.error));
114        }
115
116        match serde_json::from_str(src.as_str()) {
117            Ok(ok) => Ok(ok),
118            Err(err) => Err(CreatePostcardError::Json(err, src)),
119        }
120    }
121}
122
123impl<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k, 'l>
124    CreatePostcardRequestNoMerge<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k, 'l>
125{
126    pub async fn send(self) -> Result<CreatePostcardResponse, CreatePostcardError> {
127        let request = serde_json::to_string(&self.json_request)?;
128
129        let src = self
130            .client
131            .post(self.url.as_ref())
132            .header(CONTENT_TYPE, APPLICATION_JSON)
133            .header(IDEMPOTENCY_KEY, self.idempotency_key)
134            .basic_auth::<&str, &str>(self.api_key, None)
135            .body(request)
136            .send()
137            .await?
138            .text()
139            .await?;
140
141        if let Ok(wrapper_api_error) = serde_json::from_str::<WrapperApiError>(src.as_str()) {
142            return Err(CreatePostcardError::Api(wrapper_api_error.error));
143        }
144
145        match serde_json::from_str(src.as_str()) {
146            Ok(ok) => Ok(ok),
147            Err(err) => Err(CreatePostcardError::Json(err, src)),
148        }
149    }
150}