feat: upgrade app template server from vet reference
- integer-id persistence: memory (default, zero-dep) + mongo_int repos
selected by REPO_BACKEND via create_repo factory
- interfaces/_common.py: shared svc/dump/paginate/expand_ref/read_or_404
helpers; item/job routes rebuilt on them (paginated {total,items} lists,
PUT replace, 204 deletes, int path ids)
- interfaces/system: /health liveness probe (public)
- openapi.yaml rewritten to 3.1.0 with x- extensions on Item/Job
(x-resource, x-primary-key, x-display-format, x-list-columns, x-label,
x-order, x-hidden, x-filterable, x-sortable, x-autocomplete), auth-server
x-* securityScheme wiring, shared error responses
- config/init/main: REPO_BACKEND knob, load_dotenv before spec build
Verified: 7/7 tests pass; live smoke test (/health ok, 401 without token)
This commit is contained in:
@@ -2,41 +2,89 @@
|
||||
|
||||
Item route handlers — names must match openapi.yaml operationIds.
|
||||
"""
|
||||
from fastapi import Request
|
||||
from fastapi.responses import JSONResponse
|
||||
from fastapi import Request, Response
|
||||
|
||||
from domain.item.models import Item
|
||||
from interfaces._common import delete_or_404, dump, paginate, read_or_404, svc
|
||||
|
||||
|
||||
def svc(request: Request):
|
||||
"""Resolve the item CRUD service from app state."""
|
||||
return request.app.state.db_resources["item_svc"]
|
||||
async def list_items(request: Request, limit: int = 20, offset: int = 0) -> dict:
|
||||
"""List items (paginated). ``limit=0`` returns all remaining items.
|
||||
|
||||
Args:
|
||||
request (Request): Incoming request.
|
||||
limit (int): Page size. Defaults to 20.
|
||||
offset (int): Items to skip. Defaults to 0.
|
||||
|
||||
Returns:
|
||||
dict: ``{"total": int, "items": list[Item]}``.
|
||||
"""
|
||||
docs = await svc(request, "item").search({})
|
||||
return paginate([dump(d) for d in docs], limit, offset)
|
||||
|
||||
|
||||
async def create_item(request: Request, body: dict):
|
||||
"""Create an item from the request body."""
|
||||
data = body.model_dump() if hasattr(body, "model_dump") else dict(body)
|
||||
doc = await svc(request).create(Item(**data))
|
||||
return JSONResponse(status_code=201, content=doc.model_dump(mode="json", by_alias=True))
|
||||
async def create_item(request: Request, body: dict, response: Response) -> dict:
|
||||
"""Create an item.
|
||||
|
||||
Args:
|
||||
request (Request): Incoming request.
|
||||
body (dict): Item fields (``id`` ignored).
|
||||
response (Response): Response object; set to 201 on success.
|
||||
|
||||
Returns:
|
||||
dict: The created item.
|
||||
"""
|
||||
response.status_code = 201
|
||||
body.pop("id", None)
|
||||
doc = await svc(request, "item").create(body)
|
||||
return dump(doc)
|
||||
|
||||
|
||||
async def get_item(request: Request, id: str):
|
||||
"""Fetch one item by id."""
|
||||
doc = await svc(request).read(id)
|
||||
if doc is None:
|
||||
return JSONResponse(status_code=404, content={"detail": "item not found"})
|
||||
return doc.model_dump(mode="json", by_alias=True)
|
||||
async def get_item(request: Request, id: int) -> dict:
|
||||
"""Fetch one item by id.
|
||||
|
||||
Args:
|
||||
request (Request): Incoming request.
|
||||
id (int): Item identifier.
|
||||
|
||||
Returns:
|
||||
dict: The item document.
|
||||
|
||||
Raises:
|
||||
HTTPException: 404 when the item does not exist.
|
||||
"""
|
||||
return dump(await read_or_404(svc(request, "item"), id, "item"))
|
||||
|
||||
|
||||
async def list_items(request: Request):
|
||||
"""List all items."""
|
||||
docs = await svc(request).search({})
|
||||
return [d.model_dump(mode="json", by_alias=True) for d in docs]
|
||||
async def update_item(request: Request, id: int, body: dict) -> dict:
|
||||
"""Replace an item by id.
|
||||
|
||||
Args:
|
||||
request (Request): Incoming request.
|
||||
id (int): Item identifier.
|
||||
body (dict): Full replacement payload.
|
||||
|
||||
Returns:
|
||||
dict: The updated item.
|
||||
|
||||
Raises:
|
||||
HTTPException: 404 when the item does not exist.
|
||||
"""
|
||||
await read_or_404(svc(request, "item"), id, "item")
|
||||
body.pop("id", None)
|
||||
doc = await svc(request, "item").update(id, body)
|
||||
return dump(doc)
|
||||
|
||||
|
||||
async def delete_item(request: Request, id: str):
|
||||
"""Delete one item by id."""
|
||||
ok = await svc(request).delete(id)
|
||||
if not ok:
|
||||
return JSONResponse(status_code=404, content={"detail": "item not found"})
|
||||
return {"deleted": True}
|
||||
async def delete_item(request: Request, id: int, response: Response) -> None:
|
||||
"""Delete an item by id.
|
||||
|
||||
Args:
|
||||
request (Request): Incoming request.
|
||||
id (int): Item identifier.
|
||||
response (Response): Response object; set to 204 on success.
|
||||
|
||||
Raises:
|
||||
HTTPException: 404 when the item does not exist.
|
||||
"""
|
||||
await delete_or_404(svc(request, "item"), id, "item")
|
||||
response.status_code = 204
|
||||
|
||||
Reference in New Issue
Block a user