soulsync/api/__init__.py
Broque Thomas d9aa8303a7 Add SoulSync REST API (v1) with API key authentication
Adds a full public REST API at /api/v1/ with 32 endpoints covering library, search, downloads, wishlist, watchlist, playlists, system status, and settings. Includes API key authentication (Bearer token), per-endpoint rate limiting, and consistent JSON response format. API keys can be generated and managed from the Settings page. No changes to existing functionality — the API delegates to the same backend services the web UI uses.
2026-03-03 09:49:00 -08:00

72 lines
2.2 KiB
Python

"""
SoulSync Public REST API (v1)
Blueprint factory + rate-limiter initialisation.
"""
from flask import Blueprint
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
from utils.logging_config import get_logger
from .helpers import api_error
logger = get_logger("api_v1")
# ---------------------------------------------------------------------------
# Rate limiter (initialised with the app in web_server.py via limiter.init_app)
# ---------------------------------------------------------------------------
limiter = Limiter(
key_func=get_remote_address,
default_limits=["60 per minute"],
storage_uri="memory://",
)
def create_api_blueprint():
"""Build and return the /api/v1 Blueprint with all sub-modules registered."""
bp = Blueprint("api_v1", __name__)
# ---- import & register sub-module routes ----
from .library import register_routes as reg_library
from .system import register_routes as reg_system
from .search import register_routes as reg_search
from .wishlist import register_routes as reg_wishlist
from .watchlist import register_routes as reg_watchlist
from .downloads import register_routes as reg_downloads
from .playlists import register_routes as reg_playlists
from .settings import register_routes as reg_settings
reg_library(bp)
reg_system(bp)
reg_search(bp)
reg_wishlist(bp)
reg_watchlist(bp)
reg_downloads(bp)
reg_playlists(bp)
reg_settings(bp)
# ---- error handlers (scoped to this Blueprint) ----
@bp.errorhandler(400)
def _bad_request(e):
return api_error("BAD_REQUEST", str(e), 400)
@bp.errorhandler(404)
def _not_found(e):
return api_error("NOT_FOUND", "Resource not found.", 404)
@bp.errorhandler(429)
def _rate_limited(e):
return api_error("RATE_LIMITED", "Too many requests. Please slow down.", 429)
@bp.errorhandler(500)
def _internal(e):
return api_error("INTERNAL_ERROR", "An internal server error occurred.", 500)
@bp.errorhandler(Exception)
def _unhandled(e):
logger.error(f"Unhandled API error: {e}", exc_info=True)
return api_error("INTERNAL_ERROR", "An unexpected error occurred.", 500)
return bp