Harden RC7 API response contracts
GeoIntel release gates / Compile, test, contracts and builds (push) Canceled after 0s
GeoIntel release gates / Python and npm vulnerability policy (push) Canceled after 0s
GeoIntel release gates / GIS image, SBOM and container scan (push) Canceled after 0s

This commit is contained in:
Codex
2026-07-18 05:07:35 +02:00
parent 8e49b857dd
commit 0fae53a7de
36 changed files with 886 additions and 153 deletions
+39 -11
View File
@@ -7,7 +7,20 @@ from app.core.errors import AppError
from app.db.session import get_db
from app.models import Area, Project
from app.providers.registry import fetch_provider_data, get_provider, import_provider_dataset, list_provider_capabilities
from app.schemas import CoverageResolveRequest, ExternalFetchRequest, ExternalFetchResponse, ProviderImportRequest
from app.schemas import (
CoverageCatalogResponse,
CoverageResolveRequest,
CoverageResolveResponse,
Envelope,
ExternalFetchRequest,
ExternalFetchResponse,
ProviderCapabilitiesResponse,
ProviderCapabilityResponse,
ProviderImportRequest,
ProviderImportResponse,
ProviderLayersResponse,
ProviderStatusResponse,
)
from app.services.coverage_registry_service import CoverageRegistryService
from app.utils.response import envelope
@@ -40,19 +53,19 @@ def _provider_payload(provider_name: str) -> dict:
return get_provider(provider_name).capability.to_dict()
@router.get("/providers")
@router.get("/providers", response_model=Envelope[ProviderCapabilitiesResponse])
def list_external_providers() -> dict:
return envelope({
"providers": [provider.to_dict() for provider in list_provider_capabilities()],
})
@router.get("/coverage/catalog")
@router.get("/coverage/catalog", response_model=Envelope[CoverageCatalogResponse])
def get_coverage_catalog() -> dict:
return envelope(CoverageRegistryService.catalog().model_dump())
@router.post("/coverage/resolve")
@router.post("/coverage/resolve", response_model=Envelope[CoverageResolveResponse])
def resolve_project_coverage(payload: CoverageResolveRequest, db: Session = Depends(get_db)) -> dict:
result = CoverageRegistryService.resolve(
db,
@@ -63,19 +76,28 @@ def resolve_project_coverage(payload: CoverageResolveRequest, db: Session = Depe
return envelope(result.model_dump())
@router.get("/providers/capabilities")
@router.get(
"/providers/capabilities",
response_model=Envelope[ProviderCapabilitiesResponse],
)
def get_external_provider_capabilities() -> dict:
return envelope({
"providers": [provider.to_dict() for provider in list_provider_capabilities()],
})
@router.get("/providers/{provider_name}")
@router.get(
"/providers/{provider_name}",
response_model=Envelope[ProviderCapabilityResponse],
)
def get_external_provider(provider_name: str) -> dict:
return envelope(_provider_payload(provider_name))
@router.get("/providers/{provider_name}/layers")
@router.get(
"/providers/{provider_name}/layers",
response_model=Envelope[ProviderLayersResponse],
)
def get_external_provider_layers(provider_name: str) -> dict:
provider = get_provider(provider_name)
return envelope({
@@ -84,7 +106,10 @@ def get_external_provider_layers(provider_name: str) -> dict:
})
@router.get("/providers/{provider_name}/status")
@router.get(
"/providers/{provider_name}/status",
response_model=Envelope[ProviderStatusResponse],
)
def get_external_provider_status(provider_name: str) -> dict:
provider = get_provider(provider_name)
return envelope({
@@ -95,7 +120,10 @@ def get_external_provider_status(provider_name: str) -> dict:
})
@router.post("/providers/{provider_name}/import")
@router.post(
"/providers/{provider_name}/import",
response_model=Envelope[ProviderImportResponse],
)
def import_external_provider_dataset(provider_name: str, payload: ProviderImportRequest) -> dict:
result = import_provider_dataset(
provider_name=provider_name,
@@ -125,14 +153,14 @@ def _run_fetch(payload: ExternalFetchRequest, provider_name: str) -> ExternalFet
)
@router.post("/osm/fetch")
@router.post("/osm/fetch", response_model=Envelope[ExternalFetchResponse])
def fetch_osm(payload: ExternalFetchRequest, db: Session = Depends(get_db)) -> dict:
_assert_project_exists(db, payload.project_id)
_validate_area_in_project(db, payload.project_id, payload.area_id)
return envelope(_run_fetch(payload, "osm").model_dump())
@router.post("/grb/fetch")
@router.post("/grb/fetch", response_model=Envelope[ExternalFetchResponse])
def fetch_grb(payload: ExternalFetchRequest, db: Session = Depends(get_db)) -> dict:
_assert_project_exists(db, payload.project_id)
_validate_area_in_project(db, payload.project_id, payload.area_id)