generated from coulomb/repo-seed
optional FastAPI service skeleton
This commit is contained in:
123
src/kontextual_engine/api/app.py
Normal file
123
src/kontextual_engine/api/app.py
Normal file
@@ -0,0 +1,123 @@
|
||||
"""Versioned FastAPI service skeleton.
|
||||
|
||||
The service layer is intentionally thin: route handlers translate HTTP
|
||||
requests into service/runtime contracts and must not own domain behavior.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from importlib import metadata
|
||||
from typing import Any
|
||||
|
||||
from kontextual_engine.adapters.memory import InMemoryAssetRegistryRepository
|
||||
from kontextual_engine.core import utc_now
|
||||
from kontextual_engine.ports import AssetRegistryRepository
|
||||
|
||||
|
||||
API_VERSION = "v1"
|
||||
OPENAPI_VERSION = "1.0.0"
|
||||
|
||||
|
||||
@dataclass
|
||||
class ServiceRuntime:
|
||||
repository: AssetRegistryRepository = field(default_factory=InMemoryAssetRegistryRepository)
|
||||
api_version: str = API_VERSION
|
||||
service_name: str = "kontextual-engine"
|
||||
started_at: str = field(default_factory=lambda: utc_now().isoformat())
|
||||
|
||||
@property
|
||||
def package_version(self) -> str:
|
||||
try:
|
||||
return metadata.version("kontextual-engine")
|
||||
except metadata.PackageNotFoundError:
|
||||
return "0.1.0"
|
||||
|
||||
def health(self) -> dict[str, Any]:
|
||||
return {
|
||||
"status": "ok",
|
||||
"service": self.service_name,
|
||||
"api_version": self.api_version,
|
||||
"package_version": self.package_version,
|
||||
"started_at": self.started_at,
|
||||
}
|
||||
|
||||
def readiness(self) -> dict[str, Any]:
|
||||
checks: dict[str, dict[str, Any]] = {}
|
||||
try:
|
||||
asset_count = len(self.repository.list_assets())
|
||||
checks["asset_registry"] = {
|
||||
"status": "ok",
|
||||
"repository": type(self.repository).__name__,
|
||||
"asset_count": asset_count,
|
||||
}
|
||||
except Exception as exc:
|
||||
checks["asset_registry"] = {
|
||||
"status": "error",
|
||||
"repository": type(self.repository).__name__,
|
||||
"error_type": type(exc).__name__,
|
||||
"message": str(exc),
|
||||
}
|
||||
ready = all(item["status"] == "ok" for item in checks.values())
|
||||
return {
|
||||
"status": "ready" if ready else "not_ready",
|
||||
"ready": ready,
|
||||
"service": self.service_name,
|
||||
"api_version": self.api_version,
|
||||
"checks": checks,
|
||||
}
|
||||
|
||||
def version(self) -> dict[str, Any]:
|
||||
return {
|
||||
"service": self.service_name,
|
||||
"api_version": self.api_version,
|
||||
"package_version": self.package_version,
|
||||
"openapi_version": OPENAPI_VERSION,
|
||||
}
|
||||
|
||||
|
||||
def create_app(runtime: ServiceRuntime | None = None):
|
||||
try:
|
||||
from fastapi import FastAPI
|
||||
except ImportError as exc: # pragma: no cover - exercised when optional extra is absent
|
||||
raise RuntimeError(
|
||||
"FastAPI service dependencies are not installed. Install kontextual-engine[service]."
|
||||
) from exc
|
||||
|
||||
runtime = runtime or ServiceRuntime()
|
||||
app = FastAPI(
|
||||
title="Kontextual Engine Service API",
|
||||
version=OPENAPI_VERSION,
|
||||
openapi_url="/openapi.json",
|
||||
docs_url="/docs",
|
||||
redoc_url="/redoc",
|
||||
)
|
||||
app.state.kontextual_runtime = runtime
|
||||
|
||||
@app.get("/health", tags=["system"])
|
||||
def health() -> dict[str, Any]:
|
||||
return runtime.health()
|
||||
|
||||
@app.get("/ready", tags=["system"])
|
||||
def ready() -> dict[str, Any]:
|
||||
return runtime.readiness()
|
||||
|
||||
@app.get("/version", tags=["system"])
|
||||
def version() -> dict[str, Any]:
|
||||
return runtime.version()
|
||||
|
||||
prefix = f"/api/{runtime.api_version}"
|
||||
|
||||
@app.get(f"{prefix}/health", tags=["system"])
|
||||
def versioned_health() -> dict[str, Any]:
|
||||
return runtime.health()
|
||||
|
||||
@app.get(f"{prefix}/ready", tags=["system"])
|
||||
def versioned_ready() -> dict[str, Any]:
|
||||
return runtime.readiness()
|
||||
|
||||
@app.get(f"{prefix}/version", tags=["system"])
|
||||
def versioned_version() -> dict[str, Any]:
|
||||
return runtime.version()
|
||||
|
||||
return app
|
||||
Reference in New Issue
Block a user