From 11a6cb395c58f0b31325d335acdf37100a08f19b Mon Sep 17 00:00:00 2001 From: Volodymyr Khrestin Date: Fri, 6 Dec 2019 21:07:36 +0200 Subject: [PATCH] - removed serving of `index.html` since it was not used - moved serving of UI template to the `SwaggerBase` - added `ui.initOAuth` UI call - added support for `Oauth2ClientID` and `Oauth2AppName` - added config helpers - minor refactoring - fixed tests since they were assuming that UI is always served from the root --- README.md | 4 +-- go.mod | 3 ++ go.sum | 4 +++ swagger.go | 84 ++++++++++++++++++++++++++++++++++--------------- swagger_test.go | 28 ++++++++--------- 5 files changed, 81 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 159bd2c..ff4758c 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ import ( func main() { r := gin.New() - swaggerBase := ginSwagger.SwaggerBase("docs/") // default `swagger/` + swaggerBase := ginSwagger.SwaggerBase("/api/v2/docs/") // default `swagger/` specFileName := ginSwagger.SpecFileName("swagger.json") // default `doc.json` apiGroup := r.Group("/api/v2") @@ -75,7 +75,7 @@ func main() { } ``` -5. Run it, and browser to http://localhost:8080/swagger/index.html, you can see Swagger 2.0 Api documents. +5. Run it, and browse to http://localhost:8080/api/v2/docs/, you can see Swagger 2.0 Api documents. ![swagger_index.html](https://user-images.githubusercontent.com/8943871/60704329-b7ab0680-9f36-11e9-9184-5c638c05e9c5.png) diff --git a/go.mod b/go.mod index 85830d3..3ddf25f 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/kr/pretty v0.1.0 // indirect github.com/mattn/go-isatty v0.0.8 // indirect github.com/stretchr/testify v1.3.0 + github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14 github.com/swaggo/swag v1.5.1 github.com/ugorji/go v1.1.5-pre // indirect golang.org/x/net v0.0.0-20190611141213-3f473d35a33a @@ -15,3 +16,5 @@ require ( golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b // indirect gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect ) + +go 1.13 diff --git a/go.sum b/go.sum index 47d45af..5602ec9 100644 --- a/go.sum +++ b/go.sum @@ -53,6 +53,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14 h1:PyYN9JH5jY9j6av01SpfRMb+1DWg/i3MbGOKPxJ2wjM= +github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E= github.com/swaggo/swag v1.5.1 h1:2Agm8I4K5qb00620mHq0VJ05/KT4FtmALPIcQR9lEZM= github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= @@ -69,6 +71,8 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190611141213-3f473d35a33a h1:+KkCgOMgnKSgenxTBoiwkMqTiouMIy/3o8RLdmSbGoY= golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191204025024-5ee1b9f4859a h1:+HHJiFUXVOIS9mr1ThqkQD1N8vpFCfCShqADBM12KTc= +golang.org/x/net v0.0.0-20191206103017-1ddd1de85cb0 h1:LxY/gQN/MrcW24/46nLyiip1GhN/Yi14QPbeNskTvQA= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/swagger.go b/swagger.go index b8b1b6b..d61271f 100644 --- a/swagger.go +++ b/swagger.go @@ -2,6 +2,7 @@ package ginSwagger import ( "html/template" + "net/http" "os" "path/filepath" "regexp" @@ -16,9 +17,11 @@ import ( // Config stores ginSwagger configuration variables. type Config struct { //The url pointing to API definition (normally swagger.json or swagger.yaml). Default is `doc.json`. - SpecFileName string - SwaggerBase string - DeepLinking bool + SpecFileName string + SwaggerBase string + DeepLinking bool + Oauth2ClientID string + Oauth2AppName string } // SwaggerBase sets the subpath of swagger router. Default is `swagger/`. @@ -42,12 +45,28 @@ func DeepLinking(deepLinking bool) func(c *Config) { } } +// Oauth2ClientID sets OAuth2 client ID +func Oauth2ClientID(clientID string) func(c *Config) { + return func(c *Config) { + c.Oauth2ClientID = clientID + } +} + +// Oauth2AppName sets OAuth2 application name +func Oauth2AppName(appName string) func(c *Config) { + return func(c *Config) { + c.Oauth2AppName = appName + } +} + // WrapHandler wraps `http.Handler` into `gin.HandlerFunc`. func WrapHandler(h *webdav.Handler, confs ...func(c *Config)) gin.HandlerFunc { defaultConfig := &Config{ - SpecFileName: "doc.json", - SwaggerBase: "swagger/", - DeepLinking: true, + SpecFileName: "doc.json", + SwaggerBase: "/swagger/", + DeepLinking: true, + Oauth2ClientID: "your-client-id", + Oauth2AppName: "your-app-name", } for _, c := range confs { @@ -69,25 +88,39 @@ func CustomWrapHandler(config *Config, h *webdav.Handler) gin.HandlerFunc { } specRegexStr := strings.Replace(specFileName, ".", "\\.", -1) - var rexp = regexp.MustCompile(`(.*)(index\.html|` + specRegexStr + `|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(`(.*)(` + specRegexStr + `|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 - Oauth2RedirectURL template.JS DeepLinking bool + Oauth2RedirectURL template.JS + Oauth2ClientID string + Oauth2AppName string + } + + if c.Request.RequestURI == config.SwaggerBase { + c.Header("Content-Type", "text/html; charset=utf-8") + index.Execute(c.Writer, &swaggerUIBundle{ + URL: filepath.Join(config.SwaggerBase, specFileName), + DeepLinking: config.DeepLinking, + Oauth2RedirectURL: template.JS("`${window.location.protocol}//${window.location.host}" + filepath.Join(config.SwaggerBase, "oauth2-redirect.html") + "`"), + Oauth2ClientID: config.Oauth2ClientID, + Oauth2AppName: config.Oauth2AppName, + }) + return } var matches []string if matches = rexp.FindStringSubmatch(c.Request.RequestURI); len(matches) != 3 { - c.Status(404) + c.Status(http.StatusNotFound) c.Writer.Write([]byte("404 page not found")) return } + + h.Prefix = matches[1] path := matches[2] - prefix := matches[1] - h.Prefix = prefix if strings.HasSuffix(path, ".html") { c.Header("Content-Type", "text/html; charset=utf-8") @@ -99,39 +132,32 @@ func CustomWrapHandler(config *Config, h *webdav.Handler) gin.HandlerFunc { c.Header("Content-Type", "application/json") } - switch path { - case "index.html": - index.Execute(c.Writer, &swaggerUIBundle{ - URL: filepath.Join(config.SwaggerBase, specFileName), - Oauth2RedirectURL: template.JS("`${window.location.protocol}//${window.location.host}" + filepath.Join(config.SwaggerBase, "oauth2-redirect.html") + "`"), - DeepLinking: config.DeepLinking, - }) - case specFileName: + if path == specFileName { doc, err := swag.ReadDoc() if err != nil { panic(err) } c.Writer.Write([]byte(doc)) return - default: - h.ServeHTTP(c.Writer, c.Request) } + + h.ServeHTTP(c.Writer, c.Request) } } // DisablingWrapHandler turn handler off // if specified environment variable passed -func DisablingWrapHandler(h *webdav.Handler, envName string) gin.HandlerFunc { +func DisablingWrapHandler(h *webdav.Handler, envName string, confs ...func(c *Config)) 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, "") + c.String(http.StatusNotFound, "") } } - return WrapHandler(h) + return WrapHandler(h, confs...) } // DisablingCustomWrapHandler turn handler off @@ -142,7 +168,7 @@ func DisablingCustomWrapHandler(config *Config, h *webdav.Handler, envName strin return func(c *gin.Context) { // Simulate behavior when route unspecified and // return 404 HTTP code - c.String(404, "") + c.String(http.StatusNotFound, "") } } @@ -236,7 +262,13 @@ window.onload = function() { SwaggerUIBundle.plugins.DownloadUrl ], layout: "StandaloneLayout", - deepLinking: {{.DeepLinking}} + deepLinking: {{.DeepLinking}}, + showExtensions: true + }) + + ui.initOAuth({ + clientId: "localhost.vela.care", + appName: "notifications" }) window.ui = ui diff --git a/swagger_test.go b/swagger_test.go index 3ddc419..329c702 100644 --- a/swagger_test.go +++ b/swagger_test.go @@ -18,9 +18,9 @@ func TestWrapHandler(t *testing.T) { gin.SetMode(gin.TestMode) router := gin.New() - router.GET("/*any", WrapHandler(swaggerFiles.Handler)) + router.GET("/swagger/*any", WrapHandler(swaggerFiles.Handler)) - w1 := performRequest("GET", "/index.html", router) + w1 := performRequest("GET", "/swagger/", router) assert.Equal(t, 200, w1.Code) } @@ -28,9 +28,9 @@ func TestCustomWrapHandler(t *testing.T) { gin.SetMode(gin.TestMode) router := gin.New() - router.GET("/*any", CustomWrapHandler(&Config{}, swaggerFiles.Handler)) + router.GET("/*any", CustomWrapHandler(&Config{SwaggerBase: "/"}, swaggerFiles.Handler)) - w1 := performRequest("GET", "/index.html", router) + w1 := performRequest("GET", "/", router) assert.Equal(t, 200, w1.Code) w2 := performRequest("GET", "/doc.json", router) @@ -52,9 +52,9 @@ func TestDisablingWrapHandler(t *testing.T) { router := gin.New() disablingKey := "SWAGGER_DISABLE" - router.GET("/simple/*any", DisablingWrapHandler(swaggerFiles.Handler, disablingKey)) + router.GET("/simple/*any", DisablingWrapHandler(swaggerFiles.Handler, disablingKey, SwaggerBase("/simple/"))) - w1 := performRequest("GET", "/simple/index.html", router) + w1 := performRequest("GET", "/simple/", router) assert.Equal(t, 200, w1.Code) w2 := performRequest("GET", "/simple/doc.json", router) @@ -71,9 +71,9 @@ func TestDisablingWrapHandler(t *testing.T) { os.Setenv(disablingKey, "true") - router.GET("/disabling/*any", DisablingWrapHandler(swaggerFiles.Handler, disablingKey)) + router.GET("/disabling/*any", DisablingWrapHandler(swaggerFiles.Handler, disablingKey, SwaggerBase("/disabling/"))) - w11 := performRequest("GET", "/disabling/index.html", router) + w11 := performRequest("GET", "/disabling/", router) assert.Equal(t, 404, w11.Code) w22 := performRequest("GET", "/disabling/doc.json", router) @@ -95,16 +95,16 @@ func TestDisablingCustomWrapHandler(t *testing.T) { router := gin.New() disablingKey := "SWAGGER_DISABLE2" - router.GET("/simple/*any", DisablingCustomWrapHandler(&Config{}, swaggerFiles.Handler, disablingKey)) + router.GET("/simple/*any", DisablingCustomWrapHandler(&Config{SwaggerBase: "/simple/"}, swaggerFiles.Handler, disablingKey)) - w1 := performRequest("GET", "/simple/index.html", router) + w1 := performRequest("GET", "/simple/", router) assert.Equal(t, 200, w1.Code) os.Setenv(disablingKey, "true") - router.GET("/disabling/*any", DisablingCustomWrapHandler(&Config{}, swaggerFiles.Handler, disablingKey)) + router.GET("/disabling/*any", DisablingCustomWrapHandler(&Config{SwaggerBase: "/disabling/"}, swaggerFiles.Handler, disablingKey)) - w11 := performRequest("GET", "/disabling/index.html", router) + w11 := performRequest("GET", "/disabling/", router) assert.Equal(t, 404, w11.Code) } @@ -114,9 +114,9 @@ func TestWithGzipMiddleware(t *testing.T) { router.Use(gzip.Gzip(gzip.BestSpeed)) - router.GET("/*any", WrapHandler(swaggerFiles.Handler)) + router.GET("/*any", WrapHandler(swaggerFiles.Handler, SwaggerBase("/"))) - w1 := performRequest("GET", "/index.html", router) + w1 := performRequest("GET", "/", router) assert.Equal(t, 200, w1.Code) assert.Equal(t, w1.Header()["Content-Type"][0], "text/html; charset=utf-8")