From db2fafd4b0eb7289d5a3ae8243a80de07731367c Mon Sep 17 00:00:00 2001 From: pei Date: Sun, 24 Mar 2019 10:56:13 +0900 Subject: [PATCH] feat: support swagger configuration (#48) --- README.md | 7 +++++-- example/main.go | 5 ++++- go.mod | 6 ++++++ go.sum | 13 ++++++++++++ swagger.go | 53 ++++++++++++++++++++++++++++++++++++++----------- swagger_test.go | 29 +++++++++++++++++++++++++++ 6 files changed, 98 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index d4b27fc..22c05e0 100644 --- a/README.md +++ b/README.md @@ -64,8 +64,11 @@ import ( func main() { r := gin.New() - // use ginSwagger middleware to - r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) + config := &ginSwagger.Config{ + URL: "http://localhost:8080/swagger/doc.json", //The url pointing to API definition + } + // use ginSwagger middleware to + r.GET("/swagger/*any", ginSwagger.WrapHandler(config, swaggerFiles.Handler)) r.Run() } diff --git a/example/main.go b/example/main.go index 17bac13..afe3af7 100644 --- a/example/main.go +++ b/example/main.go @@ -25,7 +25,10 @@ import ( func main() { r := gin.New() - r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) + config := &ginSwagger.Config{ + URL: "http://localhost:8080/swagger/doc.json", //The url pointing to API definition + } + r.GET("/swagger/*any", ginSwagger.CustomWrapHandler(config, swaggerFiles.Handler)) r.Run() } diff --git a/go.mod b/go.mod index a0740e3..8137c3b 100644 --- a/go.mod +++ b/go.mod @@ -6,13 +6,19 @@ require ( github.com/go-openapi/jsonreference v0.18.0 // indirect github.com/go-openapi/spec v0.18.0 // indirect github.com/golang/protobuf v1.2.0 // indirect + github.com/json-iterator/go v1.1.6 // indirect github.com/mattn/go-isatty v0.0.4 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.1 // indirect github.com/pkg/errors v0.8.1 // indirect github.com/stretchr/testify v1.3.0 github.com/swaggo/swag v1.4.0 github.com/ugorji/go/codec v0.0.0-20181209151446-772ced7fd4c2 // indirect golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e + golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 // indirect + golang.org/x/sys v0.0.0-20190322080309-f49334f85ddc // indirect golang.org/x/tools v0.0.0-20190110015856-aa033095749b // indirect + gopkg.in/go-playground/assert.v1 v1.2.1 // indirect gopkg.in/go-playground/validator.v8 v8.18.2 // indirect gopkg.in/yaml.v2 v2.2.2 // indirect ) diff --git a/go.sum b/go.sum index dca6812..ca10315 100644 --- a/go.sum +++ b/go.sum @@ -21,10 +21,16 @@ github.com/go-openapi/swag v0.17.0 h1:iqrgMg7Q7SvtbWLlltPrkMs0UBJI6oTSs79JFRUi88 github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 h1:2gxZ0XQIU/5z3Z3bUBu+FXuk2pFbkN6tcwi/pjyaDic= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -40,11 +46,18 @@ github.com/ugorji/go/codec v0.0.0-20181209151446-772ced7fd4c2/go.mod h1:VFNgLljT golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 h1:bjcUS9ztw9kFmmIxJInhon/0Is3p+EHBKNgquIzo1OI= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190322080309-f49334f85ddc h1:4gbWbmmPFp4ySWICouJl6emP0MyS31yy9SrTlAGFT+g= +golang.org/x/sys v0.0.0-20190322080309-f49334f85ddc/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20190110015856-aa033095749b h1:G5tsw1T5VA7PD7VmXyGtX/hQp3ABPSCPRKVfsdUcVxs= golang.org/x/tools v0.0.0-20190110015856-aa033095749b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= +gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/swagger.go b/swagger.go index 4795c24..d1dfeea 100644 --- a/swagger.go +++ b/swagger.go @@ -11,21 +11,37 @@ import ( "github.com/swaggo/swag" ) +// Config stores ginSwagger configuration variables. +type Config struct { + //The url pointing to API definition (normally swagger.json or swagger.yaml). + URL string +} + +var defaultConfig = &Config{ + URL: "http://localhost:8080/swagger/doc.json", //The url pointing to API definition +} + // WrapHandler wraps `http.Handler` into `gin.HandlerFunc`. func WrapHandler(h *webdav.Handler) gin.HandlerFunc { + return CustomWrapHandler(defaultConfig, h) +} + +// CustomWrapHandler wraps `http.Handler` into `gin.HandlerFunc` +func CustomWrapHandler(config *Config, h *webdav.Handler) gin.HandlerFunc { //create a template with name t := template.New("swagger_index.html") index, _ := t.Parse(swagger_index_templ) - type pro struct { - Host string - } - - var re = regexp.MustCompile(`(.*)(index\.html|doc\.json|favicon-16x16\.png|favicon-32x32\.png|/oauth2-redirect\.html|swagger-ui\.css|swagger-ui\.css\.map|swagger-ui\.js|swagger-ui\.js\.map|swagger-ui-bundle\.js|swagger-ui-bundle\.js\.map|swagger-ui-standalone-preset\.js|swagger-ui-standalone-preset\.js\.map)[\?|.]*`) + var rexp = regexp.MustCompile(`(.*)(index\.html|doc\.json|favicon-16x16\.png|favicon-32x32\.png|/oauth2-redirect\.html|swagger-ui\.css|swagger-ui\.css\.map|swagger-ui\.js|swagger-ui\.js\.map|swagger-ui-bundle\.js|swagger-ui-bundle\.js\.map|swagger-ui-standalone-preset\.js|swagger-ui-standalone-preset\.js\.map)[\?|.]*`) return func(c *gin.Context) { + + type swaggerUIBundle struct { + URL string + } + var matches []string - if matches = re.FindStringSubmatch(c.Request.RequestURI); len(matches) != 3 { + if matches = rexp.FindStringSubmatch(c.Request.RequestURI); len(matches) != 3 { c.Status(404) c.Writer.Write([]byte("404 page not found")) return @@ -36,10 +52,9 @@ func WrapHandler(h *webdav.Handler) gin.HandlerFunc { switch path { case "index.html": - s := &pro{ - Host: "doc.json", //TODO: provide to customs? - } - index.Execute(c.Writer, s) + index.Execute(c.Writer, &swaggerUIBundle{ + URL: config.URL, + }) case "doc.json": doc, err := swag.ReadDoc() if err != nil { @@ -49,7 +64,6 @@ func WrapHandler(h *webdav.Handler) gin.HandlerFunc { return default: h.ServeHTTP(c.Writer, c.Request) - } } } @@ -69,6 +83,21 @@ func DisablingWrapHandler(h *webdav.Handler, envName string) gin.HandlerFunc { return WrapHandler(h) } +// DisablingCustomWrapHandler turn handler off +// if specified environment variable passed +func DisablingCustomWrapHandler(config *Config, h *webdav.Handler, envName string) gin.HandlerFunc { + eFlag := os.Getenv(envName) + if eFlag != "" { + return func(c *gin.Context) { + // Simulate behavior when route unspecified and + // return 404 HTTP code + c.String(404, "") + } + } + + return CustomWrapHandler(config, h) +} + const swagger_index_templ = ` @@ -144,7 +173,7 @@ const swagger_index_templ = ` window.onload = function() { // Build a system const ui = SwaggerUIBundle({ - url: "{{.Host}}", + url: "{{.URL}}", dom_id: '#swagger-ui', validatorUrl: null, presets: [ diff --git a/swagger_test.go b/swagger_test.go index 4fffb2b..0a9ff18 100644 --- a/swagger_test.go +++ b/swagger_test.go @@ -20,6 +20,16 @@ func TestWrapHandler(t *testing.T) { w1 := performRequest("GET", "/index.html", router) assert.Equal(t, 200, w1.Code) +} + +func TestWrapCustomHandler(t *testing.T) { + gin.SetMode(gin.TestMode) + router := gin.New() + + router.GET("/*any", CustomWrapHandler(&Config{}, swaggerFiles.Handler)) + + w1 := performRequest("GET", "/index.html", router) + assert.Equal(t, 200, w1.Code) w2 := performRequest("GET", "/doc.json", router) assert.Equal(t, 200, w2.Code) @@ -68,6 +78,25 @@ func TestDisablingWrapHandler(t *testing.T) { assert.Equal(t, 404, w44.Code) } +func TestDisablingCustomWrapHandler(t *testing.T) { + gin.SetMode(gin.TestMode) + + router := gin.New() + disablingKey := "SWAGGER_DISABLE2" + + router.GET("/simple/*any", DisablingCustomWrapHandler(&Config{}, swaggerFiles.Handler, disablingKey)) + + w1 := performRequest("GET", "/simple/index.html", router) + assert.Equal(t, 200, w1.Code) + + os.Setenv(disablingKey, "true") + + router.GET("/disabling/*any", DisablingCustomWrapHandler(&Config{}, swaggerFiles.Handler, disablingKey)) + + w11 := performRequest("GET", "/disabling/index.html", router) + assert.Equal(t, 404, w11.Code) +} + func performRequest(method, target string, router *gin.Engine) *httptest.ResponseRecorder { r := httptest.NewRequest(method, target, nil) w := httptest.NewRecorder()