nhl_scrabble.api

NHL API client module.

This package provides the NHL API client and related utilities for fetching team and roster data from the official NHL API.

Public API:
  • NHLApiClient: Main API client class

  • Error classes: NHLApiError, NHLApiConnectionError, NHLApiNotFoundError, NHLApiSSLError

  • Retry utilities: get_retry_after (from api.retry)

  • Error handlers: handle_http_error, handle_connection_error (from api.errors)

Functions

get_retry_after(response)

Extract Retry-After header value from 429 response.

handle_connection_error(error[, context, ...])

Handle connection errors after retries exhausted.

handle_http_error(error[, context])

Handle HTTP errors and convert to appropriate NHL API exceptions.

Classes

NHLApiClient([base_url, timeout, retries, ...])

Client for interacting with the NHL API.

Exceptions

NHLApiConnectionError

Raised when unable to connect to the NHL API.

NHLApiError

Base exception for NHL API errors.

NHLApiNotFoundError

Raised when the requested resource is not found (404).

NHLApiSSLError

Raised when SSL/TLS certificate verification fails.

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][source]

Bases: object

Client 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[source]

Base URL for the NHL API (SSRF-validated)

timeout[source]

Request timeout in seconds

retries[source]

Number of retry attempts for failed requests

rate_limiter[source]

Token bucket rate limiter for API requests

circuit_breaker[source]

Circuit breaker for DoS prevention

ca_bundle[source]

Path to CA bundle for SSL verification (uses certifi)

BASE_URL = 'https://api-web.nhle.com/v1'[source]
__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][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)

session: CachedSession | Session[source]
__del__()[source][source]

Destructor - close session if not already closed (safety net).

Return type:

None

get_teams(season=None)[source][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:

dict[str, dict[str, str]]

Raises:

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][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:
  • team_abbrev (str) – Team abbreviation (e.g., ‘TOR’, ‘MTL’)

  • season (str | None) – Optional season in format ‘YYYYYYYY’ (e.g., ‘20222023’ for 2022-23). If None, fetches current season roster.

Return type:

dict[str, Any]

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_player_details(player_id)[source][source]

Fetch detailed player information from NHL API.

Parameters:

player_id (int) – NHL player ID (numeric)

Return type:

dict[str, Any]

Returns:

Player detail data including photo, birthplace, position, etc.

Raises:

Examples

>>> client = NHLApiClient()
>>> try:
...     player = client.get_player_details(8478402)  # Connor McDavid
...     assert "playerId" in player
...     assert "firstName" in player
... finally:
...     client.close()
get_rate_limit_stats()[source][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:

dict[str, Any]

Examples

>>> client = NHLApiClient()
>>> stats = client.get_rate_limit_stats()
>>> "total_requests" in stats
True
clear_cache()[source][source]

Clear the HTTP cache.

Return type:

None

get_cache_info()[source][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:

dict[str, Any]

Examples

>>> client = NHLApiClient(cache_enabled=True)
>>> info = client.get_cache_info()
>>> print(info["enabled"])
True
>>> print(info["backend"])
'sqlite'
close()[source][source]

Close the session and release resources.

Return type:

None

__enter__()[source][source]

Support context manager protocol.

Return type:

NHLApiClient

__exit__(exc_type, exc_val, exc_tb)[source][source]

Close session when exiting context manager.

Return type:

None

exception nhl_scrabble.api.NHLApiConnectionError[source][source]

Bases: NHLApiError

Raised 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][source]

Bases: APIError

Base 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][source]

Bases: NHLApiError

Raised 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][source]

Bases: NHLApiError

Raised 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_scrabble.api.get_retry_after(response)[source][source]

Extract Retry-After header value from 429 response.

The Retry-After header can be either: - An integer (seconds to wait) - An HTTP date (less common for 429 responses)

If no valid Retry-After header is found, returns 1.0 second as default.

Parameters:

response (Response) – HTTP response with 429 status

Return type:

float

Returns:

Seconds to wait before retry (minimum 1.0)

Examples

>>> from unittest.mock import Mock
>>> response = Mock()
>>> response.headers = {"Retry-After": "60"}
>>> get_retry_after(response)
60.0
>>> response.headers = {}
>>> get_retry_after(response)
1.0
>>> response.headers = {"Retry-After": "invalid"}
>>> get_retry_after(response)
1.0
nhl_scrabble.api.handle_connection_error(error, context='', retries=3)[source][source]

Handle connection errors after retries exhausted.

Parameters:
  • error (RequestException) – The connection error

  • context (str) – Optional context string

  • retries (int) – Number of retries that were attempted

Raises:
Return type:

None

Examples

>>> import requests
>>> error = requests.exceptions.Timeout("Connection timeout")
>>> try:
...     handle_connection_error(error, "fetching teams", retries=3)
... except NHLApiConnectionError as e:
...     print("timeout" in str(e).lower())
True
nhl_scrabble.api.handle_http_error(error, context='')[source][source]

Handle HTTP errors and convert to appropriate NHL API exceptions.

Parameters:
  • error (HTTPError) – The HTTP error to handle

  • context (str) – Optional context string (e.g., “team TOR”)

Raises:
Return type:

None

Examples

>>> import requests
>>> from unittest.mock import Mock
>>> response = Mock()
>>> response.status_code = 404
>>> error = requests.exceptions.HTTPError(response=response)
>>> try:
...     handle_http_error(error, "team TOR")
... except NHLApiNotFoundError as e:
...     print(str(e))
Not found: team TOR