feat(openapi): export swagger ui path metadata
Preserve the Swagger UI mount path in generated OpenAPI output and expose it through the spec and sdk CLI builders.\n\nCo-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
c3143a5029
commit
d9ccd7c49a
7 changed files with 51 additions and 1 deletions
|
|
@ -31,6 +31,7 @@ func addSDKCommand(parent *cli.Command) {
|
|||
title string
|
||||
description string
|
||||
version string
|
||||
swaggerPath string
|
||||
graphqlPath string
|
||||
graphqlPlayground bool
|
||||
ssePath string
|
||||
|
|
@ -57,6 +58,7 @@ func addSDKCommand(parent *cli.Command) {
|
|||
// If no spec file provided, generate one to a temp file.
|
||||
if specFile == "" {
|
||||
builder := sdkSpecBuilder(title, description, version, graphqlPath, graphqlPlayground, ssePath, wsPath, pprofEnabled, expvarEnabled, termsURL, contactName, contactURL, contactEmail, licenseName, licenseURL, externalDocsDescription, externalDocsURL, servers)
|
||||
builder.SwaggerPath = swaggerPath
|
||||
groups := sdkSpecGroupsIter()
|
||||
|
||||
tmpFile, err := os.CreateTemp("", "openapi-*.json")
|
||||
|
|
@ -105,6 +107,7 @@ func addSDKCommand(parent *cli.Command) {
|
|||
cli.StringFlag(cmd, &title, "title", "t", defaultSDKTitle, "API title in generated spec")
|
||||
cli.StringFlag(cmd, &description, "description", "d", defaultSDKDescription, "API description in generated spec")
|
||||
cli.StringFlag(cmd, &version, "version", "V", defaultSDKVersion, "API version in generated spec")
|
||||
cli.StringFlag(cmd, &swaggerPath, "swagger-path", "", "", "Swagger UI path in generated spec")
|
||||
cli.StringFlag(cmd, &graphqlPath, "graphql-path", "", "", "GraphQL endpoint path in generated spec")
|
||||
cli.BoolFlag(cmd, &graphqlPlayground, "graphql-playground", "", false, "Include the GraphQL playground endpoint in generated spec")
|
||||
cli.StringFlag(cmd, &ssePath, "sse-path", "", "", "SSE endpoint path in generated spec")
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ func addSpecCommand(parent *cli.Command) {
|
|||
title string
|
||||
description string
|
||||
version string
|
||||
swaggerPath string
|
||||
graphqlPath string
|
||||
graphqlPlayground bool
|
||||
ssePath string
|
||||
|
|
@ -41,6 +42,7 @@ func addSpecCommand(parent *cli.Command) {
|
|||
Title: title,
|
||||
Description: description,
|
||||
Version: version,
|
||||
SwaggerPath: swaggerPath,
|
||||
GraphQLPath: graphqlPath,
|
||||
GraphQLPlayground: graphqlPlayground,
|
||||
SSEPath: ssePath,
|
||||
|
|
@ -77,6 +79,7 @@ func addSpecCommand(parent *cli.Command) {
|
|||
cli.StringFlag(cmd, &title, "title", "t", "Lethean Core API", "API title in spec")
|
||||
cli.StringFlag(cmd, &description, "description", "d", "Lethean Core API", "API description in spec")
|
||||
cli.StringFlag(cmd, &version, "version", "V", "1.0.0", "API version in spec")
|
||||
cli.StringFlag(cmd, &swaggerPath, "swagger-path", "", "", "Swagger UI path in generated spec")
|
||||
cli.StringFlag(cmd, &graphqlPath, "graphql-path", "", "", "GraphQL endpoint path in generated spec")
|
||||
cli.BoolFlag(cmd, &graphqlPlayground, "graphql-playground", "", false, "Include the GraphQL playground endpoint in generated spec")
|
||||
cli.StringFlag(cmd, &ssePath, "sse-path", "", "", "SSE endpoint path in generated spec")
|
||||
|
|
|
|||
|
|
@ -82,6 +82,9 @@ func TestAPISpecCmd_Good_JSON(t *testing.T) {
|
|||
if specCmd.Flag("version") == nil {
|
||||
t.Fatal("expected --version flag on spec command")
|
||||
}
|
||||
if specCmd.Flag("swagger-path") == nil {
|
||||
t.Fatal("expected --swagger-path flag on spec command")
|
||||
}
|
||||
if specCmd.Flag("graphql-path") == nil {
|
||||
t.Fatal("expected --graphql-path flag on spec command")
|
||||
}
|
||||
|
|
@ -134,7 +137,7 @@ func TestAPISpecCmd_Good_CustomDescription(t *testing.T) {
|
|||
AddAPICommands(root)
|
||||
|
||||
outputFile := t.TempDir() + "/spec.json"
|
||||
root.SetArgs([]string{"api", "spec", "--description", "Custom API description", "--output", outputFile})
|
||||
root.SetArgs([]string{"api", "spec", "--description", "Custom API description", "--swagger-path", "/docs", "--output", outputFile})
|
||||
root.SetErr(new(bytes.Buffer))
|
||||
|
||||
if err := root.Execute(); err != nil {
|
||||
|
|
@ -150,6 +153,10 @@ func TestAPISpecCmd_Good_CustomDescription(t *testing.T) {
|
|||
t.Fatalf("expected valid JSON spec, got error: %v", err)
|
||||
}
|
||||
|
||||
if got := spec["x-swagger-ui-path"]; got != "/docs" {
|
||||
t.Fatalf("expected x-swagger-ui-path=/docs, got %v", got)
|
||||
}
|
||||
|
||||
info, ok := spec["info"].(map[string]any)
|
||||
if !ok {
|
||||
t.Fatal("expected info object in generated spec")
|
||||
|
|
@ -638,6 +645,9 @@ func TestAPISDKCmd_Good_ValidatesLanguage(t *testing.T) {
|
|||
if sdkCmd.Flag("version") == nil {
|
||||
t.Fatal("expected --version flag on sdk command")
|
||||
}
|
||||
if sdkCmd.Flag("swagger-path") == nil {
|
||||
t.Fatal("expected --swagger-path flag on sdk command")
|
||||
}
|
||||
if sdkCmd.Flag("graphql-path") == nil {
|
||||
t.Fatal("expected --graphql-path flag on sdk command")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ type SpecBuilder struct {
|
|||
Title string
|
||||
Description string
|
||||
Version string
|
||||
SwaggerPath string
|
||||
GraphQLPath string
|
||||
GraphQLPlayground bool
|
||||
WSPath string
|
||||
|
|
@ -85,6 +86,10 @@ func (sb *SpecBuilder) Build(groups []RouteGroup) ([]byte, error) {
|
|||
spec["info"].(map[string]any)["license"] = license
|
||||
}
|
||||
|
||||
if swaggerPath := strings.TrimSpace(sb.SwaggerPath); swaggerPath != "" {
|
||||
spec["x-swagger-ui-path"] = normaliseSwaggerPath(swaggerPath)
|
||||
}
|
||||
|
||||
if sb.TermsOfService != "" {
|
||||
spec["info"].(map[string]any)["termsOfService"] = sb.TermsOfService
|
||||
}
|
||||
|
|
|
|||
|
|
@ -208,6 +208,29 @@ func TestSpecBuilder_Good_EmptyGroups(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestSpecBuilder_Good_SwaggerUIPathExtension(t *testing.T) {
|
||||
sb := &api.SpecBuilder{
|
||||
Title: "Test",
|
||||
Description: "Swagger path test",
|
||||
Version: "1.0.0",
|
||||
SwaggerPath: "/docs/",
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
if got := spec["x-swagger-ui-path"]; got != "/docs" {
|
||||
t.Fatalf("expected x-swagger-ui-path=/docs, got %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSpecBuilder_Good_GraphQLEndpoint(t *testing.T) {
|
||||
sb := &api.SpecBuilder{
|
||||
Title: "Test",
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ func (e *Engine) OpenAPISpecBuilder() *SpecBuilder {
|
|||
Title: e.swaggerTitle,
|
||||
Description: e.swaggerDesc,
|
||||
Version: e.swaggerVersion,
|
||||
SwaggerPath: e.swaggerPath,
|
||||
TermsOfService: e.swaggerTermsOfService,
|
||||
ContactName: e.swaggerContactName,
|
||||
ContactURL: e.swaggerContactURL,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ func TestEngine_Good_OpenAPISpecBuilderCarriesEngineMetadata(t *testing.T) {
|
|||
broker := api.NewSSEBroker()
|
||||
e, err := api.New(
|
||||
api.WithSwagger("Engine API", "Engine metadata", "2.0.0"),
|
||||
api.WithSwaggerPath("/docs"),
|
||||
api.WithSwaggerTermsOfService("https://example.com/terms"),
|
||||
api.WithSwaggerContact("API Support", "https://example.com/support", "support@example.com"),
|
||||
api.WithSwaggerServers("https://api.example.com", "/", "https://api.example.com"),
|
||||
|
|
@ -59,6 +60,10 @@ func TestEngine_Good_OpenAPISpecBuilderCarriesEngineMetadata(t *testing.T) {
|
|||
t.Fatalf("expected version 2.0.0, got %v", info["version"])
|
||||
}
|
||||
|
||||
if got := spec["x-swagger-ui-path"]; got != "/docs" {
|
||||
t.Fatalf("expected x-swagger-ui-path=/docs, got %v", got)
|
||||
}
|
||||
|
||||
contact, ok := info["contact"].(map[string]any)
|
||||
if !ok {
|
||||
t.Fatal("expected contact metadata in generated spec")
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue