Files
crucible-agent-build-fastap…/app/main.py

80 lines
3.0 KiB
Python

from uuid import UUID
from fastapi import FastAPI, HTTPException, Response, status
from app.checker import EndpointChecker
from app.config import Settings, get_settings
from app.logging_config import configure_logging
from app.models import Health, Monitor, MonitorCreate, MonitorUpdate, StatusSnapshot
from app.store import MonitorStore
def create_app(
settings: Settings | None = None, store: MonitorStore | None = None,
checker: EndpointChecker | None = None,
) -> FastAPI:
config = settings or get_settings()
configure_logging(config.log_level)
state = store or MonitorStore()
service = checker or EndpointChecker(config)
api = FastAPI(title=config.app_name, version="1.0.0")
async def existing(monitor_id: UUID) -> Monitor:
monitor = await state.get(monitor_id)
if monitor is None:
raise HTTPException(status_code=404, detail="monitor not found")
return monitor
@api.post("/monitors", response_model=Monitor, status_code=201)
async def create_monitor(body: MonitorCreate) -> Monitor:
return await state.create(body)
@api.get("/monitors", response_model=list[Monitor])
async def list_monitors() -> list[Monitor]:
return await state.list()
@api.get("/monitors/{monitor_id}", response_model=Monitor)
async def get_monitor(monitor_id: UUID) -> Monitor:
return await existing(monitor_id)
@api.put("/monitors/{monitor_id}", response_model=Monitor)
async def update_monitor(monitor_id: UUID, body: MonitorUpdate) -> Monitor:
monitor = await state.update(monitor_id, body)
if monitor is None:
raise HTTPException(status_code=404, detail="monitor not found")
return monitor
@api.delete("/monitors/{monitor_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_monitor(monitor_id: UUID) -> Response:
if not await state.delete(monitor_id):
raise HTTPException(status_code=404, detail="monitor not found")
return Response(status_code=204)
@api.post("/monitors/{monitor_id}/check", response_model=StatusSnapshot)
async def check_monitor(monitor_id: UUID) -> StatusSnapshot:
pending = await state.begin_check(monitor_id)
if pending is None:
raise HTTPException(status_code=404, detail="monitor not found")
monitor, revision = pending
result = await service.check(str(monitor.id), str(monitor.url))
await state.finish_check(monitor_id, revision, result)
return result
@api.get("/monitors/{monitor_id}/status", response_model=StatusSnapshot)
async def current_status(monitor_id: UUID) -> StatusSnapshot:
return (await existing(monitor_id)).status
@api.get("/health/live", response_model=Health)
async def liveness() -> Health:
return Health(status="ok")
@api.get("/health/ready", response_model=Health)
async def readiness() -> Health:
await state.list()
return Health(status="ready")
return api
app = create_app()