Skip to main content

resend_rs/
logs.rs

1use std::sync::Arc;
2
3use reqwest::Method;
4
5use crate::{
6    Config, Result,
7    list_opts::{ListOptions, ListResponse},
8    types::Log,
9};
10
11/// `Resend` APIs for `/logs` endpoints.
12#[derive(Clone, Debug)]
13pub struct LogsSvc(pub(crate) Arc<Config>);
14
15impl LogsSvc {
16    /// Retrieve a single API request log.
17    ///
18    /// <https://resend.com/docs/api-reference/logs/retrieve-log>
19    #[maybe_async::maybe_async]
20    pub async fn get(&self, log_id: &str) -> Result<Log> {
21        let path = format!("/logs/{log_id}");
22
23        let request = self.0.build(Method::GET, &path);
24        let response = self.0.send(request).await?;
25        let content = response.json::<Log>().await?;
26
27        Ok(content)
28    }
29
30    /// Retrieve a list of API request logs.
31    ///
32    /// - Default limit: 20
33    ///
34    /// <https://resend.com/docs/api-reference/logs/list-logs>
35    #[maybe_async::maybe_async]
36    pub async fn list<T>(&self, list_opts: ListOptions<T>) -> Result<ListResponse<Log>> {
37        let request = self.0.build(Method::GET, "/logs").query(&list_opts);
38        let response = self.0.send(request).await?;
39        let content = response.json::<ListResponse<Log>>().await?;
40
41        Ok(content)
42    }
43}
44
45#[allow(unreachable_pub)]
46pub mod types {
47    use std::num::NonZeroU16;
48
49    use serde::{Deserialize, Serialize};
50
51    crate::define_id_type!(LogId);
52
53    #[must_use]
54    #[derive(Debug, Clone, Serialize, Deserialize)]
55    pub struct Log {
56        pub id: LogId,
57        pub created_at: String,
58        pub endpoint: String,
59        pub method: String,
60        pub response_status: NonZeroU16,
61        pub user_agent: Option<String>,
62        #[serde(default)]
63        pub request_body: serde_json::Value,
64        #[serde(default)]
65        pub response_body: serde_json::Value,
66    }
67}
68
69#[cfg(test)]
70#[allow(clippy::needless_return, clippy::unwrap_used)]
71mod test {
72    #[cfg(not(feature = "blocking"))]
73    use crate::{
74        list_opts::ListOptions,
75        test::{CLIENT, DebugResult},
76    };
77
78    #[tokio_shared_rt::test(shared = true)]
79    #[serial_test::serial]
80    #[cfg(not(feature = "blocking"))]
81    async fn all() -> DebugResult<()> {
82        let resend = &*CLIENT;
83
84        // List
85        let logs = resend.logs.list(ListOptions::default()).await?;
86        assert!(!logs.data.is_empty());
87
88        // Get
89        let head = logs.data.first().unwrap();
90
91        let _log = resend.logs.get(&head.id).await?;
92
93        Ok(())
94    }
95}