Skip to content

Commit

Permalink
refactor: move error message detection to api.get_json
Browse files Browse the repository at this point in the history
Signed-off-by: Saurav Sharma <appdroiddeveloper@gmail.com>
  • Loading branch information
iamsauravsharma committed Aug 26, 2024
1 parent 8c78f46 commit 97d8b8b
Show file tree
Hide file tree
Showing 14 changed files with 49 additions and 123 deletions.
3 changes: 1 addition & 2 deletions README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,13 @@ Rust Client library built for accessing [Alphavantage][alphavantage_link] API.
### Project Functionality

- [x] Crypto Currency
- [x] Custom function
- [x] Custom function and parameters
- [x] Earning
- [x] Economic Indicator
- [x] Exchange Rate
- [x] Forex
- [x] Quote Endpoint
- [x] Search Endpoint
- [x] Sector Performances
- [x] Stock Time Series
- [x] Technical Indicators

Expand Down
6 changes: 4 additions & 2 deletions src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::crypto::{CryptoBuilder, CryptoFunction};
use crate::custom::CustomBuilder;
use crate::earning::EarningBuilder;
use crate::economic_indicator::EconomicIndicatorBuilder;
use crate::error::{Error, Result};
use crate::error::{Error, ErrorHolder, Result};
use crate::exchange::ExchangeBuilder;
use crate::forex::{ForexBuilder, ForexFunction};
use crate::quote::QuoteBuilder;
Expand Down Expand Up @@ -107,7 +107,9 @@ impl ApiClient {
.await
}
}?;
serde_json::from_str(&string_output).map_err(|_| Error::DecodeJsonToStruct)
let with_error: ErrorHolder<T> =
serde_json::from_str(&string_output).map_err(|_| Error::DecodeJsonToStruct)?;
with_error.handle_common_error()
}

