"""News articles router -- paginated, filterable by category.""" from __future__ import annotations import logging from typing import Any, Dict, List, Optional from fastapi import APIRouter, Query from server.cache import cache from server.config import settings from server.services.news_service import get_news, get_news_count logger = logging.getLogger(__name__) router = APIRouter(prefix="/api", tags=["news"]) def _cache_key(limit: int, offset: int, category: Optional[str]) -> str: return f"news:{limit}:{offset}:{category}" @router.get("/news") async def get_news_articles( limit: int = Query(default=20, le=50, ge=1), offset: int = Query(default=0, ge=0), category: Optional[str] = Query(default=None), ) -> Dict[str, Any]: """Return a paginated list of news articles. Response shape:: { "articles": [ ... ], "total": int, "limit": int, "offset": int, } """ key = _cache_key(limit, offset, category) # --- cache hit? ----------------------------------------------------------- cached = await cache.get(key) if cached is not None: return cached # --- cache miss ----------------------------------------------------------- articles: List[Dict[str, Any]] = [] total: int = 0 try: articles = await get_news(limit=limit, offset=offset, category=category, max_age_hours=settings.news_max_age_hours) except Exception as exc: logger.exception("Failed to fetch news articles") return { "articles": [], "total": 0, "limit": limit, "offset": offset, "error": True, "message": str(exc), } try: total = await get_news_count(max_age_hours=settings.news_max_age_hours, category=category) except Exception as exc: logger.exception("Failed to fetch news count") # We still have articles -- return them with total = len(articles) total = len(articles) payload: Dict[str, Any] = { "articles": articles, "total": total, "limit": limit, "offset": offset, } await cache.set(key, payload, settings.news_cache_ttl) return payload