feat: expose runtime OpenAPI contract

Register typed API operations and serve an always-current OpenAPI document without a generation command or committed generated artifact.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Daniel Noulet 2026-10-01 18:54:02 +02:00
parent 314c783659
commit 045f0b7cf2
9 changed files with 533 additions and 76 deletions

View file

@ -20,6 +20,10 @@ var safeSchemaRegex = regexp.MustCompile(`^[a-zA-Z0-9_:-]+$`)
func TenantSchemaMiddleware(db *gorm.DB) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/api/health" || r.URL.Path == "/api/openapi.json" {
next.ServeHTTP(w, r)
return
}
tenantID := r.Header.Get("X-Tenant-Id")
if tenantID == "" {
w.Header().Set("Content-Type", "application/json")

View file

@ -0,0 +1,35 @@
package middleware
import (
"net/http"
"net/http/httptest"
"testing"
)
func TestTenantMiddlewareAllowsSystemEndpointsWithoutTenant(t *testing.T) {
next := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
})
handler := TenantSchemaMiddleware(nil)(next)
for _, path := range []string{"/api/health", "/api/openapi.json"} {
response := httptest.NewRecorder()
handler.ServeHTTP(response, httptest.NewRequest(http.MethodGet, path, nil))
if response.Code != http.StatusOK {
t.Fatalf("%s returned %d", path, response.Code)
}
}
}
func TestTenantMiddlewareStillRequiresTenantForDataEndpoints(t *testing.T) {
handler := TenantSchemaMiddleware(nil)(http.HandlerFunc(func(http.ResponseWriter, *http.Request) {
t.Fatal("data endpoint reached without a tenant")
}))
response := httptest.NewRecorder()
handler.ServeHTTP(response, httptest.NewRequest(http.MethodGet, "/api/jobs", nil))
if response.Code != http.StatusBadRequest {
t.Fatalf("expected 400, got %d", response.Code)
}
}