diff --git a/openapi.go b/openapi.go index 425e1eb..e769e1c 100644 --- a/openapi.go +++ b/openapi.go @@ -919,6 +919,9 @@ func wsUpgradeHeaders() map[string]any { } func pprofPathItem(operationIDs map[string]int) map[string]any { + successHeaders := mergeHeaders(standardResponseHeaders(), rateLimitSuccessHeaders()) + errorHeaders := mergeHeaders(standardResponseHeaders(), rateLimitSuccessHeaders()) + return map[string]any{ "get": map[string]any{ "summary": "pprof index", @@ -940,7 +943,7 @@ func pprofPathItem(operationIDs map[string]int) map[string]any { }, }, }, - "headers": standardResponseHeaders(), + "headers": successHeaders, }, "401": map[string]any{ "description": "Unauthorised", @@ -952,7 +955,7 @@ func pprofPathItem(operationIDs map[string]int) map[string]any { }, }, }, - "headers": standardResponseHeaders(), + "headers": errorHeaders, }, "403": map[string]any{ "description": "Forbidden", @@ -964,7 +967,7 @@ func pprofPathItem(operationIDs map[string]int) map[string]any { }, }, }, - "headers": standardResponseHeaders(), + "headers": errorHeaders, }, }, }, @@ -972,6 +975,9 @@ func pprofPathItem(operationIDs map[string]int) map[string]any { } func expvarPathItem(operationIDs map[string]int) map[string]any { + successHeaders := mergeHeaders(standardResponseHeaders(), rateLimitSuccessHeaders()) + errorHeaders := mergeHeaders(standardResponseHeaders(), rateLimitSuccessHeaders()) + return map[string]any{ "get": map[string]any{ "summary": "Runtime metrics", @@ -994,7 +1000,7 @@ func expvarPathItem(operationIDs map[string]int) map[string]any { }, }, }, - "headers": standardResponseHeaders(), + "headers": successHeaders, }, "401": map[string]any{ "description": "Unauthorised", @@ -1006,7 +1012,7 @@ func expvarPathItem(operationIDs map[string]int) map[string]any { }, }, }, - "headers": standardResponseHeaders(), + "headers": errorHeaders, }, "403": map[string]any{ "description": "Forbidden", @@ -1018,7 +1024,7 @@ func expvarPathItem(operationIDs map[string]int) map[string]any { }, }, }, - "headers": standardResponseHeaders(), + "headers": errorHeaders, }, }, }, diff --git a/openapi_test.go b/openapi_test.go index fccf9da..14620fb 100644 --- a/openapi_test.go +++ b/openapi_test.go @@ -2485,3 +2485,37 @@ func TestSpecBuilder_Good_ServersCollapseTrailingSlashes(t *testing.T) { t.Fatalf("expected second server url=%q, got %v", "/api", second["url"]) } } + +func TestSpecBuilder_Good_RuntimeDebugEndpointsDocumentRateLimitHeaders(t *testing.T) { + sb := &api.SpecBuilder{ + Title: "Test", + Version: "1.0.0", + PprofEnabled: true, + ExpvarEnabled: true, + } + + data, err := sb.Build(nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + var spec map[string]any + if err := json.Unmarshal(data, &spec); err != nil { + t.Fatalf("invalid JSON: %v", err) + } + + paths := spec["paths"].(map[string]any) + for _, path := range []string{"/debug/pprof", "/debug/vars"} { + item := paths[path].(map[string]any) + op := item["get"].(map[string]any) + for _, code := range []string{"200", "401", "403"} { + resp := op["responses"].(map[string]any)[code].(map[string]any) + headers := resp["headers"].(map[string]any) + for _, name := range []string{"X-Request-ID", "X-RateLimit-Limit", "X-RateLimit-Remaining", "X-RateLimit-Reset"} { + if _, ok := headers[name]; !ok { + t.Fatalf("expected %s header on %s %s response", name, path, code) + } + } + } + } +}