Summary
Consolidate all HTTP API routes into application/api/v1/ with thin routers that delegate to domain Command/Query handlers. Currently, routers are scattered across domain/*/api/rest/ folders, which violates the principle that domains should be protocol-agnostic.
Current State
osa/
domain/
search/api/rest/routes.py # Router inside domain
deposition/api/rest/routes.py # Router inside domain
application/api/rest/
routes/health.py # Application-level routes
Proposed Structure
osa/
application/
api/
v1/
routes/
__init__.py # Combines all routers
health.py # Health checks
depositions.py # HTTP → Command/Query handlers
records.py
search.py
validation.py
errors.py # Centralized error transformation (DomainError → HTTPException)
domain/
deposition/
command/
create.py # CreateDeposition, CreateDepositionHandler
submit.py # SubmitDeposition, SubmitDepositionHandler
query/
get.py # GetDeposition, GetDepositionHandler
service/
deposition.py # DepositionService (used by handlers)
# NO api/ folder - domains are protocol-agnostic
Thin Router Pattern
Routers should only handle:
- Request parsing (HTTP → Command/Query DTO)
- Handler invocation via Dishka
- Response formatting (Result → HTTP response)
- Error transformation (DomainError → HTTPException)
Example:
# application/api/v1/routes/depositions.py
from dishka.integrations.fastapi import FromDishka
from fastapi import APIRouter
from osa.domain.deposition.command.create import CreateDeposition, CreateDepositionHandler
from osa.application.api.v1.errors import map_domain_error
router = APIRouter(prefix="/depositions", tags=["depositions"])
@router.post("/")
async def create_deposition(
request: CreateDepositionRequest,
handler: FromDishka[CreateDepositionHandler],
) -> DepositionResponse:
try:
cmd = CreateDeposition(metadata=request.metadata)
result = await handler.run(cmd)
return DepositionResponse(srn=str(result.srn))
except DomainError as e:
raise map_domain_error(e)
Tasks
Summary
Consolidate all HTTP API routes into
application/api/v1/with thin routers that delegate to domain Command/Query handlers. Currently, routers are scattered acrossdomain/*/api/rest/folders, which violates the principle that domains should be protocol-agnostic.Current State
Proposed Structure
Thin Router Pattern
Routers should only handle:
Example:
Tasks
application/api/v1/errors.pywithmap_domain_error()functiondomain/search/api/rest/routes.py→application/api/v1/routes/search.pydomain/deposition/api/rest/routes.py→application/api/v1/routes/depositions.pydomain/*/api/directoriesapplication/api/rest/app.pyto import from new locations