feat(api): merge custom OpenAPI security schemes
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
920c227e21
commit
8e1a424fc8
2 changed files with 75 additions and 8 deletions
34
openapi.go
34
openapi.go
|
|
@ -36,6 +36,7 @@ type SpecBuilder struct {
|
|||
Servers []string
|
||||
LicenseName string
|
||||
LicenseURL string
|
||||
SecuritySchemes map[string]any
|
||||
ExternalDocsDescription string
|
||||
ExternalDocsURL string
|
||||
PprofEnabled bool
|
||||
|
|
@ -179,14 +180,8 @@ func (sb *SpecBuilder) Build(groups []RouteGroup) ([]byte, error) {
|
|||
},
|
||||
},
|
||||
},
|
||||
"securitySchemes": map[string]any{
|
||||
"bearerAuth": map[string]any{
|
||||
"type": "http",
|
||||
"scheme": "bearer",
|
||||
"bearerFormat": "JWT",
|
||||
},
|
||||
},
|
||||
"headers": deprecationHeaderComponents(),
|
||||
"securitySchemes": securitySchemeComponents(sb.SecuritySchemes),
|
||||
"headers": deprecationHeaderComponents(),
|
||||
}
|
||||
|
||||
return json.MarshalIndent(spec, "", " ")
|
||||
|
|
@ -636,6 +631,29 @@ func deprecationHeaderComponents() map[string]any {
|
|||
}
|
||||
}
|
||||
|
||||
// securitySchemeComponents builds the OpenAPI security scheme registry.
|
||||
// bearerAuth stays available by default, while callers can add or override
|
||||
// additional scheme definitions for custom security requirements.
|
||||
func securitySchemeComponents(overrides map[string]any) map[string]any {
|
||||
schemes := map[string]any{
|
||||
"bearerAuth": map[string]any{
|
||||
"type": "http",
|
||||
"scheme": "bearer",
|
||||
"bearerFormat": "JWT",
|
||||
},
|
||||
}
|
||||
|
||||
for name, scheme := range overrides {
|
||||
name = strings.TrimSpace(name)
|
||||
if name == "" || scheme == nil {
|
||||
continue
|
||||
}
|
||||
schemes[name] = scheme
|
||||
}
|
||||
|
||||
return schemes
|
||||
}
|
||||
|
||||
// buildTags generates the tags array from all RouteGroups.
|
||||
func (sb *SpecBuilder) buildTags(groups []preparedRouteGroup) []map[string]any {
|
||||
tags := []map[string]any{
|
||||
|
|
|
|||
|
|
@ -208,6 +208,55 @@ func TestSpecBuilder_Good_EmptyGroups(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestSpecBuilder_Good_CustomSecuritySchemesAreMerged(t *testing.T) {
|
||||
sb := &api.SpecBuilder{
|
||||
Title: "Test",
|
||||
Version: "1.0.0",
|
||||
SecuritySchemes: map[string]any{
|
||||
"apiKeyAuth": map[string]any{
|
||||
"type": "apiKey",
|
||||
"in": "header",
|
||||
"name": "X-API-Key",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
components := spec["components"].(map[string]any)
|
||||
schemes := components["securitySchemes"].(map[string]any)
|
||||
|
||||
bearerAuth, ok := schemes["bearerAuth"].(map[string]any)
|
||||
if !ok {
|
||||
t.Fatal("expected default bearerAuth security scheme to remain present")
|
||||
}
|
||||
if bearerAuth["scheme"] != "bearer" {
|
||||
t.Fatalf("expected bearerAuth scheme to stay bearer, got %v", bearerAuth["scheme"])
|
||||
}
|
||||
|
||||
apiKeyAuth, ok := schemes["apiKeyAuth"].(map[string]any)
|
||||
if !ok {
|
||||
t.Fatal("expected custom apiKeyAuth security scheme to be merged")
|
||||
}
|
||||
if apiKeyAuth["type"] != "apiKey" {
|
||||
t.Fatalf("expected apiKeyAuth.type=apiKey, got %v", apiKeyAuth["type"])
|
||||
}
|
||||
if apiKeyAuth["in"] != "header" {
|
||||
t.Fatalf("expected apiKeyAuth.in=header, got %v", apiKeyAuth["in"])
|
||||
}
|
||||
if apiKeyAuth["name"] != "X-API-Key" {
|
||||
t.Fatalf("expected apiKeyAuth.name=X-API-Key, got %v", apiKeyAuth["name"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestSpecBuilder_Good_SwaggerUIPathExtension(t *testing.T) {
|
||||
sb := &api.SpecBuilder{
|
||||
Title: "Test",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue