Control Plane HTTP API
Responsibility
The control plane exposes a small REST API over feature flags. It is the only
write path for flag state: the dashboard (frontend gateway) and any external
automation talk to these endpoints, and the data plane (polling clients) reads
them. All handlers live in internal/http/flags.go (FlagsHandler) and are
wired into the mux by Register.
Entrypoints
cmd/flaggo/main.gobuilds aFlagsHandleronly when storage is usable (case "memory"or successful PostgresMigrate); otherwise the process runs in degraded mode with no flag routes.- Routes are registered in
internal/http/router.goviad.Flags.Register(mux)only whend.Flags != nil.
Endpoints
| Method | Path | Purpose |
|---|---|---|
POST |
/flags |
Create a flag |
GET |
/flags |
List all flags (sorted by name) |
GET |
/flags/{name} |
Get one flag |
PUT |
/flags/{name} |
Replace a flag |
DELETE |
/flags/{name} |
Delete a flag |
POST |
/flags/{name}/kill-switch |
Toggle/force kill switch |
PUT |
/flags/{name}/rollout |
Set rollout percentage |
Health and metrics endpoints (/healthz, /readyz, /metrics) are served
separately; see openwiki/operations/health-and-readiness.md.
Request flow
- Request enters the mux in
internal/http/router.go. - Middleware chain (outermost first):
RequestID→Recovery→Logging→Metrics→ mux. Seeopenwiki/api/middleware.md. - Handler decodes JSON with
DisallowUnknownFields, validates the model, calls theStore, and re-reads the persisted row before responding.
Contracts and invariants
model.Flagrequires a non-emptyNameandRolloutPercentin[0,100](internal/model/flag.goValidate).- Create rejects duplicates with
409 Conflict(model.ErrAlreadyExists). - Get/Update/Delete/Rollout on a missing flag return
404 Not Found. - Update forces the path name onto the body (
f.Name = name), so the URL is authoritative. - Kill switch accepts an optional
{"kill_switch": bool}; when omitted it toggles the current value. - Rollout validates the new percentage before persisting.
Failure behavior
- Malformed or unknown JSON fields →
400 Bad Request. - Validation failure →
400 Bad Request. - Store errors other than not-found/already-exists →
500 Internal Server Errorwith a generic message; details go to the slog logger with the request id. - In degraded mode (no store), flag routes are simply not registered, so
requests hit the default mux and return
404.
Configuration
No endpoint-specific configuration. The base path is fixed; the frontend
gateway rewrites /api/<path> to /<path> (see
openwiki/frontend/gateway.md).
Representative tests
internal/http/flags_test.go exercises create/list/get/update/delete and
kill-switch/rollout against the in-memory store. See
openwiki/testing/test-strategy.md.