the-odds-api 0.1.1

A Rust SDK for The Odds API - sports odds and scores
Documentation
//! Data models for API responses.

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};

/// A sport available in the API.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Sport {
    /// Unique identifier for the sport (e.g., "americanfootball_nfl").
    pub key: String,
    /// Group/category the sport belongs to (e.g., "American Football").
    pub group: String,
    /// Human-readable title (e.g., "NFL").
    pub title: String,
    /// Description of the sport.
    pub description: String,
    /// Whether the sport is currently in season.
    pub active: bool,
    /// Whether the sport has outright/futures markets.
    pub has_outrights: bool,
}

/// A sporting event.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Event {
    /// Unique identifier for the event.
    pub id: String,
    /// Sport key this event belongs to.
    pub sport_key: String,
    /// Human-readable sport title.
    pub sport_title: String,
    /// When the event starts.
    pub commence_time: DateTime<Utc>,
    /// Home team name (if applicable).
    pub home_team: Option<String>,
    /// Away team name (if applicable).
    pub away_team: Option<String>,
}

/// An event with odds from bookmakers.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EventOdds {
    /// Unique identifier for the event.
    pub id: String,
    /// Sport key this event belongs to.
    pub sport_key: String,
    /// Human-readable sport title.
    pub sport_title: String,
    /// When the event starts.
    pub commence_time: DateTime<Utc>,
    /// Home team name (if applicable).
    pub home_team: Option<String>,
    /// Away team name (if applicable).
    pub away_team: Option<String>,
    /// List of bookmakers with their odds.
    pub bookmakers: Vec<Bookmaker>,
}

/// An event with scores.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EventScore {
    /// Unique identifier for the event.
    pub id: String,
    /// Sport key this event belongs to.
    pub sport_key: String,
    /// Human-readable sport title.
    pub sport_title: String,
    /// When the event starts.
    pub commence_time: DateTime<Utc>,
    /// Home team name (if applicable).
    pub home_team: Option<String>,
    /// Away team name (if applicable).
    pub away_team: Option<String>,
    /// Whether the event has been completed.
    pub completed: bool,
    /// Current scores for each team.
    pub scores: Option<Vec<Score>>,
    /// Last update time for scores.
    pub last_update: Option<DateTime<Utc>>,
}

/// Score for a team in an event.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Score {
    /// Team name.
    pub name: String,
    /// Current score (as string to handle various formats).
    pub score: String,
}

/// A bookmaker with odds for various markets.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Bookmaker {
    /// Unique key for the bookmaker.
    pub key: String,
    /// Human-readable bookmaker title.
    pub title: String,
    /// When the odds were last updated.
    pub last_update: DateTime<Utc>,
    /// Markets offered by this bookmaker.
    pub markets: Vec<MarketOdds>,
    /// Optional deep link to the bookmaker's page.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub link: Option<String>,
    /// Optional site ID.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub sid: Option<String>,
}

/// Odds for a specific market from a bookmaker.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MarketOdds {
    /// Market key (e.g., "h2h", "spreads", "totals").
    pub key: String,
    /// When the market odds were last updated.
    pub last_update: Option<DateTime<Utc>>,
    /// Outcomes/selections for this market.
    pub outcomes: Vec<Outcome>,
}

/// An outcome/selection within a market.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Outcome {
    /// Name of the outcome (team name, "Over", "Under", etc.).
    pub name: String,
    /// The odds price.
    pub price: f64,
    /// Point spread or total line (for spreads/totals markets).
    #[serde(skip_serializing_if = "Option::is_none")]
    pub point: Option<f64>,
    /// Description for player props or alternate markets.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    /// Bet link URL if available.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub link: Option<String>,
    /// DFS multiplier if requested.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub multiplier: Option<f64>,
}

/// A participant (team or player) in a sport.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Participant {
    /// Unique identifier for the participant.
    pub id: String,
    /// Full name of the team or player.
    pub full_name: String,
}

/// Bookmaker with available markets (without odds).
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BookmakerMarkets {
    /// Unique key for the bookmaker.
    pub key: String,
    /// Human-readable bookmaker title.
    pub title: String,
    /// List of available market keys.
    pub markets: Vec<String>,
}

/// Event with bookmaker market availability.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EventMarkets {
    /// Unique identifier for the event.
    pub id: String,
    /// Sport key this event belongs to.
    pub sport_key: String,
    /// Human-readable sport title.
    pub sport_title: String,
    /// When the event starts.
    pub commence_time: DateTime<Utc>,
    /// Home team name (if applicable).
    pub home_team: Option<String>,
    /// Away team name (if applicable).
    pub away_team: Option<String>,
    /// Bookmakers with their available markets.
    pub bookmakers: Vec<BookmakerMarkets>,
}

/// Wrapper for historical API responses.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HistoricalResponse<T> {
    /// The timestamp of the historical snapshot.
    pub timestamp: DateTime<Utc>,
    /// Previous available timestamp.
    pub previous_timestamp: Option<DateTime<Utc>>,
    /// Next available timestamp.
    pub next_timestamp: Option<DateTime<Utc>>,
    /// The actual data.
    pub data: T,
}

/// API usage information from response headers.
#[derive(Debug, Clone, Default)]
pub struct UsageInfo {
    /// Remaining API requests in the current period.
    pub requests_remaining: Option<u32>,
    /// Total requests used in the current period.
    pub requests_used: Option<u32>,
    /// Cost of the last request.
    pub requests_last: Option<u32>,
}

impl UsageInfo {
    /// Parse usage info from response headers.
    pub(crate) fn from_headers(headers: &reqwest::header::HeaderMap) -> Self {
        Self {
            requests_remaining: headers
                .get("x-requests-remaining")
                .and_then(|v| v.to_str().ok())
                .and_then(|v| v.parse().ok()),
            requests_used: headers
                .get("x-requests-used")
                .and_then(|v| v.to_str().ok())
                .and_then(|v| v.parse().ok()),
            requests_last: headers
                .get("x-requests-last")
                .and_then(|v| v.to_str().ok())
                .and_then(|v| v.parse().ok()),
        }
    }
}

/// A response with data and API usage information.
#[derive(Debug, Clone)]
pub struct Response<T> {
    /// The response data.
    pub data: T,
    /// API usage information.
    pub usage: UsageInfo,
}

impl<T> Response<T> {
    /// Create a new response with data and usage info.
    pub fn new(data: T, usage: UsageInfo) -> Self {
        Self { data, usage }
    }

    /// Map the data to a new type.
    pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Response<U> {
        Response {
            data: f(self.data),
            usage: self.usage,
        }
    }
}