/// Crypto method for calling cryptography function with help of
Expand Down
9 changes: 5 additions & 4 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ use crate::error::{Error, Result};
#[async_trait]
/// Trait which can be implemented for all common library client for getting
/// output from server
/// reqwest is client which is supported with feature flag. If
/// you prefer alternate http client you can add support by implementing
/// `HttpClient` trait for client.
/// Some example of other client which can be used are surf and isahc client
///
/// reqwest client is supported with feature flag. If you prefer alternate http
/// client you can add support by implementing `HttpClient` trait for client.
/// Some example of other client which can be used are surf and isahc client or
/// other reqwest version
pub trait HttpClient {
/// AlphaVantage provider output function which provides one field path
/// where get GET request needs to be performed
Expand Down
9 changes: 1 addition & 8 deletions src/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use serde::Deserialize;

use crate::api::ApiClient;
use crate::deserialize::from_str;
use crate::error::{detect_common_helper_error, Error, Result};
use crate::error::{Error, Result};
use crate::vec_trait::FindData;

/// Store Meta Data Information
Expand Down Expand Up @@ -245,12 +245,6 @@ struct DataHelper {
/// Struct to help out for creation of struct Crypto
#[derive(Deserialize)]
pub(crate) struct CryptoHelper {
#[serde(rename = "Information")]
information: Option<String>,
#[serde(rename = "Error Message")]
error_message: Option<String>,
#[serde(rename = "Note")]
note: Option<String>,
#[serde(rename = "Meta Data")]
meta_data: Option<MetaData>,
#[serde(flatten)]
Expand All @@ -260,7 +254,6 @@ pub(crate) struct CryptoHelper {
impl CryptoHelper {
/// Function which convert `CryptoHelper` to `Crypto`
fn convert(self) -> Result<Crypto> {
detect_common_helper_error(self.information, self.error_message, self.note)?;
if self.meta_data.is_none() || self.data.is_none() {
return Err(Error::EmptyResponse);
}
Expand Down
34 changes: 2 additions & 32 deletions src/custom.rs
Original file line number Diff line number Diff line change
@@ -1,36 +1,7 @@
use std::collections::HashMap;

use serde::de::value::MapDeserializer;
use serde::de::DeserializeOwned;
use serde::Deserialize;
use serde_json::Value;

use crate::api::ApiClient;
use crate::error::{detect_common_helper_error, Error, Result};
/// struct used for helping creation of custom url
#[derive(Debug, Deserialize)]
pub(crate) struct CustomHelper {
#[serde(rename = "Error Message")]
error_message: Option<String>,
#[serde(rename = "Information")]
information: Option<String>,
#[serde(rename = "Note")]
note: Option<String>,
#[serde(flatten)]
extras: HashMap<String, Value>,
}

impl CustomHelper {
fn convert<T>(self) -> Result<T>
where
T: DeserializeOwned,
{
detect_common_helper_error(self.information, self.error_message, self.note)?;
let data = self.extras;
T::deserialize(MapDeserializer::new(data.into_iter()))
.map_err(|_| Error::DecodeJsonToStruct)
}
}
use crate::error::Result;

/// Builder to create new Custom Struct
pub struct CustomBuilder<'a> {
Expand Down Expand Up @@ -75,7 +46,6 @@ impl<'a> CustomBuilder<'a> {
T: DeserializeOwned,
{
let url = self.create_url();
let custom_helper: CustomHelper = self.api_client.get_json(&url).await?;
custom_helper.convert()
self.api_client.get_json(&url).await
}
}
9 changes: 1 addition & 8 deletions src/earning.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use serde::Deserialize;

use crate::api::ApiClient;
use crate::deserialize::{from_none_str, from_str};
use crate::error::{detect_common_helper_error, Error, Result};
use crate::error::{Error, Result};

/// Struct to store information of annual earning
#[derive(Debug, Deserialize, Clone, Default)]
Expand Down Expand Up @@ -132,12 +132,6 @@ impl Earning {
/// Struct used for creating earning
#[derive(Debug, Deserialize)]
pub(crate) struct EarningHelper {
#[serde(rename = "Information")]
information: Option<String>,
#[serde(rename = "Error Message")]
error_message: Option<String>,
#[serde(rename = "Note")]
note: Option<String>,
#[serde(rename = "symbol")]
symbol: Option<String>,
#[serde(rename = "annualEarnings")]
Expand All @@ -150,7 +144,6 @@ impl EarningHelper {
/// `Earning`
fn convert(self) -> Result<Earning> {
let mut earning = Earning::default();
detect_common_helper_error(self.information, self.error_message, self.note)?;
if self.symbol.is_none()
|| self.annual_earning.is_none()
|| self.quarterly_earning.is_none()
Expand Down
9 changes: 1 addition & 8 deletions src/economic_indicator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use serde::Deserialize;

use crate::api::ApiClient;
use crate::deserialize::from_str;
use crate::error::{detect_common_helper_error, Error, Result};
use crate::error::{Error, Result};
use crate::vec_trait::FindData;

/// Struct for storing a data values
Expand Down Expand Up @@ -112,12 +112,6 @@ impl EconomicIndicator {
/// Struct for helping indicator struct
#[derive(Deserialize)]
pub(crate) struct EconomicIndicatorHelper {
#[serde(rename = "Error Message")]
error_message: Option<String>,
#[serde(rename = "Information")]
information: Option<String>,
#[serde(rename = "Note")]
note: Option<String>,
name: Option<String>,
interval: Option<String>,
unit: Option<String>,
Expand All @@ -126,7 +120,6 @@ pub(crate) struct EconomicIndicatorHelper {

impl EconomicIndicatorHelper {
fn convert(self) -> Result<EconomicIndicator> {
detect_common_helper_error(self.information, self.error_message, self.note)?;
if self.name.is_none()
|| self.interval.is_none()
|| self.unit.is_none()
Expand Down
39 changes: 28 additions & 11 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//! Module which contains all types of error for alpha vantage crates
use serde::de::DeserializeOwned;
use thiserror::Error;

/// Result type for alpha vantage crate
Expand Down Expand Up @@ -49,19 +50,35 @@ pub enum Error {
CreateUrl,
}

pub(crate) fn detect_common_helper_error(
#[derive(serde::Deserialize)]
pub(crate) struct ErrorHolder<T> {
#[serde(rename = "Information")]
information: Option<String>,
#[serde(rename = "Error Message")]
error_message: Option<String>,
#[serde(rename = "Note")]
note: Option<String>,
) -> Result<()> {
if let Some(information) = information {
return Err(Error::AlphaVantageInformation(information));
}
if let Some(error_message) = error_message {
return Err(Error::AlphaVantageErrorMessage(error_message));
}
if let Some(note) = note {
return Err(Error::AlphaVantageNote(note));
#[serde(flatten)]
data: Option<T>,
}

impl<T> ErrorHolder<T>
where
T: DeserializeOwned,
{
pub(crate) fn handle_common_error(self) -> Result<T> {
if let Some(information) = self.information {
return Err(Error::AlphaVantageInformation(information));
}
if let Some(error_message) = self.error_message {
return Err(Error::AlphaVantageErrorMessage(error_message));
}
if let Some(note) = self.note {
return Err(Error::AlphaVantageNote(note));
}
let Some(data) = self.data else {
return Err(Error::AlphaVantageInvalidData);
};
Ok(data)
}
Ok(())
}
9 changes: 1 addition & 8 deletions src/exchange.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use serde::Deserialize;

use crate::api::ApiClient;
use crate::deserialize::from_str;
use crate::error::{detect_common_helper_error, Error, Result};
use crate::error::{Error, Result};

/// Struct used for exchanging currency
#[derive(Default)]
Expand Down Expand Up @@ -142,20 +142,13 @@ impl Exchange {
/// Struct used for helping creation of Exchange
#[derive(Debug, Deserialize)]
pub(crate) struct ExchangeHelper {
#[serde(rename = "Error Message")]
error_message: Option<String>,
#[serde(rename = "Information")]
information: Option<String>,
#[serde(rename = "Note")]
note: Option<String>,
#[serde(rename = "Realtime Currency Exchange Rate")]
real_time: Option<RealtimeExchangeRate>,
}

impl ExchangeHelper {
fn convert(self) -> Result<Exchange> {
let mut exchange = Exchange::default();
detect_common_helper_error(self.information, self.error_message, self.note)?;
if self.real_time.is_none() {
return Err(Error::EmptyResponse);
}
Expand Down
10 changes: 1 addition & 9 deletions src/forex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use serde::Deserialize;

use crate::api::{ApiClient, OutputSize, TimeSeriesInterval};
use crate::deserialize::from_str;
use crate::error::{detect_common_helper_error, Error, Result};
use crate::error::{Error, Result};
use crate::vec_trait::FindData;

/// Struct used to store metadata value
Expand Down Expand Up @@ -247,12 +247,6 @@ struct DataHelper {
/// struct which helps for collecting forex data from website
#[derive(Debug, Deserialize)]
pub(crate) struct ForexHelper {
#[serde(rename = "Error Message")]
error_message: Option<String>,
#[serde(rename = "Information")]
information: Option<String>,
#[serde(rename = "Note")]
note: Option<String>,
#[serde(rename = "Meta Data")]
meta_data: Option<HashMap<String, String>>,
#[serde(flatten)]
Expand All @@ -262,8 +256,6 @@ pub(crate) struct ForexHelper {
impl ForexHelper {
/// convert `ForexHelper` to `Forex`
fn convert(self) -> Result<Forex> {
detect_common_helper_error(self.information, self.error_message, self.note)?;

if self.meta_data.is_none() || self.forex.is_none() {
return Err(Error::EmptyResponse);
}
Expand Down
9 changes: 1 addition & 8 deletions src/quote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use serde::Deserialize;

use crate::api::ApiClient;
use crate::deserialize::{from_str, percent_f64};
use crate::error::{detect_common_helper_error, Error, Result};
use crate::error::{Error, Result};

/// Struct storing Global Quote Value
#[derive(Debug, Deserialize, Clone, Default)]
Expand Down Expand Up @@ -120,20 +120,13 @@ impl Quote {
/// Struct for helping creation of Quote
#[derive(Debug, Deserialize)]
pub(crate) struct QuoteHelper {
#[serde(rename = "Error Message")]
error_message: Option<String>,
#[serde(rename = "Information")]
information: Option<String>,
#[serde(rename = "Note")]
note: Option<String>,
#[serde(rename = "Global Quote")]
global_quote: Option<GlobalQuote>,
}

impl QuoteHelper {
fn convert(self) -> Result<Quote> {
let mut quote = Quote::default();
detect_common_helper_error(self.information, self.error_message, self.note)?;
if self.global_quote.is_none() {
return Err(Error::EmptyResponse);
}
Expand Down
7 changes: 1 addition & 6 deletions src/search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use serde::Deserialize;

use crate::api::ApiClient;
use crate::deserialize::from_str;
use crate::error::{detect_common_helper_error, Error, Result};
use crate::error::{Error, Result};

/// Struct which stores matches data for search keyword
#[derive(Debug, Clone, Deserialize, Default)]
Expand Down Expand Up @@ -184,18 +184,13 @@ impl Search {
/// struct for helping creation of search struct
#[derive(Debug, Deserialize)]
pub(crate) struct SearchHelper {
#[serde(rename = "Information")]
information: Option<String>,
#[serde(rename = "Note")]
note: Option<String>,
#[serde(rename = "bestMatches")]
matches: Option<Vec<Match>>,
}

impl SearchHelper {
fn convert(self) -> Result<Search> {
let mut search = Search::default();
detect_common_helper_error(self.information, None, self.note)?;
if self.matches.is_none() {
return Err(Error::EmptyResponse);
}
Expand Down
10 changes: 1 addition & 9 deletions src/stock_time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use serde::Deserialize;

use crate::api::{ApiClient, OutputSize, TimeSeriesInterval};
use crate::deserialize::from_str;
use crate::error::{detect_common_helper_error, Error, Result};
use crate::error::{Error, Result};
use crate::vec_trait::FindData;

/// Struct for storing Meta Data value
Expand Down Expand Up @@ -280,12 +280,6 @@ struct AdjustedHelper {
/// helper struct for `TimeSeries` which deserialize JSON
#[derive(Deserialize)]
pub(crate) struct TimeSeriesHelper {
#[serde(rename = "Error Message")]
error_message: Option<String>,
#[serde(rename = "Information")]
information: Option<String>,
#[serde(rename = "Note")]
note: Option<String>,
#[serde(rename = "Meta Data")]
meta_data: Option<HashMap<String, String>>,
#[serde(flatten)]
Expand All @@ -297,8 +291,6 @@ pub(crate) struct TimeSeriesHelper {
impl TimeSeriesHelper {
/// Convert `TimeSeriesHelper` to `TimeSeries`
fn convert(self) -> Result<TimeSeries> {
detect_common_helper_error(self.information, self.error_message, self.note)?;

if self.meta_data.is_none()
|| (self.time_series.is_none() && self.adjusted_series.is_none())
{
Expand Down
Loading

0 comments on commit 97d8b8b

Please sign in to comment.