phase 2 (part 1): OpenAPI-generated API server, first 9 endpoints
- api/openapi.yaml converted 3.1 → 3.0.3 (oapi-codegen/kin-openapi supports 3.0; nullable syntax + example keywords), still redocly-clean - oapi-codegen (v2.4.1, strict server + chi) generates internal/httpapi/gen from the spec; `make generate` wired - internal/httpapi: chi router, /healthz (unauthenticated, SG18), RFC 9457 problem+json mapping from domain sentinels (SG11), 5xx detail logged server-side only, request logging with request IDs, graceful shutdown (SG4), interim static bearer auth (constant-time; dev-open when no token; OIDC JWT still to come in Phase 2) - Implemented: listEntities (type filter walks the hierarchy, keyset pagination), getEntity (UUID or slug, ETag), getEntityRelations, getBlastRadius, getGraph (nodes+edges for UIs), getOntology, listSignals, getFleetHealth, exportSeeds. Remaining 38 ops return 501 problem+json stubs (compiler-enforced interface completeness) - `oikos api` role live: migrate-on-start, serves :8090 - 15 API integration tests (auth, pagination, hierarchy filter, ETag, 404/501 problem shapes, graph, export) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -8,8 +8,11 @@ import (
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"net/http"
|
||||
|
||||
"github.com/dtoro/oikos/internal/config"
|
||||
"github.com/dtoro/oikos/internal/db"
|
||||
"github.com/dtoro/oikos/internal/httpapi"
|
||||
"github.com/dtoro/oikos/internal/observability"
|
||||
"github.com/jackc/pgx/v5"
|
||||
)
|
||||
@@ -50,8 +53,10 @@ func main() {
|
||||
os.Exit(1)
|
||||
}
|
||||
case "api":
|
||||
slog.Info("api role not yet implemented (Phase 2)")
|
||||
os.Exit(1)
|
||||
if err := runAPI(ctx, cfg); err != nil {
|
||||
slog.Error("api failed", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
case "scheduler":
|
||||
slog.Info("scheduler role not yet implemented (Phase 3)")
|
||||
os.Exit(1)
|
||||
@@ -194,6 +199,24 @@ func runSeed(ctx context.Context, cfg config.Config) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func runAPI(ctx context.Context, cfg config.Config) error {
|
||||
pool, err := db.New(ctx, cfg.DatabaseURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer pool.Close()
|
||||
|
||||
if err := pool.Migrate(ctx); err != nil {
|
||||
return fmt.Errorf("migrations: %w", err)
|
||||
}
|
||||
|
||||
err = httpapi.ListenAndServe(ctx, pool, cfg)
|
||||
if err == http.ErrServerClosed {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func runExport(ctx context.Context, cfg config.Config) error {
|
||||
pool, err := db.New(ctx, cfg.DatabaseURL)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user