poe_ninja/
lib.rs

1//! An opinionated API wrapper around <https://poe.ninja>, specifically focused on the economy dataset.
2//!
3//! # Example
4//! ```
5//! use poe_ninja::*;
6//!
7//! #[tokio::main]
8//! async fn main() {
9//!		let client = Client::new("Scourge").unwrap();
10//!		let currencies = client.get_currencies().await.unwrap();
11//!     let mirror_shard = currencies.into_iter().find(|c| c.name == "Mirror Shard").unwrap();
12//!     println!("Mirror Shard value is {} chaos", mirror_shard.chaos_equivalent);
13//! }
14//! ```
15
16#![allow(clippy::tabs_in_doc_comments)]
17use serde::Deserialize;
18use reqwest::Error;
19
20mod model;
21pub use model::*;
22
23/// The entrypoint for the library; construct a `Client`, then issue queries through it.
24///
25/// Constructed with [Client::new], which accepts a league as input, e.g. `Client::new("Scourge")`
26///
27/// Methods are all named for the left-side navigation items on <https://poe.ninja/challenge/currency>
28#[derive(Clone)]
29pub struct Client {
30	http: reqwest::Client,
31	base_url: String,
32	league: String
33}
34
35impl Client {
36	pub fn new(league: impl AsRef<str>) -> Result<Self, Error> {
37		Ok(Self{
38			http: reqwest::Client::builder()
39				.gzip(true)
40				.build()?,
41			base_url: "https://poe.ninja/api".to_string(),
42			league: league.as_ref().to_string()
43		})
44	}
45
46	async fn get<T: for<'de> Deserialize<'de>>(&self, path: &str) -> Result<T, Error> {
47		let url = format!("{}/{}", self.base_url, path);
48		Ok(self.http.get(&url).send().await?.error_for_status()?.json().await?)
49	}
50
51	async fn get_currency_overview(&self, ctype: &str) -> Result<CurrencyResponse, Error> {
52		let path = format!("data/CurrencyOverview?league={}&type={}&language=en", self.league, ctype);
53		self.get(&path).await
54	}
55
56	async fn get_item_overview(&self, itype: &str) -> Result<ItemResponse, Error> {
57		let path = format!("data/ItemOverview?league={}&type={}&language=en", self.league, itype);
58		self.get(&path).await
59	}
60
61	// General {{{
62	pub async fn get_currencies(&self) -> Result<Vec<Currency>, Error> {
63		Ok(self.get_currency_overview("Currency").await?.lines)
64	}
65
66	pub async fn get_fragments(&self) -> Result<Vec<Currency>, Error> {
67		Ok(self.get_currency_overview("Fragment").await?.lines)
68	}
69
70	pub async fn get_divination_cards(&self) -> Result<Vec<Item>, Error> {
71		Ok(self.get_item_overview("DivinationCard").await?.lines)
72	}
73
74	pub async fn get_artifacts(&self) -> Result<Vec<Item>, Error> {
75		Ok(self.get_item_overview("Artifact").await?.lines)
76	}
77
78	pub async fn get_prophecies(&self) -> Result<Vec<Item>, Error> {
79		Ok(self.get_item_overview("Prophecy").await?.lines)
80	}
81
82	pub async fn get_oils(&self) -> Result<Vec<Item>, Error> {
83		Ok(self.get_item_overview("Oil").await?.lines)
84	}
85
86	pub async fn get_incubators(&self) -> Result<Vec<Item>, Error> {
87		Ok(self.get_item_overview("Incubator").await?.lines)
88	}
89	// }}}
90
91	// Equipment & Gems {{{
92	pub async fn get_unique_weapons(&self) -> Result<Vec<Item>, Error> {
93		Ok(self.get_item_overview("UniqueWeapon").await?.lines)
94	}
95
96	pub async fn get_unique_armors(&self) -> Result<Vec<Item>, Error> {
97		Ok(self.get_item_overview("UniqueArmour").await?.lines)
98	}
99
100	pub async fn get_unique_accessories(&self) -> Result<Vec<Item>, Error> {
101		Ok(self.get_item_overview("UniqueAccessory").await?.lines)
102	}
103
104	pub async fn get_unique_flasks(&self) -> Result<Vec<Item>, Error> {
105		Ok(self.get_item_overview("UniqueFlask").await?.lines)
106	}
107
108	pub async fn get_unique_jewels(&self) -> Result<Vec<Item>, Error> {
109		Ok(self.get_item_overview("UniqueJewel").await?.lines)
110	}
111
112	pub async fn get_skill_gems(&self) -> Result<Vec<Item>, Error> {
113		Ok(self.get_item_overview("SkillGem").await?.lines)
114	}
115
116	pub async fn get_cluster_jewels(&self) -> Result<Vec<Item>, Error> {
117		Ok(self.get_item_overview("ClusterJewel").await?.lines)
118	}
119	// }}}
120
121	// Atlas {{{
122	pub async fn get_maps(&self) -> Result<Vec<Item>, Error> {
123		Ok(self.get_item_overview("Map").await?.lines)
124	}
125
126	pub async fn get_blighted_maps(&self) -> Result<Vec<Item>, Error> {
127		Ok(self.get_item_overview("BlightedMap").await?.lines)
128	}
129
130	pub async fn get_unique_maps(&self) -> Result<Vec<Item>, Error> {
131		Ok(self.get_item_overview("UniqueMap").await?.lines)
132	}
133
134	pub async fn get_delirium_orbs(&self) -> Result<Vec<Item>, Error> {
135		Ok(self.get_item_overview("DeliriumOrb").await?.lines)
136	}
137
138	pub async fn get_invitations(&self) -> Result<Vec<Item>, Error> {
139		Ok(self.get_item_overview("Invitation").await?.lines)
140	}
141
142	pub async fn get_scarabs(&self) -> Result<Vec<Item>, Error> {
143		Ok(self.get_item_overview("Scarab").await?.lines)
144	}
145
146	pub async fn get_watchstones(&self) -> Result<Vec<Item>, Error> {
147		Ok(self.get_item_overview("Watchstone").await?.lines)
148	}
149	// }}}
150
151	// Crafting {{{
152	pub async fn get_base_types(&self) -> Result<Vec<Item>, Error> {
153		Ok(self.get_item_overview("BaseType").await?.lines)
154	}
155
156	pub async fn get_fossils(&self) -> Result<Vec<Item>, Error> {
157		Ok(self.get_item_overview("Fossil").await?.lines)
158	}
159
160	pub async fn get_resonators(&self) -> Result<Vec<Item>, Error> {
161		Ok(self.get_item_overview("Resonator").await?.lines)
162	}
163
164	pub async fn get_helmet_enchants(&self) -> Result<Vec<Item>, Error> {
165		Ok(self.get_item_overview("HelmetEnchant").await?.lines)
166	}
167
168	pub async fn get_beasts(&self) -> Result<Vec<Item>, Error> {
169		Ok(self.get_item_overview("Beast").await?.lines)
170	}
171
172	pub async fn get_essences(&self) -> Result<Vec<Item>, Error> {
173		Ok(self.get_item_overview("Essence").await?.lines)
174	}
175
176	pub async fn get_vials(&self) -> Result<Vec<Item>, Error> {
177		Ok(self.get_item_overview("Vial").await?.lines)
178	}
179	// }}}
180}
181
182#[cfg(test)]
183mod test;
184