listing-radar/custom_search_api/views.py

60 lines
2.1 KiB
Python

import logging
from typing import Optional
from fastapi import APIRouter, HTTPException, Query
from fastapi.responses import JSONResponse
import httpx
from .service import CustomSearchService
from .serializers import SearchResponse, SearchResultItem
app_router = APIRouter()
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
log = logging.getLogger(__name__)
@app_router.get("/search", response_model=SearchResponse)
async def search_endpoint(
q: str = Query(..., description="Search query string"),
num: int = Query(10, ge=1, le=10, description="Number of results to return (1-10)"),
start: int = Query(1, ge=1, description="Start index for pagination"),
):
try:
service = CustomSearchService()
data = await service.search(query=q, num=num, start=start)
items = [
SearchResultItem(
title=item.get("title"),
link=item.get("link"),
displayLink=item.get("displayLink"),
snippet=item.get("snippet"),
formattedUrl=item.get("formattedUrl"),
pagemap=item.get("pagemap"),
)
for item in data.get("items", [])
]
search_info = data.get("searchInformation", {}) or {}
return SearchResponse(
query=q,
total_results=search_info.get("totalResults"),
search_time=search_info.get("searchTime"),
items=items,
raw=data,
)
except ValueError as e:
log.error(f"Configuration error: {e}")
raise HTTPException(status_code=500, detail=str(e))
except httpx.HTTPStatusError as e:
log.error(f"Google CSE returned {e.response.status_code}: {e.response.text}")
raise HTTPException(status_code=e.response.status_code, detail=e.response.text)
except httpx.RequestError as e:
log.error(f"Network error calling Google CSE: {e}")
raise HTTPException(status_code=502, detail=f"Upstream request failed: {e}")
except Exception as e:
log.error(f"Unexpected error: {e}")
raise HTTPException(status_code=500, detail=str(e))