84 lines
2.1 KiB
Python
84 lines
2.1 KiB
Python
import json
|
|
|
|
from fastapi import APIRouter, Request, status
|
|
from fastapi.responses import JSONResponse
|
|
|
|
from core.api.publisher import IngestionQueueFull, KafkaPublishError
|
|
from core.domain.errors import CDRProcessingError
|
|
from core.domain.validation import parse_raw_cdr
|
|
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.post(
|
|
"/cdr/raw",
|
|
status_code=status.HTTP_202_ACCEPTED,
|
|
)
|
|
async def ingest_raw_cdr(request: Request) -> JSONResponse:
|
|
try:
|
|
payload = await request.json()
|
|
|
|
except (json.JSONDecodeError, UnicodeDecodeError) as exc:
|
|
return JSONResponse(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
content={
|
|
"error": "invalid_json",
|
|
"detail": str(exc),
|
|
},
|
|
)
|
|
|
|
if not isinstance(payload, dict):
|
|
return JSONResponse(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
content={
|
|
"error": "invalid_payload",
|
|
"detail": "JSON payload must be an object.",
|
|
},
|
|
)
|
|
|
|
try:
|
|
raw_cdr = parse_raw_cdr(payload)
|
|
|
|
except CDRProcessingError as exc:
|
|
return JSONResponse(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
content={
|
|
"error": exc.reason.value,
|
|
"detail": exc.detail,
|
|
"failed_field": exc.failed_field,
|
|
},
|
|
)
|
|
|
|
try:
|
|
await request.app.state.publisher.publish(
|
|
payload,
|
|
key=raw_cdr.raw_id,
|
|
)
|
|
|
|
except IngestionQueueFull:
|
|
return JSONResponse(
|
|
status_code=status.HTTP_429_TOO_MANY_REQUESTS,
|
|
content={
|
|
"error": "backpressure",
|
|
"detail": "Ingestion queue is full.",
|
|
},
|
|
)
|
|
|
|
except KafkaPublishError as exc:
|
|
return JSONResponse(
|
|
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
|
content={
|
|
"error": "kafka_unavailable",
|
|
"detail": str(exc),
|
|
},
|
|
)
|
|
|
|
return JSONResponse(
|
|
status_code=status.HTTP_202_ACCEPTED,
|
|
content={
|
|
"status": "accepted",
|
|
"raw_id": raw_cdr.raw_id,
|
|
},
|
|
)
|