resend_rs/idempotent.rs
1//! A few helpers for adding idempotency keys to requests that support them.
2//!
3//! ### Example
4//!
5//! ```rust,no_run
6//! use resend_rs::{idempotent::IdempotentTrait, types::CreateEmailBaseOptions};
7//! use resend_rs::{Resend, Result};
8//!
9//! #[tokio::main]
10//! async fn main() -> Result<()> {
11//! let resend = Resend::new("re_123456789");
12//!
13//! let emails = vec![
14//! CreateEmailBaseOptions::new(
15//! "Acme <onboarding@resend.dev>",
16//! vec!["foo@gmail.com"],
17//! "hello world",
18//! )
19//! .with_html("<h1>it works!</h1>"),
20//! CreateEmailBaseOptions::new(
21//! "Acme <onboarding@resend.dev>",
22//! vec!["bar@outlook.com"],
23//! "world hello",
24//! )
25//! .with_html("<p>it works!</p>"),
26//! ].with_idempotency_key("welcome-user/123456789");
27//!
28//! let _emails = resend.batch.send(emails).await?;
29//!
30//! Ok(())
31//!}
32//! ```
33use crate::types::CreateEmailBaseOptions;
34
35/// Wrapper struct for adding an `idempotency_key` header to data `T`.
36#[derive(Debug, Clone, serde::Serialize)]
37pub struct Idempotent<T> {
38 #[serde(skip)]
39 pub(crate) idempotency_key: Option<String>,
40 #[serde(flatten)]
41 pub(crate) data: T,
42}
43
44/// Implements `From<inner>` only works for concrete types.
45macro_rules! idempotent_from {
46 ($inner:ty) => {
47 impl From<$inner> for Idempotent<$inner> {
48 fn from(value: $inner) -> Self {
49 Self {
50 idempotency_key: None,
51 data: value,
52 }
53 }
54 }
55 };
56}
57
58idempotent_from!(CreateEmailBaseOptions);
59idempotent_from!(Vec<CreateEmailBaseOptions>);
60
61/// Used to add easy conversion of trait impls to [`Idempotent`].
62pub trait IdempotentTrait<T> {
63 /// Adds an `Idempotency-Key` header to the request.
64 fn with_idempotency_key(self, idempotency_key: &str) -> Idempotent<T>;
65}
66
67impl<T> IdempotentTrait<Self> for T
68where
69 T: IntoIterator<Item = CreateEmailBaseOptions> + Send,
70{
71 fn with_idempotency_key(self, idempotency_key: &str) -> Idempotent<Self> {
72 Idempotent {
73 idempotency_key: Some(idempotency_key.to_owned()),
74 data: self,
75 }
76 }
77}