ezlime_rs/lib.rs
1//! # ezlime-rs
2//!
3//! A Rust client library for the [ezli.me](https://ezli.me) URL shortener API.
4//!
5//! This crate provides a simple interface to create shortened URLs using the ezli.me service.
6//! To use this API, you'll need an API key from ezli.me.
7//!
8//! ## Getting an API Key
9//!
10//! If you're interested in using ezli.me for your own project via the API, please join the
11//! [Discord server](https://discord.gg/MHzmYHnnsE) to request an API key.
12//!
13//! ## Example
14//!
15//! ```rust,no_run
16//! # async fn example() -> Result<(), ezlime_rs::EzlimeApiError> {
17//! use ezlime_rs::EzlimeApi;
18//!
19//! let api = EzlimeApi::new("your-api-key-here".to_string());
20//! let original_url = "https://example.com/very/long/url";
21//!
22//! let shortened = api.create_short_url(original_url).await?;
23//! println!("Shortened URL: {}", shortened);
24//! # Ok(())
25//! # }
26//! ```
27//!
28
29use reqwest::Url;
30use serde::{Deserialize, Serialize};
31use thiserror::Error;
32
33/// Request payload for creating a shortened URL.
34#[derive(Debug, Serialize, Deserialize)]
35pub struct CreateLinkRequest {
36 /// The original URL to be shortened.
37 pub url: String,
38}
39
40/// Response from the ezli.me API after creating a shortened URL.
41#[derive(Debug, Serialize, Deserialize)]
42pub struct CreatedLinkResponse {
43 /// The unique identifier for the shortened link.
44 pub id: String,
45 /// The complete shortened URL.
46 pub shortened_url: String,
47 /// The original URL that was shortened.
48 pub original_url: String,
49}
50
51impl CreatedLinkResponse {
52 /// Creates a new `CreatedLinkResponse` with the given parameters.
53 ///
54 /// # Arguments
55 ///
56 /// * `id` - The unique identifier for the shortened link
57 /// * `prefix` - The URL prefix (e.g., `https://ezli.me`)
58 /// * `original_url` - The original URL that was shortened
59 pub fn new(id: String, prefix: &str, original_url: String) -> Self {
60 let shortened_url = format!("{}/{}", prefix, id);
61 Self {
62 id,
63 shortened_url,
64 original_url,
65 }
66 }
67}
68
69/// A client for interacting with the ezli.me API.
70///
71/// This struct provides a convenient interface for creating shortened URLs
72/// using the ezli.me service. It manages the API endpoint, authentication,
73/// and HTTP client internally.
74///
75/// # Example
76///
77/// ```rust,no_run
78/// # async fn example() -> Result<(), ezlime_rs::EzlimeApiError> {
79/// use ezlime_rs::EzlimeApi;
80///
81/// let api = EzlimeApi::new("your-api-key".to_string());
82/// let shortened = api.create_short_url("https://example.com").await?;
83/// println!("Shortened URL: {}", shortened);
84/// # Ok(())
85/// # }
86/// ```
87#[derive(Clone)]
88pub struct EzlimeApi {
89 url: String,
90 key: String,
91 client: reqwest::Client,
92}
93
94/// Errors that can occur when interacting with the ezli.me API.
95#[derive(Debug, Error)]
96pub enum EzlimeApiError {
97 /// An error occurred during API configuration (e.g., invalid URL parsing).
98 #[error("Configuration error: {0}")]
99 ConfigurationError(String),
100 /// An error occurred while sending the HTTP request or receiving the response.
101 #[error("Request error: {0}")]
102 RequestError(String),
103 /// An error occurred while deserializing the API response.
104 #[error("Deserialization error: {0}")]
105 DeserializationError(String),
106}
107
108impl EzlimeApi {
109 /// Creates a new `EzlimeApi` client with the default ezli.me endpoint.
110 ///
111 /// # Arguments
112 ///
113 /// * `key` - Your ezli.me API key for authentication
114 ///
115 /// # Example
116 ///
117 /// ```rust
118 /// use ezlime_rs::EzlimeApi;
119 ///
120 /// let api = EzlimeApi::new("your-api-key".to_string());
121 /// ```
122 pub fn new(key: String) -> Self {
123 Self {
124 url: String::from("https://ezli.me"),
125 key,
126 client: reqwest::Client::new(),
127 }
128 }
129
130 /// Sets a custom API endpoint URL.
131 ///
132 /// By default, the client uses `https://ezli.me`. Use this method to
133 /// configure a different endpoint, such as for testing or self-hosted instances.
134 ///
135 /// # Arguments
136 ///
137 /// * `url` - The base URL of the ezli.me API endpoint
138 ///
139 /// # Example
140 ///
141 /// ```rust
142 /// use ezlime_rs::EzlimeApi;
143 ///
144 /// let api = EzlimeApi::new("your-api-key".to_string())
145 /// .with_url("https://custom.ezli.me");
146 /// ```
147 pub fn with_url(mut self, url: &str) -> Self {
148 self.url = url.into();
149 self
150 }
151
152 /// Creates a shortened URL using the ezli.me API.
153 ///
154 /// This method sends a request to the ezli.me API to create a shortened version
155 /// of the provided URL.
156 ///
157 /// # Arguments
158 ///
159 /// * `original_link` - The URL to be shortened
160 ///
161 /// # Returns
162 ///
163 /// Returns `Ok(String)` containing the shortened URL on success, or an
164 /// `EzlimeApiError` if the request fails.
165 ///
166 /// # Errors
167 ///
168 /// This function will return an error if:
169 /// - The API endpoint URL is invalid (`ConfigurationError`)
170 /// - The HTTP request fails (`RequestError`)
171 /// - The response cannot be deserialized (`DeserializationError`)
172 ///
173 /// # Example
174 ///
175 /// ```rust,no_run
176 /// # async fn example() -> Result<(), ezlime_rs::EzlimeApiError> {
177 /// use ezlime_rs::EzlimeApi;
178 ///
179 /// let api = EzlimeApi::new("your-api-key".to_string());
180 /// let shortened = api.create_short_url("https://example.com/long/url").await?;
181 /// println!("Shortened URL: {}", shortened);
182 /// # Ok(())
183 /// # }
184 /// ```
185 pub async fn create_short_url(&self, original_link: &str) -> Result<String, EzlimeApiError> {
186 let url: Url = Url::parse(&format!("{}/link/create", self.url))
187 .map_err(|e| EzlimeApiError::ConfigurationError(e.to_string()))?;
188
189 let resp = self
190 .client
191 .post(url)
192 .header("Authorization", self.key.clone())
193 .json(&CreateLinkRequest {
194 url: original_link.to_string(),
195 })
196 .send()
197 .await
198 .map_err(|e| EzlimeApiError::RequestError(e.to_string()))?
199 .json::<CreatedLinkResponse>()
200 .await
201 .map_err(|e| EzlimeApiError::DeserializationError(e.to_string()))?;
202
203 Ok(resp.shortened_url)
204 }
205}