Skip to main content

sure_client_rs/
lib.rs

1//! # Sure API Client
2//!
3//! A type-safe Rust client for the Sure API, providing comprehensive access to
4//! financial data including transactions, categories, accounts, chat functionality, and authentication.
5//!
6//! ## Features
7//!
8//! - **Type-safe API**: Compile-time guarantees prevent common errors
9//! - **Comprehensive error handling**: Detailed, actionable error types
10//! - **Full async/await support**: Built on tokio and reqwest
11//! - **Complete API coverage**: Accounts, transactions, categories, chats, authentication, sync, and usage
12//! - **UUID-based identifiers**: Type-safe wrappers for all IDs
13//! - **Pagination support**: Built-in pagination handling for list endpoints
14//!
15//! ## Quick Start
16//!
17//! ### Using API Key Authentication
18//! ```no_run
19//! use sure_client_rs::{SureClient, Auth};
20//!
21//! #[tokio::main]
22//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
23//!     // Create a client with your API key
24//!     let client = SureClient::new(
25//!         reqwest::Client::new(),
26//!         Auth::api_key("your_api_key"),
27//!         "http://localhost:3000".to_string().parse().unwrap(),
28//!     );
29//!
30//!     // List all categories
31//!     let categories = client.get_categories().call().await?;
32//!     for category in categories.items.categories {
33//!         println!("{}: {}", category.name, category.color);
34//!     }
35//!
36//!     // List recent transactions
37//!     let transactions = client.get_transactions()
38//!         .page(1)
39//!         .per_page(25)
40//!         .call()
41//!         .await?;
42//!
43//!     for transaction in transactions.items.transactions {
44//!         println!("{}: {} {}",
45//!             transaction.name,
46//!             transaction.amount,
47//!             transaction.currency
48//!         );
49//!     }
50//!
51//!     Ok(())
52//! }
53//! ```
54//!
55//! ### Using Bearer Token Authentication
56//! ```no_run
57//! use sure_client_rs::{SureClient, Auth};
58//!
59//! #[tokio::main]
60//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
61//!     // Create a client with a JWT bearer token
62//!     let client = SureClient::new(
63//!         reqwest::Client::new(),
64//!         Auth::bearer("your_jwt_token"),
65//!         "http://localhost:3000".to_string().parse().unwrap(),
66//!     );
67//!
68//!     let categories = client.get_categories().call().await?;
69//!     for category in categories.items.categories {
70//!         println!("{}: {}", category.name, category.color);
71//!     }
72//!
73//!     Ok(())
74//! }
75//! ```
76//!
77//! ## Authentication
78//!
79//! The Sure API supports two authentication methods:
80//!
81//! ### API Key Authentication (X-Api-Key header)
82//! ```no_run
83//! use sure_client_rs::{SureClient, Auth};
84//!
85//! let client = SureClient::new(
86//!     reqwest::Client::new(),
87//!     Auth::api_key("your_api_key"),
88//!     "http://localhost:3000".to_string().parse().unwrap(),
89//! );
90//! ```
91//!
92//! ### Bearer Token Authentication (Authorization header)
93//! ```no_run
94//! use sure_client_rs::{SureClient, Auth};
95//!
96//! let client = SureClient::new(
97//!     reqwest::Client::new(),
98//!     Auth::bearer("your_jwt_token"),
99//!     "http://localhost:3000".to_string().parse().unwrap(),
100//! );
101//! ```
102//!
103//! ## Working with Categories
104//!
105//! ```no_run
106//! use sure_client_rs::{SureClient, BearerToken, CategoryId};
107//! use uuid::Uuid;
108//!
109//! # async fn example(client: SureClient) -> Result<(), Box<dyn std::error::Error>> {
110//! // List the first page of categories
111//! let categories = client.get_categories()
112//!     .page(1)
113//!     .per_page(25)
114//!     .call()
115//!     .await?;
116//!
117//! // Get a specific category
118//! let category_id = CategoryId::new(Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap());
119//! let category = client.get_category(&category_id).await?;
120//! # Ok(())
121//! # }
122//! ```
123//!
124//! ## Working with Transactions
125//!
126//! ```no_run
127//! use sure_client_rs::{SureClient, BearerToken, AccountId};
128//! use chrono::{DateTime, TimeZone, Utc};
129//! use rust_decimal::Decimal;
130//! use uuid::Uuid;
131//!
132//! # async fn example(client: SureClient) -> Result<(), Box<dyn std::error::Error>> {
133//! // Create a transaction using the builder pattern
134//! let transaction = client.create_transaction()
135//!     .account_id(AccountId::new(Uuid::new_v4()))
136//!     .date(Utc.with_ymd_and_hms(2024, 1, 15, 12, 0, 0).unwrap())
137//!     .amount(Decimal::new(4250, 2)) // $42.50
138//!     .name("Grocery Store".to_string())
139//!     .currency(iso_currency::Currency::USD)
140//!     .call()
141//!     .await?;
142//!
143//! // Update a transaction
144//! let updated = client.update_transaction()
145//!     .id(&transaction.id)
146//!     .notes("Updated notes".to_string())
147//!     .call()
148//!     .await?;
149//!
150//! // Delete a transaction
151//! let response = client.delete_transaction(&transaction.id).await?;
152//! # Ok(())
153//! # }
154//! ```
155//!
156//! ## Error Handling
157//!
158//! The client uses a comprehensive error type that covers both API-level and
159//! client-level errors:
160//!
161//! ```no_run
162//! use sure_client_rs::{SureClient, ApiError};
163//!
164//! # async fn example(client: SureClient) -> Result<(), Box<dyn std::error::Error>> {
165//! match client.get_categories().call().await {
166//!     Ok(categories) => {
167//!         // Handle success
168//!     }
169//!     Err(ApiError::Unauthorized { message }) => {
170//!         // Handle authentication error
171//!     }
172//!     Err(ApiError::NotFound { message }) => {
173//!         // Handle not found error
174//!     }
175//!     Err(ApiError::RateLimited { message }) => {
176//!         // Handle rate limiting
177//!     }
178//!     Err(e) => {
179//!         // Handle other errors
180//!     }
181//! }
182//! # Ok(())
183//! # }
184//! ```
185//!
186//! ## Development and Testing
187//!
188//! For local development, you can configure the client to use a different base URL:
189//!
190//! ```no_run
191//! use sure_client_rs::{SureClient, BearerToken};
192//!
193//! let client = SureClient::new(
194//!     reqwest::Client::new(),
195//!     BearerToken::new("your_api_key"),
196//!     "http://localhost:3000".to_string().parse().unwrap(),
197//! );
198//! ```
199
200// Module declarations
201mod client;
202mod error;
203pub mod models;
204pub(crate) mod serde;
205mod types;
206
207// Public re-exports
208pub use client::SureClient;
209pub use error::{ApiError, ApiResult};
210pub use types::{
211    AccountId, ApiKey, Auth, BearerToken, CategoryId, MerchantId, TagId, TransactionId, ValuationId,
212};