feat(api): document debug endpoints in OpenAPI spec

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Virgil 2026-04-02 02:24:27 +00:00
parent d803ac8f3b
commit 41615bbe47
3 changed files with 135 additions and 0 deletions

View file

@ -35,6 +35,8 @@ type SpecBuilder struct {
LicenseURL string
ExternalDocsDescription string
ExternalDocsURL string
PprofEnabled bool
ExpvarEnabled bool
}
type preparedRouteGroup struct {
@ -197,6 +199,14 @@ func (sb *SpecBuilder) buildPaths(groups []preparedRouteGroup) map[string]any {
paths[ssePath] = ssePathItem(ssePath, operationIDs)
}
if sb.PprofEnabled {
paths["/debug/pprof"] = pprofPathItem(operationIDs)
}
if sb.ExpvarEnabled {
paths["/debug/vars"] = expvarPathItem(operationIDs)
}
for _, g := range groups {
for _, rd := range g.descs {
fullPath := joinOpenAPIPath(g.group.BasePath(), rd.Path)
@ -598,6 +608,14 @@ func (sb *SpecBuilder) buildTags(groups []preparedRouteGroup) []map[string]any {
seen["events"] = true
}
if (sb.PprofEnabled || sb.ExpvarEnabled) && !seen["debug"] {
tags = append(tags, map[string]any{
"name": "debug",
"description": "Runtime debug endpoints",
})
seen["debug"] = true
}
for _, g := range groups {
name := strings.TrimSpace(g.group.Name())
if name != "" && !seen[name] {
@ -703,6 +721,113 @@ func ssePathItem(path string, operationIDs map[string]int) map[string]any {
}
}
func pprofPathItem(operationIDs map[string]int) map[string]any {
return map[string]any{
"get": map[string]any{
"summary": "pprof index",
"description": "Lists the available Go runtime profiles",
"tags": []string{"debug"},
"operationId": operationID("get", "/debug/pprof", operationIDs),
"security": []any{
map[string]any{
"bearerAuth": []any{},
},
},
"responses": map[string]any{
"200": map[string]any{
"description": "pprof index",
"content": map[string]any{
"text/html": map[string]any{
"schema": map[string]any{
"type": "string",
},
},
},
"headers": standardResponseHeaders(),
},
"401": map[string]any{
"description": "Unauthorised",
"content": map[string]any{
"application/json": map[string]any{
"schema": map[string]any{
"type": "object",
"additionalProperties": true,
},
},
},
"headers": standardResponseHeaders(),
},
"403": map[string]any{
"description": "Forbidden",
"content": map[string]any{
"application/json": map[string]any{
"schema": map[string]any{
"type": "object",
"additionalProperties": true,
},
},
},
"headers": standardResponseHeaders(),
},
},
},
}
}
func expvarPathItem(operationIDs map[string]int) map[string]any {
return map[string]any{
"get": map[string]any{
"summary": "Runtime metrics",
"description": "Returns expvar metrics as JSON",
"tags": []string{"debug"},
"operationId": operationID("get", "/debug/vars", operationIDs),
"security": []any{
map[string]any{
"bearerAuth": []any{},
},
},
"responses": map[string]any{
"200": map[string]any{
"description": "Runtime metrics",
"content": map[string]any{
"application/json": map[string]any{
"schema": map[string]any{
"type": "object",
"additionalProperties": true,
},
},
},
"headers": standardResponseHeaders(),
},
"401": map[string]any{
"description": "Unauthorised",
"content": map[string]any{
"application/json": map[string]any{
"schema": map[string]any{
"type": "object",
"additionalProperties": true,
},
},
},
"headers": standardResponseHeaders(),
},
"403": map[string]any{
"description": "Forbidden",
"content": map[string]any{
"application/json": map[string]any{
"schema": map[string]any{
"type": "object",
"additionalProperties": true,
},
},
},
"headers": standardResponseHeaders(),
},
},
},
}
}
func graphqlRequestSchema() map[string]any {
return map[string]any{
"type": "object",

View file

@ -36,6 +36,8 @@ func (e *Engine) OpenAPISpecBuilder() *SpecBuilder {
if e.sseBroker != nil {
builder.SSEPath = resolveSSEPath(e.ssePath)
}
builder.PprofEnabled = e.pprofEnabled
builder.ExpvarEnabled = e.expvarEnabled
return builder
}

View file

@ -25,6 +25,8 @@ func TestEngine_Good_OpenAPISpecBuilderCarriesEngineMetadata(t *testing.T) {
api.WithGraphQL(newTestSchema(), api.WithGraphQLPath("/gql")),
api.WithSSE(broker),
api.WithSSEPath("/events"),
api.WithPprof(),
api.WithExpvar(),
)
if err != nil {
t.Fatalf("unexpected error: %v", err)
@ -107,4 +109,10 @@ func TestEngine_Good_OpenAPISpecBuilderCarriesEngineMetadata(t *testing.T) {
if _, ok := paths["/events"]; !ok {
t.Fatal("expected SSE path from engine metadata in generated spec")
}
if _, ok := paths["/debug/pprof"]; !ok {
t.Fatal("expected pprof path from engine metadata in generated spec")
}
if _, ok := paths["/debug/vars"]; !ok {
t.Fatal("expected expvar path from engine metadata in generated spec")
}
}