1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
//! An opinionated API wrapper around <https://poe.ninja>, specifically focused on the economy dataset.
//!
//! # Example
//! ```
//! use poe_ninja::*;
//!
//! #[tokio::main]
//! async fn main() {
//!		let client = Client::new("Scourge").unwrap();
//!		let currencies = client.get_currencies().await.unwrap();
//!     let mirror_shard = currencies.into_iter().find(|c| c.name == "Mirror Shard").unwrap();
//!     println!("Mirror Shard value is {} chaos", mirror_shard.chaos_equivalent);
//! }
//! ```

#![allow(clippy::tabs_in_doc_comments)]
use serde::Deserialize;
use reqwest::Error;

mod model;
pub use model::*;

/// The entrypoint for the library; construct a `Client`, then issue queries through it.
///
/// Constructed with [Client::new], which accepts a league as input, e.g. `Client::new("Scourge")`
///
/// Methods are all named for the left-side navigation items on <https://poe.ninja/challenge/currency>
#[derive(Clone)]
pub struct Client {
	http: reqwest::Client,
	base_url: String,
	league: String
}

impl Client {
	pub fn new(league: impl AsRef<str>) -> Result<Self, Error> {
		Ok(Self{
			http: reqwest::Client::builder()
				.gzip(true)
				.build()?,
			base_url: "https://poe.ninja/api".to_string(),
			league: league.as_ref().to_string()
		})
	}

	async fn get<T: for<'de> Deserialize<'de>>(&self, path: &str) -> Result<T, Error> {
		let url = format!("{}/{}", self.base_url, path);
		Ok(self.http.get(&url).send().await?.error_for_status()?.json().await?)
	}

	async fn get_currency_overview(&self, ctype: &str) -> Result<CurrencyResponse, Error> {
		let path = format!("data/CurrencyOverview?league={}&type={}&language=en", self.league, ctype);
		self.get(&path).await
	}

	async fn get_item_overview(&self, itype: &str) -> Result<ItemResponse, Error> {
		let path = format!("data/ItemOverview?league={}&type={}&language=en", self.league, itype);
		self.get(&path).await
	}

	// General {{{
	pub async fn get_currencies(&self) -> Result<Vec<Currency>, Error> {
		Ok(self.get_currency_overview("Currency").await?.lines)
	}

	pub async fn get_fragments(&self) -> Result<Vec<Currency>, Error> {
		Ok(self.get_currency_overview("Fragment").await?.lines)
	}

	pub async fn get_divination_cards(&self) -> Result<Vec<Item>, Error> {
		Ok(self.get_item_overview("DivinationCard").await?.lines)
	}

	pub async fn get_artifacts(&self) -> Result<Vec<Item>, Error> {
		Ok(self.get_item_overview("Artifact").await?.lines)
	}

	pub async fn get_prophecies(&self) -> Result<Vec<Item>, Error> {
		Ok(self.get_item_overview("Prophecy").await?.lines)
	}

	pub async fn get_oils(&self) -> Result<Vec<Item>, Error> {
		Ok(self.get_item_overview("Oil").await?.lines)
	}

	pub async fn get_incubators(&self) -> Result<Vec<Item>, Error> {
		Ok(self.get_item_overview("Incubator").await?.lines)
	}
	// }}}

	// Equipment & Gems {{{
	pub async fn get_unique_weapons(&self) -> Result<Vec<Item>, Error> {
		Ok(self.get_item_overview("UniqueWeapon").await?.lines)
	}

	pub async fn get_unique_armors(&self) -> Result<Vec<Item>, Error> {
		Ok(self.get_item_overview("UniqueArmour").await?.lines)
	}

	pub async fn get_unique_accessories(&self) -> Result<Vec<Item>, Error> {
		Ok(self.get_item_overview("UniqueAccessory").await?.lines)
	}

	pub async fn get_unique_flasks(&self) -> Result<Vec<Item>, Error> {
		Ok(self.get_item_overview("UniqueFlask").await?.lines)
	}

	pub async fn get_unique_jewels(&self) -> Result<Vec<Item>, Error> {
		Ok(self.get_item_overview("UniqueJewel").await?.lines)
	}

	pub async fn get_skill_gems(&self) -> Result<Vec<Item>, Error> {
		Ok(self.get_item_overview("SkillGem").await?.lines)
	}

	pub async fn get_cluster_jewels(&self) -> Result<Vec<Item>, Error> {
		Ok(self.get_item_overview("ClusterJewel").await?.lines)
	}
	// }}}

	// Atlas {{{
	pub async fn get_maps(&self) -> Result<Vec<Item>, Error> {
		Ok(self.get_item_overview("Map").await?.lines)
	}

	pub async fn get_blighted_maps(&self) -> Result<Vec<Item>, Error> {
		Ok(self.get_item_overview("BlightedMap").await?.lines)
	}

	pub async fn get_unique_maps(&self) -> Result<Vec<Item>, Error> {
		Ok(self.get_item_overview("UniqueMap").await?.lines)
	}

	pub async fn get_delirium_orbs(&self) -> Result<Vec<Item>, Error> {
		Ok(self.get_item_overview("DeliriumOrb").await?.lines)
	}

	pub async fn get_invitations(&self) -> Result<Vec<Item>, Error> {
		Ok(self.get_item_overview("Invitation").await?.lines)
	}

	pub async fn get_scarabs(&self) -> Result<Vec<Item>, Error> {
		Ok(self.get_item_overview("Scarab").await?.lines)
	}

	pub async fn get_watchstones(&self) -> Result<Vec<Item>, Error> {
		Ok(self.get_item_overview("Watchstone").await?.lines)
	}
	// }}}

	// Crafting {{{
	pub async fn get_base_types(&self) -> Result<Vec<Item>, Error> {
		Ok(self.get_item_overview("BaseType").await?.lines)
	}

	pub async fn get_fossils(&self) -> Result<Vec<Item>, Error> {
		Ok(self.get_item_overview("Fossil").await?.lines)
	}

	pub async fn get_resonators(&self) -> Result<Vec<Item>, Error> {
		Ok(self.get_item_overview("Resonator").await?.lines)
	}

	pub async fn get_helmet_enchants(&self) -> Result<Vec<Item>, Error> {
		Ok(self.get_item_overview("HelmetEnchant").await?.lines)
	}

	pub async fn get_beasts(&self) -> Result<Vec<Item>, Error> {
		Ok(self.get_item_overview("Beast").await?.lines)
	}

	pub async fn get_essences(&self) -> Result<Vec<Item>, Error> {
		Ok(self.get_item_overview("Essence").await?.lines)
	}

	pub async fn get_vials(&self) -> Result<Vec<Item>, Error> {
		Ok(self.get_item_overview("Vial").await?.lines)
	}
	// }}}
}

#[cfg(test)]
mod test;