NHL API Module
NHL API client with retry logic and rate limiting.
The API module provides an async HTTP client for fetching roster data from the official NHL API with built-in error handling, retries, and rate limiting.
NHL API client module.
- class nhl_scrabble.api.NHLApiClient(base_url=None, timeout=10, retries=3, rate_limit_max_requests=30, rate_limit_window=60.0, backoff_factor=2.0, max_backoff=30.0, cache_enabled=True, cache_expiry=3600, cache_dir=None, verify_ssl=True, dos_max_connections=10, dos_max_per_host=5, dos_circuit_breaker_threshold=5, dos_circuit_breaker_timeout=60.0)[source]
Bases:
objectClient for interacting with the NHL API.
This client provides methods to fetch team standings and roster data from the official NHL API with built-in retry logic, rate limiting, SSRF protection, DoS prevention, and enforced SSL/TLS certificate verification.
- SSL/TLS Security:
Certificate verification is always enabled and cannot be disabled
Uses certifi CA bundle for up-to-date certificate authorities
SSL errors are caught and logged for security monitoring
- DoS Prevention:
Circuit breaker pattern to prevent cascading failures
Connection pool limits to prevent resource exhaustion
Configurable failure thresholds and timeouts
- base_url
Base URL for the NHL API (SSRF-validated)
- timeout
Request timeout in seconds
- retries
Number of retry attempts for failed requests
- rate_limiter
Token bucket rate limiter for API requests
- circuit_breaker
Circuit breaker for DoS prevention
- ca_bundle
Path to CA bundle for SSL verification (uses certifi)
- BASE_URL = 'https://api-web.nhle.com/v1'
- __init__(base_url=None, timeout=10, retries=3, rate_limit_max_requests=30, rate_limit_window=60.0, backoff_factor=2.0, max_backoff=30.0, cache_enabled=True, cache_expiry=3600, cache_dir=None, verify_ssl=True, dos_max_connections=10, dos_max_per_host=5, dos_circuit_breaker_threshold=5, dos_circuit_breaker_timeout=60.0)[source]
Initialize the NHL API client.
- Parameters:
base_url (
str|None) – Base URL for NHL API (default: https://api-web.nhle.com/v1). Will be validated for SSRF protection on first request.timeout (
int) – Request timeout in seconds (default: 10)retries (
int) – Number of retry attempts for failed requests (default: 3)rate_limit_max_requests (
int) – Maximum requests per time window (default: 30)rate_limit_window (
float) – Time window for rate limiting in seconds (default: 60.0)backoff_factor (
float) – Exponential backoff multiplier (default: 2.0)max_backoff (
float) – Maximum backoff delay in seconds (default: 30.0)cache_enabled (
bool) – Enable HTTP caching (default: True)cache_expiry (
int) – Cache expiration in seconds (default: 3600 = 1 hour)cache_dir (
str|Path|None) – Cache directory path (default: platform-specific user cache directory)verify_ssl (
bool) – SSL verification (must be True, cannot be disabled for security)dos_max_connections (
int) – Maximum connection pool connections (default: 10)dos_max_per_host (
int) – Maximum connections per host (default: 5)dos_circuit_breaker_threshold (
int) – Circuit breaker failure threshold (default: 5)dos_circuit_breaker_timeout (
float) – Circuit breaker timeout in seconds (default: 60.0)
- Raises:
NHLApiError – If base_url fails SSRF protection validation or cache directory not writable
ValueError – If verify_ssl is False (SSL verification cannot be disabled)
- get_teams(season=None)[source]
Fetch all NHL teams with division and conference information.
This method uses the retry decorator to automatically retry on network errors. The URL is validated with SSRF protection before making the request.
- Parameters:
season (
str|None) – Optional season in format ‘YYYYYYYY’ (e.g., ‘20222023’ for 2022-23). If None, fetches current season data.- Returns:
- {
‘TOR’: {‘division’: ‘Atlantic’, ‘conference’: ‘Eastern’}, ‘MTL’: {‘division’: ‘Atlantic’, ‘conference’: ‘Eastern’}, …
}
- Return type:
- Raises:
NHLApiConnectionError – If unable to connect to the API
NHLApiError – For other API errors, including SSRF protection blocks
Examples
>>> client = NHLApiClient() >>> teams = client.get_teams() >>> "TOR" in teams True >>> teams_2022 = client.get_teams(season="20222023") >>> "TOR" in teams_2022 True
- get_team_roster(team_abbrev, season=None)[source]
Fetch the roster for a specific team with input and response validation.
Validates team abbreviation before making API call and validates response structure to prevent errors from malformed data.
The URL is validated with SSRF protection before making the request.
- Parameters:
- Return type:
- Returns:
Dictionary containing roster data with ‘forwards’, ‘defensemen’, and ‘goalies’ keys
- Raises:
ValidationError – If team abbreviation is invalid
NHLApiNotFoundError – If the roster is not found (404 response)
NHLApiConnectionError – If unable to connect to the API after all retries
NHLApiError – For other API errors, including SSRF protection blocks and malformed responses
- Security:
Validates team abbreviation to prevent injection attacks
Validates response structure to prevent KeyError exceptions
Sanitizes player names from API responses
SSRF protection on all API requests
Examples
>>> client = NHLApiClient() >>> roster = client.get_team_roster("TOR") >>> "forwards" in roster True >>> roster_2022 = client.get_team_roster("TOR", season="20222023") >>> "forwards" in roster_2022 True >>> client.get_team_roster("INVALID") Traceback (most recent call last): ValidationError: Team abbreviation must be 2-3 characters...
- get_rate_limit_stats()[source]
Get rate limiter statistics.
- Returns:
total_requests: Total requests made
total_waits: Total times waited for tokens
total_wait_time: Total time spent waiting
average_wait: Average wait time per wait
current_tokens: Current token count
max_tokens: Maximum token capacity
- Return type:
Examples
>>> client = NHLApiClient() >>> stats = client.get_rate_limit_stats() >>> "total_requests" in stats True
- get_cache_info()[source]
Get cache statistics and information.
- Returns:
enabled (bool): Whether caching is enabled
backend (str | None): Cache backend type (e.g., “sqlite”)
size (int | None): Number of cached responses
expiry (int): Cache expiry time in seconds
- Return type:
Examples
>>> client = NHLApiClient(cache_enabled=True) >>> info = client.get_cache_info() >>> print(info["enabled"]) True >>> print(info["backend"]) 'sqlite'
- exception nhl_scrabble.api.NHLApiConnectionError[source]
Bases:
NHLApiErrorRaised when unable to connect to the NHL API.
This includes network timeouts, connection refused, DNS failures, and other connection-related issues.
Examples
>>> raise NHLApiConnectionError("Unable to connect to NHL API after 3 retries") Traceback (most recent call last): NHLApiConnectionError: Unable to connect to NHL API after 3 retries
- exception nhl_scrabble.api.NHLApiError[source]
Bases:
APIErrorBase exception for NHL API errors.
Raised for NHL API-specific errors including HTTP errors, invalid responses, and API-level failures.
Examples
>>> raise NHLApiError("NHL API returned invalid data") Traceback (most recent call last): NHLApiError: NHL API returned invalid data
- exception nhl_scrabble.api.NHLApiNotFoundError[source]
Bases:
NHLApiErrorRaised when the requested resource is not found (404).
Indicates that the NHL API returned a 404 status code, meaning the requested resource (team, roster, etc.) does not exist.
Examples
>>> raise NHLApiNotFoundError("Roster not found for team: XYZ") Traceback (most recent call last): NHLApiNotFoundError: Roster not found for team: XYZ
- exception nhl_scrabble.api.NHLApiSSLError[source]
Bases:
NHLApiErrorRaised when SSL/TLS certificate verification fails.
Indicates a problem with SSL/TLS certificate validation, which could be a security issue or a configuration problem.
Examples
>>> raise NHLApiSSLError("SSL certificate verification failed for api.nhle.com") Traceback (most recent call last): NHLApiSSLError: SSL certificate verification failed for api.nhle.com
NHL Client
NHL API client for fetching team and roster data.
- class nhl_scrabble.api.nhl_client.NHLApiClient(base_url=None, timeout=10, retries=3, rate_limit_max_requests=30, rate_limit_window=60.0, backoff_factor=2.0, max_backoff=30.0, cache_enabled=True, cache_expiry=3600, cache_dir=None, verify_ssl=True, dos_max_connections=10, dos_max_per_host=5, dos_circuit_breaker_threshold=5, dos_circuit_breaker_timeout=60.0)[source]
Bases:
objectClient for interacting with the NHL API.
This client provides methods to fetch team standings and roster data from the official NHL API with built-in retry logic, rate limiting, SSRF protection, DoS prevention, and enforced SSL/TLS certificate verification.
- SSL/TLS Security:
Certificate verification is always enabled and cannot be disabled
Uses certifi CA bundle for up-to-date certificate authorities
SSL errors are caught and logged for security monitoring
- DoS Prevention:
Circuit breaker pattern to prevent cascading failures
Connection pool limits to prevent resource exhaustion
Configurable failure thresholds and timeouts
- base_url
Base URL for the NHL API (SSRF-validated)
- timeout
Request timeout in seconds
- retries
Number of retry attempts for failed requests
- rate_limiter
Token bucket rate limiter for API requests
- circuit_breaker
Circuit breaker for DoS prevention
- ca_bundle
Path to CA bundle for SSL verification (uses certifi)
- BASE_URL = 'https://api-web.nhle.com/v1'
- __init__(base_url=None, timeout=10, retries=3, rate_limit_max_requests=30, rate_limit_window=60.0, backoff_factor=2.0, max_backoff=30.0, cache_enabled=True, cache_expiry=3600, cache_dir=None, verify_ssl=True, dos_max_connections=10, dos_max_per_host=5, dos_circuit_breaker_threshold=5, dos_circuit_breaker_timeout=60.0)[source]
Initialize the NHL API client.
- Parameters:
base_url (
str|None) – Base URL for NHL API (default: https://api-web.nhle.com/v1). Will be validated for SSRF protection on first request.timeout (
int) – Request timeout in seconds (default: 10)retries (
int) – Number of retry attempts for failed requests (default: 3)rate_limit_max_requests (
int) – Maximum requests per time window (default: 30)rate_limit_window (
float) – Time window for rate limiting in seconds (default: 60.0)backoff_factor (
float) – Exponential backoff multiplier (default: 2.0)max_backoff (
float) – Maximum backoff delay in seconds (default: 30.0)cache_enabled (
bool) – Enable HTTP caching (default: True)cache_expiry (
int) – Cache expiration in seconds (default: 3600 = 1 hour)cache_dir (
str|Path|None) – Cache directory path (default: platform-specific user cache directory)verify_ssl (
bool) – SSL verification (must be True, cannot be disabled for security)dos_max_connections (
int) – Maximum connection pool connections (default: 10)dos_max_per_host (
int) – Maximum connections per host (default: 5)dos_circuit_breaker_threshold (
int) – Circuit breaker failure threshold (default: 5)dos_circuit_breaker_timeout (
float) – Circuit breaker timeout in seconds (default: 60.0)
- Raises:
NHLApiError – If base_url fails SSRF protection validation or cache directory not writable
ValueError – If verify_ssl is False (SSL verification cannot be disabled)
- get_teams(season=None)[source]
Fetch all NHL teams with division and conference information.
This method uses the retry decorator to automatically retry on network errors. The URL is validated with SSRF protection before making the request.
- Parameters:
season (
str|None) – Optional season in format ‘YYYYYYYY’ (e.g., ‘20222023’ for 2022-23). If None, fetches current season data.- Returns:
- {
‘TOR’: {‘division’: ‘Atlantic’, ‘conference’: ‘Eastern’}, ‘MTL’: {‘division’: ‘Atlantic’, ‘conference’: ‘Eastern’}, …
}
- Return type:
- Raises:
NHLApiConnectionError – If unable to connect to the API
NHLApiError – For other API errors, including SSRF protection blocks
Examples
>>> client = NHLApiClient() >>> teams = client.get_teams() >>> "TOR" in teams True >>> teams_2022 = client.get_teams(season="20222023") >>> "TOR" in teams_2022 True
- get_team_roster(team_abbrev, season=None)[source]
Fetch the roster for a specific team with input and response validation.
Validates team abbreviation before making API call and validates response structure to prevent errors from malformed data.
The URL is validated with SSRF protection before making the request.
- Parameters:
- Return type:
- Returns:
Dictionary containing roster data with ‘forwards’, ‘defensemen’, and ‘goalies’ keys
- Raises:
ValidationError – If team abbreviation is invalid
NHLApiNotFoundError – If the roster is not found (404 response)
NHLApiConnectionError – If unable to connect to the API after all retries
NHLApiError – For other API errors, including SSRF protection blocks and malformed responses
- Security:
Validates team abbreviation to prevent injection attacks
Validates response structure to prevent KeyError exceptions
Sanitizes player names from API responses
SSRF protection on all API requests
Examples
>>> client = NHLApiClient() >>> roster = client.get_team_roster("TOR") >>> "forwards" in roster True >>> roster_2022 = client.get_team_roster("TOR", season="20222023") >>> "forwards" in roster_2022 True >>> client.get_team_roster("INVALID") Traceback (most recent call last): ValidationError: Team abbreviation must be 2-3 characters...
- get_rate_limit_stats()[source]
Get rate limiter statistics.
- Returns:
total_requests: Total requests made
total_waits: Total times waited for tokens
total_wait_time: Total time spent waiting
average_wait: Average wait time per wait
current_tokens: Current token count
max_tokens: Maximum token capacity
- Return type:
Examples
>>> client = NHLApiClient() >>> stats = client.get_rate_limit_stats() >>> "total_requests" in stats True
- get_cache_info()[source]
Get cache statistics and information.
- Returns:
enabled (bool): Whether caching is enabled
backend (str | None): Cache backend type (e.g., “sqlite”)
size (int | None): Number of cached responses
expiry (int): Cache expiry time in seconds
- Return type:
Examples
>>> client = NHLApiClient(cache_enabled=True) >>> info = client.get_cache_info() >>> print(info["enabled"]) True >>> print(info["backend"]) 'sqlite'
- exception nhl_scrabble.api.nhl_client.NHLApiConnectionError[source]
Bases:
NHLApiErrorRaised when unable to connect to the NHL API.
This includes network timeouts, connection refused, DNS failures, and other connection-related issues.
Examples
>>> raise NHLApiConnectionError("Unable to connect to NHL API after 3 retries") Traceback (most recent call last): NHLApiConnectionError: Unable to connect to NHL API after 3 retries
- exception nhl_scrabble.api.nhl_client.NHLApiError[source]
Bases:
APIErrorBase exception for NHL API errors.
Raised for NHL API-specific errors including HTTP errors, invalid responses, and API-level failures.
Examples
>>> raise NHLApiError("NHL API returned invalid data") Traceback (most recent call last): NHLApiError: NHL API returned invalid data
- exception nhl_scrabble.api.nhl_client.NHLApiNotFoundError[source]
Bases:
NHLApiErrorRaised when the requested resource is not found (404).
Indicates that the NHL API returned a 404 status code, meaning the requested resource (team, roster, etc.) does not exist.
Examples
>>> raise NHLApiNotFoundError("Roster not found for team: XYZ") Traceback (most recent call last): NHLApiNotFoundError: Roster not found for team: XYZ
- exception nhl_scrabble.api.nhl_client.NHLApiSSLError[source]
Bases:
NHLApiErrorRaised when SSL/TLS certificate verification fails.
Indicates a problem with SSL/TLS certificate validation, which could be a security issue or a configuration problem.
Examples
>>> raise NHLApiSSLError("SSL certificate verification failed for api.nhle.com") Traceback (most recent call last): NHLApiSSLError: SSL certificate verification failed for api.nhle.com
NHLClient
Async HTTP client for NHL API with context manager support.
Features:
Async/await support with aiohttp
Automatic retry with exponential backoff
Rate limiting with configurable delay
Timeout handling
Session management via context manager
Comprehensive error handling
Configuration:
Environment variables for customization:
NHL_SCRABBLE_API_TIMEOUT- Request timeout in seconds (default: 10)NHL_SCRABBLE_API_RETRIES- Number of retry attempts (default: 3)NHL_SCRABBLE_RATE_LIMIT_DELAY- Delay between requests in seconds (default: 0.3)
Usage:
from nhl_scrabble.api import NHLClient
import asyncio
async def fetch_data():
async with NHLClient() as client:
# Fetch all teams
teams = await client.fetch_all_teams()
# Fetch roster for specific team
roster = await client.fetch_team_roster("TOR")
# Fetch all rosters (with rate limiting)
all_rosters = await client.fetch_all_rosters()
return teams, all_rosters
# Run async code
teams, rosters = asyncio.run(fetch_data())
Methods
fetch_all_teams
Fetch metadata for all NHL teams including division and conference.
Returns:
List of Team objects with: * Team ID, abbreviation, full name * Division and conference assignments * Logo URL
Endpoint:
GET https://api-web.nhle.com/v1/standings/now
Example:
async with NHLClient() as client:
teams = await client.fetch_all_teams()
for team in teams:
print(f"{team.name} ({team.abbrev}) - {team.division}, {team.conference}")
fetch_team_roster
Fetch current roster for a specific team.
Parameters:
team_abbrev- Team abbreviation (e.g., ‘TOR’, ‘MTL’, ‘NYR’)
Returns:
List of Player objects for the team’s current roster
Endpoint:
GET https://api-web.nhle.com/v1/roster/{team_abbrev}/current
Example:
async with NHLClient() as client:
roster = await client.fetch_team_roster("TOR")
print(f"Toronto Maple Leafs roster: {len(roster)} players")
for player in roster[:5]:
print(f" {player.firstName} {player.lastName}")
fetch_all_rosters
Fetch rosters for all NHL teams with rate limiting.
Returns:
Dictionary mapping team abbreviations to lists of Player objects
Example:
async with NHLClient() as client:
all_rosters = await client.fetch_all_rosters()
total_players = sum(len(roster) for roster in all_rosters.values())
print(f"Total players across NHL: {total_players}")
Error Handling
The client handles various error conditions:
Network Errors:
Connection timeouts → Automatic retry with exponential backoff
Network unavailable → Raises with descriptive error message
DNS failures → Raises with connection details
HTTP Errors:
404 Not Found → Logs warning, returns empty list
429 Too Many Requests → Respects retry-after header
500+ Server Errors → Retries with backoff
Example Error Handling:
from nhl_scrabble.api import NHLClient
import aiohttp
import asyncio
async def safe_fetch():
try:
async with NHLClient() as client:
teams = await client.fetch_all_teams()
except aiohttp.ClientError as e:
print(f"Network error: {e}")
teams = []
except asyncio.TimeoutError:
print("Request timed out")
teams = []
return teams
Rate Limiting
The client implements rate limiting to be respectful to the NHL API:
Default delay: 0.3 seconds between roster fetches
Configurable via
NHL_SCRABBLE_RATE_LIMIT_DELAYApplied in
fetch_all_rosters()methodUses
asyncio.sleep()for non-blocking delays
Custom Rate Limit:
import os
os.environ["NHL_SCRABBLE_RATE_LIMIT_DELAY"] = "0.5" # 500ms delay
async with NHLClient() as client:
rosters = await client.fetch_all_rosters() # Uses 500ms delay
Retry Logic
Automatic retry with exponential backoff:
Retries: Configurable (default: 3)
Backoff: Exponential (1s, 2s, 4s)
Conditions: Network errors, timeouts, 5xx errors
No Retry: 4xx errors (client errors)
Custom Retry Configuration:
import os
os.environ["NHL_SCRABBLE_API_RETRIES"] = "5" # 5 retry attempts
async with NHLClient() as client:
teams = await client.fetch_all_teams() # Up to 5 retries