Source code for gamesheet_sdk.common.shared.gamesheet_http

# Copyright (c) 2026 bdperkin
# SPDX-License-Identifier: MIT

"""HTTP response handling utilities."""

from __future__ import annotations

from http import HTTPStatus
from typing import TYPE_CHECKING, Any

from gamesheet_sdk.common import errors
from gamesheet_sdk.common.exceptions import (
    AuthenticationError,
    GameSheetAPIError,
    GameSheetError,
    GameSheetNotFoundError,
    GameSheetPermissionError,
    GameSheetRateLimitError,
)

if TYPE_CHECKING:
    import requests


[docs] def handle_response( response: requests.Response, endpoint: str, context_msg: str = "request", ) -> None: """Centralized HTTP error handling for all domain modules. Args: response (requests.Response): The HTTP response object. endpoint (str): The endpoint that was called. context_msg (str): Context message for error reporting (e.g., ``"GET associations"``). Raises: AuthenticationError: If response status is 401 (Unauthorized). GameSheetPermissionError: If response status is 403 (Forbidden). GameSheetNotFoundError: If response status is 404 (Not Found). GameSheetRateLimitError: If response status is 429 (Too Many Requests). GameSheetAPIError: For any other >= 400 response status. """ text_val = getattr(response, "text", "") body_snippet = text_val[:200] if isinstance(text_val, str) and text_val else None if response.status_code == HTTPStatus.UNAUTHORIZED: msg = errors.ERROR_MSG_401_GENERIC.format(context=context_msg) raise AuthenticationError(msg) if response.status_code == HTTPStatus.FORBIDDEN: msg = errors.ERROR_MSG_403_GENERIC.format(context=context_msg) raise GameSheetPermissionError( msg, status_code=HTTPStatus.FORBIDDEN, endpoint=endpoint, response_body=body_snippet, ) if response.status_code == HTTPStatus.NOT_FOUND: msg = errors.ERROR_MSG_404_RESOURCE.format(endpoint=endpoint) raise GameSheetNotFoundError( msg, status_code=HTTPStatus.NOT_FOUND, endpoint=endpoint, response_body=body_snippet, ) if response.status_code == HTTPStatus.TOO_MANY_REQUESTS: msg = f"Rate limit exceeded (HTTP 429) for {endpoint}" raise GameSheetRateLimitError( msg, status_code=HTTPStatus.TOO_MANY_REQUESTS, endpoint=endpoint, response_body=body_snippet, ) if response.status_code >= HTTPStatus.BAD_REQUEST: msg = errors.ERROR_MSG_GENERIC_HTTP.format( context=context_msg.upper(), endpoint=endpoint, status_code=response.status_code, text=response.text, ) raise GameSheetAPIError( msg, status_code=response.status_code, endpoint=endpoint, response_body=body_snippet, )
[docs] def check_bff_response_status(data: dict[str, Any], _endpoint: str) -> None: """Validate BFF API response status field. BFF API responses include a ``"status"`` field that should be ``"success"``. Args: data (dict[str, Any]): The parsed JSON response data. Raises: GameSheetError: If status is not ``"success"``. """ status = data.get("status") if status != "success": msg = errors.ERROR_MSG_BFF_NON_SUCCESS.format(status=status, response=data) raise GameSheetError(msg)
[docs] def handle_season_scoped_response( response: requests.Response, endpoint: str, season_id: str, method: str = "GET", resource_type: str = "season", ) -> None: """Handle HTTP errors for season-scoped API calls. Provides season-specific error messages for common failures. Args: response (requests.Response): The HTTP response object. endpoint (str): The endpoint that was called. season_id (str): The season ID used in the request. method (str): The HTTP verb (GET, POST, PATCH, DELETE). resource_type (str): Type of resource being accessed (e.g. "season", "referee"). Raises: AuthenticationError: If response status is 401 (Unauthorized). GameSheetPermissionError: If response status is 403 (Forbidden). GameSheetNotFoundError: If response status is 404 (Not Found). GameSheetAPIError: For any other >= 400 response status. """ text_val = getattr(response, "text", "") body_snippet = repr(text_val[:200]) if isinstance(text_val, str) and text_val else None if response.status_code == HTTPStatus.UNAUTHORIZED: raise AuthenticationError(errors.ERROR_MSG_401_EXPIRED) if response.status_code == HTTPStatus.FORBIDDEN: msg = errors.ERROR_MSG_403_GENERIC.format(context=f"{method} {resource_type}") raise GameSheetPermissionError( msg, status_code=HTTPStatus.FORBIDDEN, endpoint=endpoint, response_body=body_snippet, ) if response.status_code == HTTPStatus.NOT_FOUND: msg = errors.ERROR_MSG_404_SEASON.format(season_id=season_id) raise GameSheetNotFoundError( msg, status_code=HTTPStatus.NOT_FOUND, endpoint=endpoint, response_body=body_snippet, ) if response.status_code >= HTTPStatus.BAD_REQUEST: msg = errors.ERROR_MSG_GENERIC_HTTP.format( context=method.upper(), endpoint=endpoint, status_code=response.status_code, text=repr(text_val[:200]) if isinstance(text_val, str) else "", ) raise GameSheetAPIError( msg, status_code=response.status_code, endpoint=endpoint, response_body=body_snippet, )