api.rs (1427B)
1 use crate::error::{AppError, Result}; 2 use crate::league::League; 3 use crate::models::{MatchesResponse, StandingsResponse}; 4 5 pub struct ApiClient { 6 client: reqwest::Client, 7 api_token: String, 8 } 9 10 impl ApiClient { 11 pub fn new(api_token: String) -> Self { 12 Self { 13 client: reqwest::Client::new(), 14 api_token, 15 } 16 } 17 18 async fn fetch<T: for<'de> serde::Deserialize<'de>>(&self, path: &str) -> Result<T> { 19 let url = format!("https://api.football-data.org/v4/{path}"); 20 21 let response = self 22 .client 23 .get(&url) 24 .header("X-Auth-Token", &self.api_token) 25 .send() 26 .await?; 27 28 if !response.status().is_success() { 29 return Err(AppError::ApiStatus(response.status().as_u16())); 30 } 31 32 Ok(response.json::<T>().await?) 33 } 34 35 pub async fn fetch_matches(&self, league: League) -> Result<MatchesResponse> { 36 self.fetch(&format!("competitions/{}/matches", league.code())) 37 .await 38 } 39 40 pub async fn fetch_standings(&self, league: League) -> Result<StandingsResponse> { 41 self.fetch(&format!("competitions/{}/standings", league.code())) 42 .await 43 } 44 45 /// Fetch all matches across every available competition (`GET /v4/matches`). 46 pub async fn fetch_all_matches(&self) -> Result<MatchesResponse> { 47 self.fetch("matches").await 48 } 49 }