"""
NHL API Client
A comprehensive Python client for the NHL API with functions for all documented endpoints.
Based on the NHL API Reference: https://github.com/Zmalski/NHL-API-Reference
"""
import requests
from typing import Dict, Any, Optional, List, Union
import json
class NHLAPIClient:
"""Client for interacting with the NHL API."""
def __init__(self, base_url: str = "https://api-web.nhle.com"):
self.base_url = base_url
self.session = requests.Session()
self.session.headers.update({
'User-Agent': 'NHL-MCP-Client/1.0'
})
def _make_request(self, endpoint: str, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
"""Make a GET request to the NHL API."""
url = f"{self.base_url}{endpoint}"
try:
response = self.session.get(url, params=params)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
raise Exception(f"API request failed: {str(e)}")
except json.JSONDecodeError as e:
raise Exception(f"Failed to decode JSON response: {str(e)}")
# Player Information Endpoints
def get_player_game_log(self, player_id: int, season: int, game_type: int) -> Dict[str, Any]:
"""
Get game log for a specific player, season, and game type.
Args:
player_id: Player ID
season: Season in YYYYYYYY format (e.g., 20232024)
game_type: Game type (2 for regular season, 3 for playoffs)
"""
endpoint = f"/v1/player/{player_id}/game-log/{season}/{game_type}"
return self._make_request(endpoint)
def get_player_info(self, player_id: int) -> Dict[str, Any]:
"""
Get information for a specific player.
Args:
player_id: Player ID
"""
endpoint = f"/v1/player/{player_id}/landing"
return self._make_request(endpoint)
def get_player_game_log_now(self, player_id: int) -> Dict[str, Any]:
"""
Get current game log for a specific player.
Args:
player_id: Player ID
"""
endpoint = f"/v1/player/{player_id}/game-log/now"
return self._make_request(endpoint)
# Skater Stats Endpoints
def get_current_skater_stats_leaders(self, categories: Optional[str] = None, limit: Optional[int] = None) -> Dict[str, Any]:
"""
Get current skater stats leaders.
Args:
categories: Optional categories filter
limit: Optional limit (-1 for all results)
"""
endpoint = "/v1/skater-stats-leaders/current"
params = {}
if categories:
params['categories'] = categories
if limit is not None:
params['limit'] = limit
return self._make_request(endpoint, params)
def get_skater_stats_leaders(self, season: int, game_type: int, categories: Optional[str] = None, limit: Optional[int] = None) -> Dict[str, Any]:
"""
Get skater stats leaders for a specific season and game type.
Args:
season: Season in YYYYYYYY format
game_type: Game type (2 for regular season, 3 for playoffs)
categories: Optional categories filter
limit: Optional limit (-1 for all results)
"""
endpoint = f"/v1/skater-stats-leaders/{season}/{game_type}"
params = {}
if categories:
params['categories'] = categories
if limit is not None:
params['limit'] = limit
return self._make_request(endpoint, params)
# Goalie Stats Endpoints
def get_current_goalie_stats_leaders(self, categories: Optional[str] = None, limit: Optional[int] = None) -> Dict[str, Any]:
"""
Get current goalie stats leaders.
Args:
categories: Optional categories filter
limit: Optional limit (-1 for all results)
"""
endpoint = "/v1/goalie-stats-leaders/current"
params = {}
if categories:
params['categories'] = categories
if limit is not None:
params['limit'] = limit
return self._make_request(endpoint, params)
def get_goalie_stats_leaders(self, season: int, game_type: int, categories: Optional[str] = None, limit: Optional[int] = None) -> Dict[str, Any]:
"""
Get goalie stats leaders for a specific season and game type.
Args:
season: Season in YYYYYYYY format
game_type: Game type (2 for regular season, 3 for playoffs)
categories: Optional categories filter
limit: Optional limit (-1 for all results)
"""
endpoint = f"/v1/goalie-stats-leaders/{season}/{game_type}"
params = {}
if categories:
params['categories'] = categories
if limit is not None:
params['limit'] = limit
return self._make_request(endpoint, params)
# Player Spotlight
def get_player_spotlight(self) -> Dict[str, Any]:
"""Get players in the spotlight."""
endpoint = "/v1/player-spotlight"
return self._make_request(endpoint)
# Standings Endpoints
def get_standings_now(self) -> Dict[str, Any]:
"""Get current standings."""
endpoint = "/v1/standings/now"
return self._make_request(endpoint)
def get_standings_by_date(self, date: str) -> Dict[str, Any]:
"""
Get standings for a specific date.
Args:
date: Date in YYYY-MM-DD format
"""
endpoint = f"/v1/standings/{date}"
return self._make_request(endpoint)
def get_standings_season(self) -> Dict[str, Any]:
"""Get standings information for each season."""
endpoint = "/v1/standings-season"
return self._make_request(endpoint)
# Team Stats Endpoints
def get_club_stats_now(self, team: str) -> Dict[str, Any]:
"""
Get current statistics for a specific club.
Args:
team: Three-letter team code (e.g., 'TOR')
"""
endpoint = f"/v1/club-stats/{team}/now"
return self._make_request(endpoint)
def get_club_stats_season(self, team: str) -> Dict[str, Any]:
"""
Get stats overview for each season for a specific club.
Args:
team: Three-letter team code
"""
endpoint = f"/v1/club-stats-season/{team}"
return self._make_request(endpoint)
def get_club_stats(self, team: str, season: int, game_type: int) -> Dict[str, Any]:
"""
Get stats for a specific team, season, and game type.
Args:
team: Three-letter team code
season: Season in YYYYYYYY format
game_type: Game type (2 for regular season, 3 for playoffs)
"""
endpoint = f"/v1/club-stats/{team}/{season}/{game_type}"
return self._make_request(endpoint)
def get_team_scoreboard(self, team: str) -> Dict[str, Any]:
"""
Get scoreboard for a specific team.
Args:
team: Three-letter team code
"""
endpoint = f"/v1/scoreboard/{team}/now"
return self._make_request(endpoint)
# Team Roster and Schedule
def get_team_roster(self, team: str, season: Optional[str] = None) -> Dict[str, Any]:
"""
Get roster for a specific team.
Args:
team: Three-letter team code
season: Optional season parameter
"""
if season:
endpoint = f"/v1/roster/{team}/{season}"
else:
endpoint = f"/v1/roster/{team}/current"
return self._make_request(endpoint)
def get_team_schedule(self, team: str, season: Optional[str] = None) -> Dict[str, Any]:
"""
Get schedule for a specific team.
Args:
team: Three-letter team code
season: Optional season parameter
"""
if season:
endpoint = f"/v1/club-schedule-season/{team}/{season}"
else:
endpoint = f"/v1/club-schedule/{team}/now"
return self._make_request(endpoint)
# League Schedule Endpoints
def get_schedule_now(self) -> Dict[str, Any]:
"""Get current schedule."""
endpoint = "/v1/schedule/now"
return self._make_request(endpoint)
def get_schedule_by_date(self, date: str) -> Dict[str, Any]:
"""
Get schedule for a specific date.
Args:
date: Date in YYYY-MM-DD format
"""
endpoint = f"/v1/schedule/{date}"
return self._make_request(endpoint)
def get_schedule_calendar_now(self) -> Dict[str, Any]:
"""Get current schedule calendar."""
endpoint = "/v1/schedule-calendar/now"
return self._make_request(endpoint)
def get_schedule_calendar_by_date(self, date: str) -> Dict[str, Any]:
"""
Get schedule calendar for a specific date.
Args:
date: Date in YYYY-MM-DD format
"""
endpoint = f"/v1/schedule-calendar/{date}"
return self._make_request(endpoint)
# Game Information Endpoints
def get_daily_scores_now(self) -> Dict[str, Any]:
"""Get current daily scores."""
endpoint = "/v1/score/now"
return self._make_request(endpoint)
def get_daily_scores_by_date(self, date: str) -> Dict[str, Any]:
"""
Get daily scores for a specific date.
Args:
date: Date in YYYY-MM-DD format
"""
endpoint = f"/v1/score/{date}"
return self._make_request(endpoint)
def get_scoreboard_now(self) -> Dict[str, Any]:
"""Get current overall scoreboard."""
endpoint = "/v1/scoreboard/now"
return self._make_request(endpoint)
def get_where_to_watch(self, include: Optional[str] = None) -> Dict[str, Any]:
"""
Get streaming information.
Args:
include: Optional include parameter
"""
endpoint = "/v1/where-to-watch"
params = {}
if include:
params['include'] = include
return self._make_request(endpoint, params)
# Game Events Endpoints
def get_play_by_play(self, game_id: int) -> Dict[str, Any]:
"""
Get play-by-play information for a specific game.
Args:
game_id: Game ID
"""
endpoint = f"/v1/gamecenter/{game_id}/play-by-play"
return self._make_request(endpoint)
def get_game_landing(self, game_id: int) -> Dict[str, Any]:
"""
Get landing information for a specific game.
Args:
game_id: Game ID
"""
endpoint = f"/v1/gamecenter/{game_id}/landing"
return self._make_request(endpoint)
def get_game_boxscore(self, game_id: int) -> Dict[str, Any]:
"""
Get boxscore information for a specific game.
Args:
game_id: Game ID
"""
endpoint = f"/v1/gamecenter/{game_id}/boxscore"
return self._make_request(endpoint)
def get_game_story(self, game_id: int) -> Dict[str, Any]:
"""
Get game story information for a specific game.
Args:
game_id: Game ID
"""
endpoint = f"/v1/wsc/game-story/{game_id}"
return self._make_request(endpoint)
# Network/TV Schedule Endpoints
def get_tv_schedule_by_date(self, date: str) -> Dict[str, Any]:
"""
Get TV schedule for a specific date.
Args:
date: Date in YYYY-MM-DD format
"""
endpoint = f"/v1/network/tv-schedule/{date}"
return self._make_request(endpoint)
def get_tv_schedule_now(self) -> Dict[str, Any]:
"""Get current TV schedule."""
endpoint = "/v1/network/tv-schedule/now"
return self._make_request(endpoint)
# Playoff Information
def get_playoff_overview(self) -> Dict[str, Any]:
"""Get playoff overview."""
endpoint = "/v1/playoff-overview"
return self._make_request(endpoint)
def get_playoff_schedule(self, season: Optional[int] = None) -> Dict[str, Any]:
"""
Get playoff schedule.
Args:
season: Optional season in YYYYYYYY format
"""
if season:
endpoint = f"/v1/playoff-schedule/{season}"
else:
endpoint = "/v1/playoff-schedule/now"
return self._make_request(endpoint)
def get_playoff_bracket(self, season: Optional[int] = None) -> Dict[str, Any]:
"""
Get playoff bracket.
Args:
season: Optional season in YYYYYYYY format
"""
if season:
endpoint = f"/v1/playoff-bracket/{season}"
else:
endpoint = "/v1/playoff-bracket/now"
return self._make_request(endpoint)
# Season and Draft Information
def get_season_info(self) -> Dict[str, Any]:
"""Get season information."""
endpoint = "/v1/season"
return self._make_request(endpoint)
def get_draft_info(self, year: Optional[int] = None) -> Dict[str, Any]:
"""
Get draft information.
Args:
year: Optional draft year
"""
if year:
endpoint = f"/v1/draft/{year}"
else:
endpoint = "/v1/draft"
return self._make_request(endpoint)
# Miscellaneous Endpoints
def get_meta_info(self) -> Dict[str, Any]:
"""Get meta information."""
endpoint = "/v1/meta"
return self._make_request(endpoint)
def get_postal_lookup(self, postal_code: str) -> Dict[str, Any]:
"""
Get postal code lookup information.
Args:
postal_code: Postal code to lookup
"""
endpoint = f"/v1/postal-lookup/{postal_code}"
return self._make_request(endpoint)
def get_game_replays(self, date: Optional[str] = None) -> Dict[str, Any]:
"""
Get game replays.
Args:
date: Optional date in YYYY-MM-DD format
"""
if date:
endpoint = f"/v1/game-replays/{date}"
else:
endpoint = "/v1/game-replays"
return self._make_request(endpoint)
# Convenience functions for common operations
def get_nhl_client() -> NHLAPIClient:
"""Get a configured NHL API client."""
return NHLAPIClient()
# Example usage
if __name__ == "__main__":
client = get_nhl_client()
# Example: Get current standings
try:
standings = client.get_standings_now()
print("Current NHL Standings:")
print(json.dumps(standings, indent=2))
except Exception as e:
print(f"Error: {e}")