feat: add proxy query endpoint with filtering and sorting

This commit is contained in:
agatha 2026-03-14 16:19:00 -04:00
parent a38d6a5e36
commit 2ba579754c
3 changed files with 75 additions and 2 deletions

View File

@ -9,7 +9,8 @@ from proxy_pool.config import get_settings
from proxy_pool.db.session import create_session_factory
from proxy_pool.plugins.discovery import discover_plugins
from proxy_pool.plugins.registry import PluginRegistry
from proxy_pool.proxy.router import router as proxy_router
from proxy_pool.proxy.router import proxy_router
from proxy_pool.proxy.router import router as source_router
logger = logging.getLogger(__name__)
@ -60,6 +61,7 @@ def create_app() -> FastAPI:
)
app.include_router(health_router)
app.include_router(source_router)
app.include_router(proxy_router)
return app

View File

@ -6,14 +6,19 @@ from sqlalchemy.ext.asyncio import AsyncSession
from proxy_pool.common.dependencies import get_db, get_registry
from proxy_pool.plugins.registry import PluginRegistry
from proxy_pool.proxy.models import ProxySource
from proxy_pool.proxy.models import Proxy, ProxySource
from proxy_pool.proxy.schemas import (
ProxyListParams,
ProxyListResponse,
ProxyResponse,
ProxySourceCreate,
ProxySourceResponse,
ProxySourceUpdate,
)
from proxy_pool.proxy.service import query_proxies
router = APIRouter(prefix="/sources", tags=["sources"])
proxy_router = APIRouter(prefix="/proxies", tags=["proxies"])
@router.get("", response_model=list[ProxySourceResponse])
@ -124,3 +129,47 @@ async def delete_source(
)
await db.delete(source)
await db.commit()
@proxy_router.get("", response_model=ProxyListResponse)
async def list_proxies(
params: ProxyListParams = Depends(),
db: AsyncSession = Depends(get_db),
) -> ProxyListResponse:
proxies, total = await query_proxies(
db,
status=params.status,
protocol=params.protocol,
anonymity=params.anonymity,
country=params.country,
min_score=params.min_score,
max_latency_ms=params.max_latency_ms,
min_uptime_pct=params.min_uptime_pct,
verified_within_minutes=params.verified_within_minutes,
sort_by=params.sort_by,
sort_order=params.sort_order,
limit=params.limit,
offset=params.offset,
)
return ProxyListResponse(
items=[ProxyResponse.model_validate(p) for p in proxies],
total_count=total,
limit=params.limit,
offset=params.offset,
)
@proxy_router.get("/{proxy_id}", response_model=ProxyResponse)
async def get_proxy(
proxy_id: UUID,
db: AsyncSession = Depends(get_db),
) -> ProxyResponse:
proxy = await db.get(Proxy, proxy_id)
if proxy is None:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Proxy not found",
) from None
return ProxyResponse.model_validate(proxy)

View File

@ -51,3 +51,25 @@ class ProxyResponse(BaseModel):
last_checked_at: datetime | None
first_seen_at: datetime
created_at: datetime
class ProxyListParams(BaseModel):
status: ProxyStatus | None = None
protocol: ProxyProtocol | None = None
anonymity: AnonymityLevel | None = None
country: str | None = Field(default=None, min_length=2, max_length=2)
min_score: float | None = Field(default=None, ge=0.0, le=1.0)
max_latency_ms: float | None = Field(default=None, gt=0)
min_uptime_pct: float | None = Field(default=None, ge=0.0, le=100.0)
verified_within_minutes: int | None = Field(default=None, gt=0)
sort_by: str = Field(default="score")
sort_order: str = Field(default="desc", pattern="^(asc|desc)$")
limit: int = Field(default=50, ge=1, le=200)
offset: int = Field(default=0, ge=0)
class ProxyListResponse(BaseModel):
items: list[ProxyResponse]
total_count: int
limit: int
offset: int