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}