mangadex_api/v5/ping/
get.rs

1//! Builder for the ping endpoint.
2//!
3//! <https://api.mangadex.org/docs/swagger.html#/Infrastructure/get_ping>
4//!
5//! # Examples
6//!
7//! ```rust
8//! use mangadex_api::v5::MangaDexClient;
9//!
10//! # async fn run() -> anyhow::Result<()> {
11//! let client = MangaDexClient::default();
12//!
13//! let res = client
14//!     .ping()
15//!     .get()
16//!     .send()
17//!     .await?;
18//!
19//! println!("ping: {:?}", res);
20//! # Ok(())
21//! # }
22//! ```
23
24use derive_builder::Builder;
25use serde::Serialize;
26
27use crate::HttpClientRef;
28use mangadex_api_types::error::{Error, Result};
29
30/// Ping the server.
31///
32/// Makes a request to `GET /ping`.
33// It doesn't make much sense to make this a builder pattern but for consistency, it is.
34#[cfg_attr(
35    feature = "deserializable-endpoint",
36    derive(serde::Deserialize, getset::Getters, getset::Setters)
37)]
38#[derive(Debug, Serialize, Clone, Builder, Default)]
39#[serde(rename_all = "camelCase")]
40#[builder(
41    setter(into, strip_option),
42    build_fn(error = "mangadex_api_types::error::BuilderError")
43)]
44pub struct Ping {
45    /// This should never be set manually as this is only for internal use.
46    #[doc(hidden)]
47    #[serde(skip)]
48    #[builder(pattern = "immutable")]
49    #[cfg_attr(feature = "deserializable-endpoint", getset(set = "pub", get = "pub"))]
50    pub http_client: HttpClientRef,
51}
52
53endpoint! {
54    GET "/ping",
55    #[no_data] Ping,
56    #[no_send] Result<String>,
57    PingBuilder
58}
59
60impl Ping {
61    pub async fn send(&self) -> Result<String> {
62        #[cfg(all(
63            not(feature = "multi-thread"),
64            not(feature = "tokio-multi-thread"),
65            not(feature = "rw-multi-thread")
66        ))]
67        let res = self
68            .http_client
69            .try_borrow()?
70            .send_request_without_deserializing(self)
71            .await?;
72        #[cfg(any(feature = "multi-thread", feature = "tokio-multi-thread"))]
73        let res = self
74            .http_client
75            .lock()
76            .await
77            .send_request_without_deserializing(self)
78            .await?;
79        #[cfg(feature = "rw-multi-thread")]
80        let res = self
81            .http_client
82            .read()
83            .await
84            .send_request_without_deserializing(self)
85            .await?;
86
87        let response_body = res.text().await?;
88        if response_body.as_str() == "pong" {
89            return Ok(response_body);
90        }
91
92        Err(Error::PingError)
93    }
94}
95
96#[cfg(test)]
97mod tests {
98    use url::Url;
99    use wiremock::matchers::{method, path};
100    use wiremock::{Mock, MockServer, ResponseTemplate};
101
102    use crate::{HttpClient, MangaDexClient};
103
104    #[tokio::test]
105    async fn ping_fires_a_request_to_base_url() -> anyhow::Result<()> {
106        let mock_server = MockServer::start().await;
107        let http_client: HttpClient = HttpClient::builder()
108            .base_url(Url::parse(&mock_server.uri())?)
109            .build()?;
110        let mangadex_client = MangaDexClient::new_with_http_client(http_client);
111
112        let response_body = "pong";
113
114        Mock::given(method("GET"))
115            .and(path(r"/ping"))
116            .respond_with(ResponseTemplate::new(200).set_body_string(response_body))
117            .expect(1)
118            .mount(&mock_server)
119            .await;
120
121        let res = mangadex_client.ping().get().send().await?;
122
123        assert_eq!(res, "pong".to_string());
124
125        Ok(())
126    }
127}