From 141e302c532513f94e2f9692969e575c79f68af9 Mon Sep 17 00:00:00 2001 From: dylanhitt Date: Mon, 23 Dec 2024 19:37:06 -0500 Subject: [PATCH] BREAKING: add WithEngineOptions and move WithOpenAPIConfig to a WithEngineOption --- engine.go | 81 +++++++++++------------ examples/generate-opengraph-image/main.go | 12 ++-- examples/petstore/lib/server_test.go | 14 ++-- openapi_handler_test.go | 20 +++--- openapi_test.go | 70 +++++++++++--------- server.go | 6 +- server_test.go | 74 ++++++++++++--------- 7 files changed, 153 insertions(+), 124 deletions(-) diff --git a/engine.go b/engine.go index c566b512..410b883c 100644 --- a/engine.go +++ b/engine.go @@ -9,19 +9,16 @@ import ( "path/filepath" ) -func NewEngine(config ...OpenAPIConfig) *Engine { - if len(config) > 1 { - panic("config should not be more than one") - } - engine := &Engine{ +func NewEngine(options ...func(*Engine)) *Engine { + e := &Engine{ OpenAPI: NewOpenAPI(), OpenAPIConfig: defaultOpenAPIConfig, ErrorHandler: ErrorHandler, } - if len(config) > 0 { - engine.setOpenAPIConfig(config[0]) + for _, option := range options { + option(e) } - return engine + return e } // The Engine is the main struct of the framework. @@ -44,6 +41,41 @@ type EngineOpenAPIConfig struct { PrettyFormatJson bool } +func WithOpenAPIConfig(config OpenAPIConfig) func(*Engine) { + return func(e *Engine) { + if config.JsonUrl != "" { + e.OpenAPIConfig.JsonUrl = config.JsonUrl + } + + if config.SwaggerUrl != "" { + e.OpenAPIConfig.SwaggerUrl = config.SwaggerUrl + } + + if config.JsonFilePath != "" { + e.OpenAPIConfig.JsonFilePath = config.JsonFilePath + } + + if config.UIHandler != nil { + e.OpenAPIConfig.UIHandler = config.UIHandler + } + + e.OpenAPIConfig.DisableSwagger = config.DisableSwagger + e.OpenAPIConfig.DisableSwaggerUI = config.DisableSwaggerUI + e.OpenAPIConfig.DisableLocalSave = config.DisableLocalSave + e.OpenAPIConfig.PrettyFormatJson = config.PrettyFormatJson + + if !validateJsonSpecUrl(e.OpenAPIConfig.JsonUrl) { + slog.Error("Error serving openapi json spec. Value of 's.OpenAPIConfig.JsonSpecUrl' option is not valid", "url", e.OpenAPIConfig.JsonUrl) + return + } + + if !validateSwaggerUrl(e.OpenAPIConfig.SwaggerUrl) { + slog.Error("Error serving swagger ui. Value of 's.OpenAPIConfig.SwaggerUrl' option is not valid", "url", e.OpenAPIConfig.SwaggerUrl) + return + } + } +} + // OutputOpenAPISpec takes the OpenAPI spec and outputs it to a JSON file func (e *Engine) OutputOpenAPISpec() []byte { e.OpenAPI.computeTags() @@ -99,39 +131,6 @@ func (s *Engine) marshalSpec() ([]byte, error) { return json.Marshal(s.OpenAPI.Description()) } -func (e *Engine) setOpenAPIConfig(config OpenAPIConfig) { - if config.JsonUrl != "" { - e.OpenAPIConfig.JsonUrl = config.JsonUrl - } - - if config.SwaggerUrl != "" { - e.OpenAPIConfig.SwaggerUrl = config.SwaggerUrl - } - - if config.JsonFilePath != "" { - e.OpenAPIConfig.JsonFilePath = config.JsonFilePath - } - - if config.UIHandler != nil { - e.OpenAPIConfig.UIHandler = config.UIHandler - } - - e.OpenAPIConfig.DisableSwagger = config.DisableSwagger - e.OpenAPIConfig.DisableSwaggerUI = config.DisableSwaggerUI - e.OpenAPIConfig.DisableLocalSave = config.DisableLocalSave - e.OpenAPIConfig.PrettyFormatJson = config.PrettyFormatJson - - if !validateJsonSpecUrl(e.OpenAPIConfig.JsonUrl) { - slog.Error("Error serving openapi json spec. Value of 's.OpenAPIConfig.JsonSpecUrl' option is not valid", "url", e.OpenAPIConfig.JsonUrl) - return - } - - if !validateSwaggerUrl(e.OpenAPIConfig.SwaggerUrl) { - slog.Error("Error serving swagger ui. Value of 's.OpenAPIConfig.SwaggerUrl' option is not valid", "url", e.OpenAPIConfig.SwaggerUrl) - return - } -} - func (e *Engine) printOpenAPIMessage(msg string) { if !e.OpenAPIConfig.DisableMessages { slog.Info(msg) diff --git a/examples/generate-opengraph-image/main.go b/examples/generate-opengraph-image/main.go index 7e258cb5..5c7f0637 100644 --- a/examples/generate-opengraph-image/main.go +++ b/examples/generate-opengraph-image/main.go @@ -21,11 +21,13 @@ var optionReturnsPNG = func(br *fuego.BaseRoute) { func main() { s := fuego.NewServer( - fuego.WithOpenAPIConfig(fuego.OpenAPIConfig{ - EngineOpenAPIConfig: fuego.EngineOpenAPIConfig{ - PrettyFormatJson: true, - }, - }), + fuego.WithEngineOptions( + fuego.WithOpenAPIConfig(fuego.OpenAPIConfig{ + EngineOpenAPIConfig: fuego.EngineOpenAPIConfig{ + PrettyFormatJson: true, + }, + }), + ), ) fuego.GetStd(s, "/{title}", controller.OpenGraphHandler, diff --git a/examples/petstore/lib/server_test.go b/examples/petstore/lib/server_test.go index 05a1f9a9..cc9cbbdb 100644 --- a/examples/petstore/lib/server_test.go +++ b/examples/petstore/lib/server_test.go @@ -14,12 +14,14 @@ import ( func TestPetstoreOpenAPIGeneration(t *testing.T) { server := NewPetStoreServer( fuego.WithoutStartupMessages(), - fuego.WithOpenAPIConfig(fuego.OpenAPIConfig{ - EngineOpenAPIConfig: fuego.EngineOpenAPIConfig{ - JsonFilePath: "testdata/doc/openapi.json", - PrettyFormatJson: true, - }, - }), + fuego.WithEngineOptions( + fuego.WithOpenAPIConfig(fuego.OpenAPIConfig{ + EngineOpenAPIConfig: fuego.EngineOpenAPIConfig{ + JsonFilePath: "testdata/doc/openapi.json", + PrettyFormatJson: true, + }, + }), + ), ) server.OutputOpenAPISpec() diff --git a/openapi_handler_test.go b/openapi_handler_test.go index 0e1bfe59..0b031217 100644 --- a/openapi_handler_test.go +++ b/openapi_handler_test.go @@ -37,11 +37,13 @@ func TestUIHandler(t *testing.T) { t.Run("wrap DefaultOpenAPIHandler behind a middleware", func(t *testing.T) { s := NewServer( - WithOpenAPIConfig(OpenAPIConfig{ - UIHandler: func(specURL string) http.Handler { - return dummyMiddleware(DefaultOpenAPIHandler(specURL)) - }, - }), + WithEngineOptions( + WithOpenAPIConfig(OpenAPIConfig{ + UIHandler: func(specURL string) http.Handler { + return dummyMiddleware(DefaultOpenAPIHandler(specURL)) + }, + }), + ), ) s.OutputOpenAPISpec() @@ -59,9 +61,11 @@ func TestUIHandler(t *testing.T) { t.Run("disabling UI", func(t *testing.T) { s := NewServer( - WithOpenAPIConfig(OpenAPIConfig{ - DisableSwaggerUI: true, - }), + WithEngineOptions( + WithOpenAPIConfig(OpenAPIConfig{ + DisableSwaggerUI: true, + }), + ), ) s.OutputOpenAPISpec() diff --git a/openapi_test.go b/openapi_test.go index 6ee81739..f933553f 100644 --- a/openapi_test.go +++ b/openapi_test.go @@ -245,12 +245,14 @@ func TestServer_OutputOpenApiSpec(t *testing.T) { docPath := "doc/openapi.json" t.Run("base", func(t *testing.T) { s := NewServer( - WithOpenAPIConfig( - OpenAPIConfig{ - EngineOpenAPIConfig: EngineOpenAPIConfig{ - JsonFilePath: docPath, + WithEngineOptions( + WithOpenAPIConfig( + OpenAPIConfig{ + EngineOpenAPIConfig: EngineOpenAPIConfig{ + JsonFilePath: docPath, + }, }, - }, + ), ), ) Get(s, "/", func(ContextNoBody) (MyStruct, error) { @@ -268,13 +270,15 @@ func TestServer_OutputOpenApiSpec(t *testing.T) { }) t.Run("do not print file", func(t *testing.T) { s := NewServer( - WithOpenAPIConfig( - OpenAPIConfig{ - EngineOpenAPIConfig: EngineOpenAPIConfig{ - JsonFilePath: docPath, - DisableLocalSave: true, + WithEngineOptions( + WithOpenAPIConfig( + OpenAPIConfig{ + EngineOpenAPIConfig: EngineOpenAPIConfig{ + JsonFilePath: docPath, + DisableLocalSave: true, + }, }, - }, + ), ), ) Get(s, "/", func(ContextNoBody) (MyStruct, error) { @@ -290,14 +294,16 @@ func TestServer_OutputOpenApiSpec(t *testing.T) { }) t.Run("swagger disabled", func(t *testing.T) { s := NewServer( - WithOpenAPIConfig( - OpenAPIConfig{ - EngineOpenAPIConfig: EngineOpenAPIConfig{ - JsonFilePath: docPath, - DisableLocalSave: true, + WithEngineOptions( + WithOpenAPIConfig( + OpenAPIConfig{ + EngineOpenAPIConfig: EngineOpenAPIConfig{ + JsonFilePath: docPath, + DisableLocalSave: true, + }, + DisableSwagger: true, }, - DisableSwagger: true, - }, + ), ), ) Get(s, "/", func(ContextNoBody) (MyStruct, error) { @@ -314,13 +320,15 @@ func TestServer_OutputOpenApiSpec(t *testing.T) { }) t.Run("pretty format json file", func(t *testing.T) { s := NewServer( - WithOpenAPIConfig( - OpenAPIConfig{ - EngineOpenAPIConfig: EngineOpenAPIConfig{ - JsonFilePath: docPath, - PrettyFormatJson: true, + WithEngineOptions( + WithOpenAPIConfig( + OpenAPIConfig{ + EngineOpenAPIConfig: EngineOpenAPIConfig{ + JsonFilePath: docPath, + PrettyFormatJson: true, + }, }, - }, + ), ), ) Get(s, "/", func(ContextNoBody) (MyStruct, error) { @@ -433,12 +441,14 @@ func TestLocalSave(t *testing.T) { func TestAutoGroupTags(t *testing.T) { s := NewServer( - WithOpenAPIConfig(OpenAPIConfig{ - EngineOpenAPIConfig: EngineOpenAPIConfig{ - DisableLocalSave: true, - }, - DisableSwagger: true, - }), + WithEngineOptions( + WithOpenAPIConfig(OpenAPIConfig{ + EngineOpenAPIConfig: EngineOpenAPIConfig{ + DisableLocalSave: true, + }, + DisableSwagger: true, + }), + ), ) Get(s, "/a", func(ContextNoBody) (MyStruct, error) { return MyStruct{}, nil diff --git a/server.go b/server.go index 31721326..9046cc80 100644 --- a/server.go +++ b/server.go @@ -365,9 +365,11 @@ func WithoutLogger() func(*Server) { } } -func WithOpenAPIConfig(openapiConfig OpenAPIConfig) func(*Server) { +func WithEngineOptions(options ...func(*Engine)) func(*Server) { return func(s *Server) { - s.Engine.setOpenAPIConfig(openapiConfig) + for _, option := range options { + option(s.Engine) + } } } diff --git a/server_test.go b/server_test.go index 3cde1178..e3e0d61a 100644 --- a/server_test.go +++ b/server_test.go @@ -71,7 +71,9 @@ func TestWithXML(t *testing.T) { func TestWithOpenAPIConfig(t *testing.T) { t.Run("with default values", func(t *testing.T) { s := NewServer( - WithOpenAPIConfig(OpenAPIConfig{}), + WithEngineOptions( + WithOpenAPIConfig(OpenAPIConfig{}), + ), ) require.Equal(t, "/swagger", s.OpenAPIConfig.SwaggerUrl) @@ -82,16 +84,18 @@ func TestWithOpenAPIConfig(t *testing.T) { t.Run("with custom values", func(t *testing.T) { s := NewServer( - WithOpenAPIConfig(OpenAPIConfig{ - SwaggerUrl: "/api", - JsonUrl: "/api/openapi.json", - DisableSwagger: true, - EngineOpenAPIConfig: EngineOpenAPIConfig{ - JsonFilePath: "openapi.json", - DisableLocalSave: true, - PrettyFormatJson: true, - }, - }), + WithEngineOptions( + WithOpenAPIConfig(OpenAPIConfig{ + SwaggerUrl: "/api", + JsonUrl: "/api/openapi.json", + DisableSwagger: true, + EngineOpenAPIConfig: EngineOpenAPIConfig{ + JsonFilePath: "openapi.json", + DisableLocalSave: true, + PrettyFormatJson: true, + }, + }), + ), ) require.Equal(t, "/api", s.OpenAPIConfig.SwaggerUrl) @@ -105,36 +109,42 @@ func TestWithOpenAPIConfig(t *testing.T) { t.Run("with invalid local path values", func(t *testing.T) { t.Run("with invalid path", func(t *testing.T) { NewServer( - WithOpenAPIConfig(OpenAPIConfig{ - SwaggerUrl: "p i", - JsonUrl: "pi/op enapi.json", - EngineOpenAPIConfig: EngineOpenAPIConfig{ - JsonFilePath: "path/to/jsonSpec", - }, - }), + WithEngineOptions( + WithOpenAPIConfig(OpenAPIConfig{ + SwaggerUrl: "p i", + JsonUrl: "pi/op enapi.json", + EngineOpenAPIConfig: EngineOpenAPIConfig{ + JsonFilePath: "path/to/jsonSpec", + }, + }), + ), ) }) t.Run("with invalid url", func(t *testing.T) { NewServer( - WithOpenAPIConfig(OpenAPIConfig{ - JsonUrl: "pi/op enapi.json", - SwaggerUrl: "p i", - EngineOpenAPIConfig: EngineOpenAPIConfig{ - JsonFilePath: "path/to/jsonSpec.json", - }, - }), + WithEngineOptions( + WithOpenAPIConfig(OpenAPIConfig{ + JsonUrl: "pi/op enapi.json", + SwaggerUrl: "p i", + EngineOpenAPIConfig: EngineOpenAPIConfig{ + JsonFilePath: "path/to/jsonSpec.json", + }, + }), + ), ) }) t.Run("with invalid url", func(t *testing.T) { NewServer( - WithOpenAPIConfig(OpenAPIConfig{ - JsonUrl: "/api/openapi.json", - SwaggerUrl: "invalid path", - EngineOpenAPIConfig: EngineOpenAPIConfig{ - JsonFilePath: "path/to/jsonSpec.json", - }, - }), + WithEngineOptions( + WithOpenAPIConfig(OpenAPIConfig{ + JsonUrl: "/api/openapi.json", + SwaggerUrl: "invalid path", + EngineOpenAPIConfig: EngineOpenAPIConfig{ + JsonFilePath: "path/to/jsonSpec.json", + }, + }), + ), ) }) })