add docExpansion feature (#163)

* add docExpansion feature

* add pull request template
This commit is contained in:
Bogdan U 2021-09-25 14:14:03 +03:00 committed by GitHub
parent 6433b1c297
commit b388ffa3dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 91 additions and 44 deletions

8
PULL_REQUEST_TEMPLATE.md Normal file
View File

@ -0,0 +1,8 @@
**Describe the PR**
e.g. add cool parser.
**Relation issue**
e.g. https://github.com/swaggo/gin-swagger/pull/123/files
**Additional context**
Add any other context about the problem here.

View File

@ -147,5 +147,6 @@ func main() {
| Option | Type | Default | Description | | Option | Type | Default | Description |
|--------------------------|--------|------------|---------------------------------------------------------------------------| |--------------------------|--------|------------|---------------------------------------------------------------------------|
| URL | string | "doc.json" | URL pointing to API definition | | URL | string | "doc.json" | URL pointing to API definition |
| DeepLinking | bool | true | Swagger deeplinking configuration | | DocExpantion | string | "list" | Controls the default expansion setting for the operations and tags. It can be 'list' (expands only the tags), 'full' (expands the tags and operations) or 'none' (expands nothing). |
| DeepLinking | bool | true | If set to true, enables deep linking for tags and operations. See the Deep Linking documentation for more information.|
| DefaultModelsExpandDepth | int | 1 | Default expansion depth for models (set to -1 completely hide the models) | | DefaultModelsExpandDepth | int | 1 | Default expansion depth for models (set to -1 completely hide the models) |

View File

@ -4,8 +4,8 @@ import (
"html/template" "html/template"
"net/http" "net/http"
"os" "os"
"path/filepath"
"regexp" "regexp"
"strings"
"sync" "sync"
"golang.org/x/net/webdav" "golang.org/x/net/webdav"
@ -19,6 +19,7 @@ type Config struct {
//The url pointing to API definition (normally swagger.json or swagger.yaml). Default is `doc.json`. //The url pointing to API definition (normally swagger.json or swagger.yaml). Default is `doc.json`.
URL string URL string
DeepLinking bool DeepLinking bool
DocExpansion string
DefaultModelsExpandDepth int DefaultModelsExpandDepth int
} }
@ -29,6 +30,13 @@ func URL(url string) func(c *Config) {
} }
} }
// DocExpansion list, full, none.
func DocExpansion(docExpansion string) func(c *Config) {
return func(c *Config) {
c.DocExpansion = docExpansion
}
}
// DeepLinking set the swagger deeplinking configuration // DeepLinking set the swagger deeplinking configuration
func DeepLinking(deepLinking bool) func(c *Config) { func DeepLinking(deepLinking bool) func(c *Config) {
return func(c *Config) { return func(c *Config) {
@ -49,6 +57,7 @@ func WrapHandler(h *webdav.Handler, confs ...func(c *Config)) gin.HandlerFunc {
defaultConfig := &Config{ defaultConfig := &Config{
URL: "doc.json", URL: "doc.json",
DeepLinking: true, DeepLinking: true,
DocExpansion: "list",
DefaultModelsExpandDepth: 1, DefaultModelsExpandDepth: 1,
} }
@ -60,52 +69,43 @@ func WrapHandler(h *webdav.Handler, confs ...func(c *Config)) gin.HandlerFunc {
} }
// CustomWrapHandler wraps `http.Handler` into `gin.HandlerFunc` // CustomWrapHandler wraps `http.Handler` into `gin.HandlerFunc`
func CustomWrapHandler(config *Config, h *webdav.Handler) gin.HandlerFunc { func CustomWrapHandler(config *Config, handler *webdav.Handler) gin.HandlerFunc {
//create a template with name var once sync.Once
// create a template with name
t := template.New("swagger_index.html") t := template.New("swagger_index.html")
index, _ := t.Parse(swagger_index_templ) index, _ := t.Parse(swagger_index_templ)
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)[\?|.]*`) 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)[\?|.]*`)
var locker sync.RWMutex
return func(c *gin.Context) { return func(c *gin.Context) {
matches := rexp.FindStringSubmatch(c.Request.RequestURI)
type swaggerUIBundle struct { if len(matches) != 3 {
URL string
DeepLinking bool
DefaultModelsExpandDepth int
}
var matches []string
if matches = rexp.FindStringSubmatch(c.Request.RequestURI); len(matches) != 3 {
c.Status(404) c.Status(404)
c.Writer.Write([]byte("404 page not found")) _, _ = c.Writer.Write([]byte("404 page not found"))
return return
} }
path := matches[2] path := matches[2]
prefix := matches[1] once.Do(func() {
handler.Prefix = matches[1]
})
locker.Lock() switch filepath.Ext(path) {
h.Prefix = prefix case ".html":
locker.Unlock()
if strings.HasSuffix(path, ".html") {
c.Header("Content-Type", "text/html; charset=utf-8") c.Header("Content-Type", "text/html; charset=utf-8")
} else if strings.HasSuffix(path, ".css") { case ".css":
c.Header("Content-Type", "text/css; charset=utf-8") c.Header("Content-Type", "text/css; charset=utf-8")
} else if strings.HasSuffix(path, ".js") { case ".js":
c.Header("Content-Type", "application/javascript") c.Header("Content-Type", "application/javascript")
} else if strings.HasSuffix(path, ".json") { case ".json":
c.Header("Content-Type", "application/json; charset=utf-8") c.Header("Content-Type", "application/json; charset=utf-8")
} }
switch path { switch path {
case "index.html": case "index.html":
index.Execute(c.Writer, &swaggerUIBundle{ _ = index.Execute(c.Writer, config)
URL: config.URL,
DeepLinking: config.DeepLinking,
DefaultModelsExpandDepth: config.DefaultModelsExpandDepth,
})
case "doc.json": case "doc.json":
doc, err := swag.ReadDoc() doc, err := swag.ReadDoc()
if err != nil { if err != nil {
@ -113,11 +113,9 @@ func CustomWrapHandler(config *Config, h *webdav.Handler) gin.HandlerFunc {
return return
} }
c.Writer.Write([]byte(doc)) _, _ = c.Writer.Write([]byte(doc))
default: default:
locker.RLock() handler.ServeHTTP(c.Writer, c.Request)
h.ServeHTTP(c.Writer, c.Request)
locker.RUnlock()
} }
} }
} }
@ -238,6 +236,7 @@ window.onload = function() {
SwaggerUIBundle.plugins.DownloadUrl SwaggerUIBundle.plugins.DownloadUrl
], ],
layout: "StandaloneLayout", layout: "StandaloneLayout",
docExpansion: "{{.DocExpansion}}",
deepLinking: {{.DeepLinking}}, deepLinking: {{.DeepLinking}},
defaultModelsExpandDepth: {{.DefaultModelsExpandDepth}} defaultModelsExpandDepth: {{.DefaultModelsExpandDepth}}
}) })

