resend_rs/
segments.rs

1use std::fmt;
2use std::sync::Arc;
3
4use reqwest::Method;
5
6use crate::{Config, Result, list_opts::ListOptions};
7use crate::{list_opts::ListResponse, types::Segment};
8
9use self::types::CreateSegmentResponse;
10
11/// `Resend` APIs for `/segments` endpoints.
12#[derive(Clone)]
13pub struct SegmentsSvc(pub(crate) Arc<Config>);
14
15impl SegmentsSvc {
16    /// Create a new segment for contacts to be added to.
17    ///
18    /// Returns an `id` of a created segment.
19    ///
20    /// <https://resend.com/docs/api-reference/segments/create-segment>
21    #[maybe_async::maybe_async]
22    pub async fn create(&self, name: &str) -> Result<CreateSegmentResponse> {
23        let segment = types::CreateSegmentRequest {
24            name: name.to_owned(),
25        };
26
27        let request = self.0.build(Method::POST, "/segments");
28        let response = self.0.send(request.json(&segment)).await?;
29        let content = response.json::<CreateSegmentResponse>().await?;
30
31        Ok(content)
32    }
33
34    /// Retrieve a single segment.
35    ///
36    /// <https://resend.com/docs/api-reference/segments/get-segment>
37    #[maybe_async::maybe_async]
38    pub async fn get(&self, id: &str) -> Result<Segment> {
39        let path = format!("/segments/{id}");
40
41        let request = self.0.build(Method::GET, &path);
42        let response = self.0.send(request).await?;
43        let content = response.json::<Segment>().await?;
44
45        Ok(content)
46    }
47
48    /// Remove an existing segment.
49    ///
50    /// <https://resend.com/docs/api-reference/segments/delete-segment>
51    #[maybe_async::maybe_async]
52    #[allow(clippy::needless_pass_by_value)]
53    pub async fn delete(&self, id: &str) -> Result<bool> {
54        let path = format!("/segments/{id}");
55
56        let request = self.0.build(Method::DELETE, &path);
57        let response = self.0.send(request).await?;
58        let content = response.json::<types::RemoveSegmentResponse>().await?;
59
60        Ok(content.deleted)
61    }
62
63    /// Retrieve a list of segments.
64    ///
65    /// - Default limit: no limit (return everything)
66    ///
67    /// <https://resend.com/docs/api-reference/segments/list-segments>
68    #[maybe_async::maybe_async]
69    #[allow(clippy::needless_pass_by_value)]
70    pub async fn list<T>(&self, list_opts: ListOptions<T>) -> Result<ListResponse<Segment>> {
71        let request = self.0.build(Method::GET, "/segments").query(&list_opts);
72        let response = self.0.send(request).await?;
73        let content = response.json::<ListResponse<Segment>>().await?;
74
75        Ok(content)
76    }
77}
78
79impl fmt::Debug for SegmentsSvc {
80    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81        fmt::Debug::fmt(&self.0, f)
82    }
83}
84
85#[allow(unreachable_pub)]
86pub mod types {
87    use serde::{Deserialize, Serialize};
88
89    crate::define_id_type!(SegmentId);
90
91    #[must_use]
92    #[derive(Debug, Clone, Serialize)]
93    pub struct CreateSegmentRequest {
94        /// The name of the segment you want to create.
95        pub name: String,
96    }
97
98    #[derive(Debug, Clone, Deserialize)]
99    pub struct CreateSegmentResponse {
100        /// The ID of the segment.
101        pub id: SegmentId,
102        /// The name of the segment.
103        pub name: String,
104    }
105
106    /// Name and ID of an existing contact list.
107    #[must_use]
108    #[derive(Debug, Clone, Deserialize)]
109    pub struct Segment {
110        /// The ID of the segment.
111        pub id: SegmentId,
112        // /// The object of the segment.
113        // pub object: String,
114        /// The name of the segment.
115        pub name: String,
116        /// The date that the object was created in ISO8601 format.
117        pub created_at: String,
118    }
119
120    #[derive(Debug, Clone, Deserialize)]
121    pub struct RemoveSegmentResponse {
122        /// The ID of the segment.
123        #[allow(dead_code)]
124        pub id: SegmentId,
125        /// The deleted attribute indicates that the corresponding segment has been deleted.
126        pub deleted: bool,
127    }
128}
129
130#[cfg(test)]
131#[allow(clippy::needless_return)]
132mod test {
133    use crate::list_opts::ListOptions;
134    use crate::test::{CLIENT, DebugResult};
135
136    #[tokio_shared_rt::test(shared = true)]
137    #[cfg(not(feature = "blocking"))]
138    async fn all() -> DebugResult<()> {
139        let resend = &*CLIENT;
140        let segment = "test_segments";
141
142        // Create.
143        let created = resend.segments.create(segment).await?;
144        let id = created.id;
145        std::thread::sleep(std::time::Duration::from_secs(2));
146
147        // Get.
148        let data = resend.segments.get(&id).await?;
149        assert_eq!(data.name.as_str(), segment);
150
151        // List.
152        let segments = resend.segments.list(ListOptions::default()).await?;
153        let segments_before = segments.len();
154        assert!(segments_before > 1);
155
156        // Delete.
157        let deleted = resend.segments.delete(&id).await?;
158        assert!(deleted);
159
160        Ok(())
161    }
162}