lljz66 commited on
Commit
7ea950d
Β·
verified Β·
1 Parent(s): 5230075

Put app/routers/assets.py

Browse files
Files changed (1) hide show
  1. app/routers/assets.py +9 -19
app/routers/assets.py CHANGED
@@ -1,16 +1,4 @@
1
- """POST /assets β€” extract image/video/audio/svg-icon/font assets from a URL.
2
-
3
- Returns structured error responses for all failure modes:
4
- - Bad request (400) β€” missing/invalid url
5
- - SSRF block (403) β€” blocked host
6
- - Not HTML (415) β€” wrong content-type
7
- - Fetch error (502) β€” network or redirect failure
8
- - Page too large (413) β€” exceeds size cap
9
- - Server error (500) β€” unexpected
10
-
11
- All errors are logged at INFO+ level and returned as JSON with
12
- the request ID attached.
13
- """
14
 
15
  import logging
16
  import uuid
@@ -19,12 +7,12 @@ from fastapi import APIRouter, HTTPException, status
19
 
20
  from app.schemas import AssetExtractRequest, AssetExtractResponse, ErrorResponse
21
  from app.services.asset_service import AssetExtractError, extract_assets
 
22
 
23
  router = APIRouter()
24
 
25
 
26
  def _log_request(req: AssetExtractRequest, phase: str, **extra) -> None:
27
- """Log a structured request entry."""
28
  logger = logging.getLogger(__name__)
29
  logger.info("request phase=%s id=%s url=%r groups=%r enrich=%s include_data_uris=%s extra=%r",
30
  phase, req._request_id or "?", req.url, req.groups, req.enrich,
@@ -32,7 +20,6 @@ def _log_request(req: AssetExtractRequest, phase: str, **extra) -> None:
32
 
33
 
34
  def _log_response(req: AssetExtractRequest, status_code: int, phase: str, **extra) -> None:
35
- """Log a structured response entry."""
36
  logger = logging.getLogger(__name__)
37
  logger.info("response phase=%s status=%s id=%s url=%r extra=%r",
38
  phase, status_code, req._request_id or "?", req.url, extra)
@@ -43,7 +30,6 @@ async def extract_assets_endpoint(req: AssetExtractRequest) -> AssetExtractRespo
43
  """Extract assets from a URL, grouped by category."""
44
  _log_request(req, "start")
45
  req_id = req._request_id or str(uuid.uuid4())
46
- _request_id = req_id
47
  try:
48
  result = await extract_assets(
49
  url=req.url,
@@ -55,6 +41,9 @@ async def extract_assets_endpoint(req: AssetExtractRequest) -> AssetExtractRespo
55
  return result
56
  except AssetExtractError as exc:
57
  _log_response(req, 502, "asset_extract_error", detail=str(exc))
 
 
 
58
  raise HTTPException(
59
  status_code=status.HTTP_502_BAD_GATEWAY,
60
  detail=ErrorResponse(
@@ -62,7 +51,8 @@ async def extract_assets_endpoint(req: AssetExtractRequest) -> AssetExtractRespo
62
  code=502,
63
  detail=str(exc),
64
  request_id=req_id,
65
- ).model_dump_json(),
 
66
  ) from exc
67
  except Exception as exc:
68
  _log_response(req, 500, "unexpected_error", detail=str(exc))
@@ -73,10 +63,10 @@ async def extract_assets_endpoint(req: AssetExtractRequest) -> AssetExtractRespo
73
  code=500,
74
  detail=str(exc),
75
  request_id=req_id,
76
- ).model_dump_json(),
77
  ) from exc
78
 
79
 
80
  @router.get("/health")
81
  async def health_check() -> dict[str, str]:
82
- return {"status": "ok", "endpoint": "/assets"}
 
1
+ """POST /assets β€” extract image/video/audio/svg-icon/font assets from a URL."""
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
  import logging
4
  import uuid
 
7
 
8
  from app.schemas import AssetExtractRequest, AssetExtractResponse, ErrorResponse
9
  from app.services.asset_service import AssetExtractError, extract_assets
10
+ from app.services.fetcher import FetchError
11
 
12
  router = APIRouter()
13
 
14
 
15
  def _log_request(req: AssetExtractRequest, phase: str, **extra) -> None:
 
16
  logger = logging.getLogger(__name__)
17
  logger.info("request phase=%s id=%s url=%r groups=%r enrich=%s include_data_uris=%s extra=%r",
18
  phase, req._request_id or "?", req.url, req.groups, req.enrich,
 
20
 
21
 
22
  def _log_response(req: AssetExtractRequest, status_code: int, phase: str, **extra) -> None:
 
23
  logger = logging.getLogger(__name__)
24
  logger.info("response phase=%s status=%s id=%s url=%r extra=%r",
25
  phase, status_code, req._request_id or "?", req.url, extra)
 
30
  """Extract assets from a URL, grouped by category."""
31
  _log_request(req, "start")
32
  req_id = req._request_id or str(uuid.uuid4())
 
33
  try:
34
  result = await extract_assets(
35
  url=req.url,
 
41
  return result
42
  except AssetExtractError as exc:
43
  _log_response(req, 502, "asset_extract_error", detail=str(exc))
44
+ stages = None
45
+ if hasattr(exc, '__cause__') and isinstance(exc.__cause__, FetchError):
46
+ stages = exc.__cause__.stages
47
  raise HTTPException(
48
  status_code=status.HTTP_502_BAD_GATEWAY,
49
  detail=ErrorResponse(
 
51
  code=502,
52
  detail=str(exc),
53
  request_id=req_id,
54
+ stages=stages,
55
+ ).model_dump(),
56
  ) from exc
57
  except Exception as exc:
58
  _log_response(req, 500, "unexpected_error", detail=str(exc))
 
63
  code=500,
64
  detail=str(exc),
65
  request_id=req_id,
66
+ ).model_dump(),
67
  ) from exc
68
 
69
 
70
  @router.get("/health")
71
  async def health_check() -> dict[str, str]:
72
+ return {"status": "ok", "endpoint": "/assets"}