View File

@ -1,13 +1,14 @@
package ginSwagger package ginSwagger
import ( import (
"github.com/gin-contrib/gzip"
"github.com/swaggo/swag"
"net/http/httptest" "net/http/httptest"
"os" "os"
"path/filepath"
"testing" "testing"
"github.com/gin-contrib/gzip"
"github.com/swaggo/swag"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/swaggo/gin-swagger/swaggerFiles" "github.com/swaggo/gin-swagger/swaggerFiles"
@ -74,7 +75,7 @@ func TestDisablingWrapHandler(t *testing.T) {
w4 := performRequest("GET", "/simple/notfound", router) w4 := performRequest("GET", "/simple/notfound", router)
assert.Equal(t, 404, w4.Code) assert.Equal(t, 404, w4.Code)
os.Setenv(disablingKey, "true") _ = os.Setenv(disablingKey, "true")
router.GET("/disabling/*any", DisablingWrapHandler(swaggerFiles.Handler, disablingKey)) router.GET("/disabling/*any", DisablingWrapHandler(swaggerFiles.Handler, disablingKey))
@ -102,7 +103,7 @@ func TestDisablingCustomWrapHandler(t *testing.T) {
w1 := performRequest("GET", "/simple/index.html", router) w1 := performRequest("GET", "/simple/index.html", router)
assert.Equal(t, 200, w1.Code) assert.Equal(t, 200, w1.Code)
os.Setenv(disablingKey, "true") _ = os.Setenv(disablingKey, "true")
router.GET("/disabling/*any", DisablingCustomWrapHandler(&Config{}, swaggerFiles.Handler, disablingKey)) router.GET("/disabling/*any", DisablingCustomWrapHandler(&Config{}, swaggerFiles.Handler, disablingKey))
@ -143,25 +144,63 @@ func performRequest(method, target string, router *gin.Engine) *httptest.Respons
} }
func TestURL(t *testing.T) { func TestURL(t *testing.T) {
expected := "https://github.com/swaggo/http-swagger"
cfg := Config{} cfg := Config{}
expected := "https://github.com/swaggo/http-swagger"
configFunc := URL(expected) configFunc := URL(expected)
configFunc(&cfg) configFunc(&cfg)
assert.Equal(t, expected, cfg.URL) assert.Equal(t, expected, cfg.URL)
} }
func TestDeepLinking(t *testing.T) { func TestDocExpansion(t *testing.T) {
expected := true var cfg Config
cfg := Config{}
configFunc := DeepLinking(expected) expected := "list"
configFunc := DocExpansion(expected)
configFunc(&cfg) configFunc(&cfg)
assert.Equal(t, expected, cfg.DeepLinking) assert.Equal(t, expected, cfg.DocExpansion)
expected = "full"
configFunc = DocExpansion(expected)
configFunc(&cfg)
assert.Equal(t, expected, cfg.DocExpansion)
expected = "none"
configFunc = DocExpansion(expected)
configFunc(&cfg)
assert.Equal(t, expected, cfg.DocExpansion)
}
func TestDeepLinking(t *testing.T) {
var cfg Config
assert.Equal(t, false, cfg.DeepLinking)
configFunc := DeepLinking(true)
configFunc(&cfg)
assert.Equal(t, true, cfg.DeepLinking)
configFunc = DeepLinking(false)
configFunc(&cfg)
assert.Equal(t, false, cfg.DeepLinking)
} }
func TestDefaultModelsExpandDepth(t *testing.T) { func TestDefaultModelsExpandDepth(t *testing.T) {
var cfg Config
assert.Equal(t, 0, cfg.DefaultModelsExpandDepth)
expected := -1 expected := -1
cfg := Config{}
configFunc := DefaultModelsExpandDepth(expected) configFunc := DefaultModelsExpandDepth(expected)
configFunc(&cfg) configFunc(&cfg)
assert.Equal(t, expected, cfg.DefaultModelsExpandDepth) assert.Equal(t, expected, cfg.DefaultModelsExpandDepth)
expected = 1
configFunc = DefaultModelsExpandDepth(expected)
configFunc(&cfg)
assert.Equal(t, expected, cfg.DefaultModelsExpandDepth)
}
func TestDeepLinking2(t *testing.T) {
t.Logf("extension: %s", filepath.Ext("/asas/index.html"))
} }