currency_prices/
lib.rs

1mod api_client;
2pub mod models;
3
4/// A small library for fetching cryptocurrency prices using the CoinMarketCap API.
5///
6/// The library includes a `CurrencyPrices` struct that requires a `CoinMarketCapConfig`.
7/// You can obtain the development configuration by calling `CoinMarketCapConfig::get_sandbox_config()`,
8/// and for the production configuration, use `CoinMarketCapConfig::get_production_config()`.
9///
10/// # Example
11///
12/// ```rust
13/// use currency_prices::{
14///     models::{CoinMarketCapConfig, Currency},
15///     CurrencyPrices,
16/// };
17///
18/// let config = CoinMarketCapConfig::get_sandbox_config();
19/// let prices = CurrencyPrices::new(config);
20/// ```
21///
22/// The library exposes a struct containing a function for fetching cryptocurrency prices.
23/// You need to pass the `from_currency` and `to_currency` as arguments.
24///
25/// The `get_price` method is asynchronous, returning a `CurrencyPrice` object.
26///
27/// # Example
28///
29/// ```rust
30/// use currency_prices::{
31///     models::{CoinMarketCapConfig, Currency},
32///     CurrencyPrices,
33/// };
34///
35///
36/// #[tokio::main]
37/// async fn main() {
38///     let api_key = String::from("my_api_key");
39///     let config = CoinMarketCapConfig::get_production_config(api_key);
40///     let prices = CurrencyPrices::new(config);
41///     
42///     let from_currency = Currency {
43///       name: String::from("HDN"),
44///     };
45///     let to_currency = Currency {
46///        name: String::from("USD"),
47///      };
48///     
49///     let price = prices.get_price(from_currency, to_currency).await;
50///     
51///     match price {
52///         Ok(currency_price) => {
53///             println!("Price from {} to {} is: {}", currency_price.from_currency.name, currency_price.to_currency.name, currency_price.price);
54///         }
55///         Err(err) => {
56///             eprintln!("Error fetching price: {:#?}", err);
57///         }
58///     }
59/// }
60/// ```
61///
62/// ## Struct: CurrencyPrice
63/// A structure representing cryptocurrency price information.
64///
65/// ```rust
66/// use currency_prices::{
67///     models::{CoinMarketCapConfig, Currency},
68///     CurrencyPrices,
69/// };
70/// use rust_decimal::prelude::*;
71///
72/// pub struct CurrencyPrice {
73///     pub from_currency: Currency,
74///     pub to_currency: Currency,
75///     pub price: Decimal,
76/// }
77/// ```
78use models::{CoinMarketCapConfig, Currency, CurrencyPrice, CurrencyPricesError};
79
80pub struct CurrencyPrices {
81    coin_market_cap_config: CoinMarketCapConfig,
82}
83
84impl CurrencyPrices {
85    pub fn new(coin_market_cap_config: CoinMarketCapConfig) -> CurrencyPrices {
86        Self {
87            coin_market_cap_config,
88        }
89    }
90
91    pub async fn get_price(
92        &self,
93        from_currency: Currency,
94        to_currency: Currency,
95    ) -> Result<CurrencyPrice, CurrencyPricesError> {
96        let api_response =
97            api_client::send_request(&from_currency, &to_currency, &self.coin_market_cap_config)
98                .await;
99
100        match api_response {
101            Ok(api_response) => {
102                let currency_price_maybe =
103                    api_response
104                        .data
105                        .get(&to_currency.name)
106                        .and_then(|data_item| {
107                            data_item
108                                .quote
109                                .get(&from_currency.name)
110                                .map(|quote| quote.price)
111                        });
112
113                currency_price_maybe
114                    .map(|price| {
115                        Ok(CurrencyPrice {
116                            from_currency,
117                            to_currency,
118                            price,
119                        })
120                    })
121                    .unwrap_or(Err(CurrencyPricesError::Custom(String::from(
122                        "The response didn't have the requested currency",
123                    ))))
124            }
125
126            Err(reqwuest_error) => Err(CurrencyPricesError::Request(reqwuest_error)),
127        }
128    }
129}