Skip to main content

pasty_rs/
client.rs

1use crate::{
2    errors::Result,
3    model::{ApplicationInformation, CreatePasteRequest, CreatedPaste, Metadata, Paste},
4};
5use reqwest::{Client, IntoUrl, Request, Url};
6use serde::de::DeserializeOwned;
7
8/// API client to perform unauthenticated requests to the
9/// pasty API.
10///
11/// # Reference
12/// Implementation according to the pasty API documentation:
13/// https://github.com/lus/pasty/blob/master/API.md#api
14#[derive(Clone)]
15pub struct UnauthenticatedClient {
16    client: Client,
17    host: Url,
18}
19
20impl UnauthenticatedClient {
21    /// Creates a new instance of UnauthenticatedClient with the given
22    /// host URL.
23    ///
24    /// # Example
25    /// ```
26    /// # use pasty_rs::client::*;
27    /// # #[tokio::main]
28    /// # async fn main() {
29    /// let client = UnauthenticatedClient::new("https://pasty.lus.pm").unwrap();
30    /// let res = client.application_information().await.unwrap();
31    /// # }
32    /// ```
33    ///
34    /// # Reference
35    /// Implementation according to the pasty API documentation:
36    /// https://github.com/lus/pasty/blob/master/API.md#api
37    pub fn new(host: impl IntoUrl) -> Result<Self> {
38        Ok(Self {
39            client: Default::default(),
40            host: host.into_url()?,
41        })
42    }
43
44    /// Returns generall application information of the pasty instance.
45    ///
46    /// # Reference
47    /// Binds to the `GET /api/v2/info` endpoint.
48    /// https://github.com/lus/pasty/blob/master/API.md#unsecured-retrieve-application-information
49    pub async fn application_information(&self) -> Result<ApplicationInformation> {
50        let r = self.client.get(self.host.join("/api/v2/info")?).build()?;
51        req_body(&self.client, r).await
52    }
53
54    /// Returns a pastes content by it's ID.
55    ///
56    /// # Reference
57    /// Binds to the `GET /api/v2/pastes/{paste_id}` endpoint.
58    /// https://github.com/lus/pasty/blob/master/API.md#unsecured-retrieve-a-paste
59    pub async fn paste(&self, id: &str) -> Result<Paste> {
60        let r = self
61            .client
62            .get(self.host.join(&format!("/api/v2/pastes/{id}"))?)
63            .build()?;
64        req_body(&self.client, r).await
65    }
66
67    /// Creates a paste with the given content and metadata.
68    ///
69    /// # Reference
70    /// Binds to the `POST /api/v2/pastes` endpoint.
71    /// https://github.com/lus/pasty/blob/master/API.md#unsecured-create-a-paste
72    pub async fn create_paste(
73        &self,
74        content: impl Into<String>,
75        metadata: Option<Metadata>,
76    ) -> Result<CreatedPaste> {
77        let r = self
78            .client
79            .post(self.host.join("/api/v2/pastes")?)
80            .json(&CreatePasteRequest {
81                content: content.into(),
82                metadata,
83            })
84            .build()?;
85        req_body(&self.client, r).await
86    }
87
88    /// Consumes the `UnauthenticatedClient` and a given paste modification or
89    /// admin token to perform authenticated requests.
90    pub fn authenticate(self, token: impl Into<String>) -> AuthenticatedClient {
91        AuthenticatedClient {
92            client: self,
93            token: token.into(),
94        }
95    }
96}
97
98#[derive(Clone)]
99pub struct AuthenticatedClient {
100    client: UnauthenticatedClient,
101    token: String,
102}
103
104/// API client to perform authenticated requests to the
105/// pasty API.
106///
107/// This client can be created from an `UnauthenticatedClient` instance.
108///
109/// # Example
110/// ```
111/// # use pasty_rs::client::*;
112/// # fn main() {
113/// let client = UnauthenticatedClient::new("https://pasty.lus.pm").unwrap();
114/// let auth_client = client.authenticate("some-token");
115/// # }
116/// ```
117///
118/// # Reference
119/// Implementation according to the pasty API documentation:
120/// https://github.com/lus/pasty/blob/master/API.md#api
121impl AuthenticatedClient {
122    /// Returns a reference to the inner `UnauthenticatedClient` instance.
123    pub fn inner(&self) -> &UnauthenticatedClient {
124        &self.client
125    }
126
127    /// Updates a given content and metadata by it's ID.
128    ///
129    /// # Reference
130    /// Binds to the `PATCH /api/v2/pastes/{paste_id}` endpoint.
131    /// https://github.com/lus/pasty/blob/master/API.md#paste_specific-update-a-paste
132    pub async fn update_paste(
133        &self,
134        id: &str,
135        content: impl Into<String>,
136        metadata: Option<Metadata>,
137    ) -> Result<()> {
138        let r = self
139            .client
140            .client
141            .patch(self.client.host.join(&format!("/api/v2/pastes/{id}"))?)
142            .json(&CreatePasteRequest {
143                content: content.into(),
144                metadata,
145            })
146            .bearer_auth(&self.token)
147            .build()?;
148        req(&self.client.client, r).await
149    }
150
151    /// Deletes a paste by it's ID.
152    ///
153    /// # Reference
154    /// Binds to the `DELETE /api/v2/pastes/{paste_id}` endpoint.
155    /// https://github.com/lus/pasty/blob/master/API.md#paste_specific-delete-a-paste
156    pub async fn delete_paste(&self, id: &str) -> Result<()> {
157        let r = self
158            .client
159            .client
160            .delete(self.client.host.join(&format!("/api/v2/pastes/{id}"))?)
161            .bearer_auth(&self.token)
162            .build()?;
163        req(&self.client.client, r).await
164    }
165}
166
167async fn req_body<T: DeserializeOwned>(client: &Client, req: Request) -> Result<T> {
168    let res = client
169        .execute(req)
170        .await?
171        .error_for_status()?
172        .json()
173        .await?;
174    Ok(res)
175}
176
177async fn req(client: &Client, req: Request) -> Result<()> {
178    client.execute(req).await?.error_for_status()?;
179    Ok(())
180}