"""领券业务透传端点。 把客户端的 POST /api/v1/coupon/step 请求原样转发给 pricebot-backend 的 /api/coupon/step,只在外层加 JWT 鉴权。 pricebot 协议文档: pricebot-backend/docs/projects/领券-客户端对接协议.md """ from __future__ import annotations import logging from typing import Any import httpx from fastapi import APIRouter, HTTPException, Request, status from app.api.deps import CurrentUser from app.core.config import settings logger = logging.getLogger("shagua.coupon") router = APIRouter(prefix="/api/v1/coupon", tags=["coupon"]) @router.post("/step", summary="领券任务步进 (透传到 pricebot)") async def coupon_step( request: Request, user: CurrentUser, ) -> dict[str, Any]: """把请求体原样转发给 pricebot-backend 的 /api/coupon/step。 - 鉴权: Bearer access_token (get_current_user 隐式校验) - 透传: 不做 schema 校验,pricebot 自己校验 - 失败: 网络不可达 / pricebot 5xx → 502 + 友好 message """ try: body = await request.json() except Exception as e: raise HTTPException(status_code=400, detail=f"invalid json body: {e}") from e url = f"{settings.PRICEBOT_BASE_URL.rstrip('/')}/api/coupon/step" timeout = settings.PRICEBOT_REQUEST_TIMEOUT_SEC logger.info( "coupon_step user_id=%d trace_id=%s step=%s", user.id, body.get("trace_id"), body.get("step"), ) try: async with httpx.AsyncClient(timeout=timeout) as client: resp = await client.post(url, json=body) except httpx.RequestError as e: logger.error("[pricebot] request failed: %s", e) raise HTTPException( status_code=status.HTTP_502_BAD_GATEWAY, detail=f"pricebot upstream unreachable: {e}", ) from e if resp.status_code >= 500: logger.error( "[pricebot] 5xx status=%d body=%s", resp.status_code, resp.text[:500], ) raise HTTPException( status_code=status.HTTP_502_BAD_GATEWAY, detail=f"pricebot upstream returned {resp.status_code}", ) return resp.json()