#23 Fix bug of matching path for spec

This commit is contained in:
elvinchan 2019-05-13 10:10:24 +08:00
parent 795eb4e894
commit d715040d11
9 changed files with 58 additions and 31 deletions

View File

@ -31,7 +31,7 @@ import (
func main() { func main() {
// ApiRoot with Echo instance // ApiRoot with Echo instance
r := echoswagger.New(echo.New(), "doc/", nil) r := echoswagger.New(echo.New(), "/doc", nil)
// Routes with parameters & responses // Routes with parameters & responses
r.POST("/", createUser). r.POST("/", createUser).
@ -56,7 +56,7 @@ func createUser(c echo.Context) error {
## Usage ## Usage
#### Create a `ApiRoot` with `New()`, which is a wrapper of `echo.New()` #### Create a `ApiRoot` with `New()`, which is a wrapper of `echo.New()`
``` ```
r := echoswagger.New(echo.New(), "doc/", nil) r := echoswagger.New(echo.New(), "/doc", nil)
``` ```
You can use the result `ApiRoot` instance to: You can use the result `ApiRoot` instance to:
- Setup Security definitions, request/response Content-Types, UI options, Scheme, etc. - Setup Security definitions, request/response Content-Types, UI options, Scheme, etc.

View File

@ -31,7 +31,7 @@ import (
func main() { func main() {
// ApiRoot with Echo instance // ApiRoot with Echo instance
r := echoswagger.New(echo.New(), "doc/", nil) r := echoswagger.New(echo.New(), "/doc", nil)
// Routes with parameters & responses // Routes with parameters & responses
r.POST("/", createUser). r.POST("/", createUser).
@ -56,7 +56,7 @@ func createUser(c echo.Context) error {
## 用法 ## 用法
#### 用`New()`创建`ApiRoot`,此方法是对`echo.New()`方法的封装 #### 用`New()`创建`ApiRoot`,此方法是对`echo.New()`方法的封装
``` ```
r := echoswagger.New(echo.New(), "/v1", "doc/", nil) r := echoswagger.New(echo.New(), "/doc", nil)
``` ```
你可以用这个`ApiRoot`来: 你可以用这个`ApiRoot`来:
- 设置Security定义, 请求/响应Content-TypeUI选项Scheme等。 - 设置Security定义, 请求/响应Content-TypeUI选项Scheme等。

View File

@ -51,11 +51,23 @@ const SwaggerUIContent = `{{define "swagger"}}
if (!window.location.pathname.endsWith("/")) { if (!window.location.pathname.endsWith("/")) {
specPath = "/" + specPath specPath = "/" + specPath
} }
var spec = "{{.spec}}" var specStr = "{{.spec}}"
var spec = specStr ? JSON.parse(specStr) : undefined
if (spec) {
spec.host = window.location.host
var docPath = "{{.docPath}}"
var basePath = window.location.pathname
if (!docPath.endsWith("/")) { docPath += "/" }
if (!basePath.endsWith("/")) { basePath += "/" }
if (basePath.endsWith(docPath)) {
basePath = basePath.slice(0, -docPath.length)
}
spec.basePath = basePath
}
// Build a system // Build a system
const ui = SwaggerUIBundle({ const ui = SwaggerUIBundle({
url: window.location.origin+window.location.pathname+specPath, url: window.location.origin+window.location.pathname+specPath,
spec: spec ? JSON.parse(spec) : undefined, spec: spec,
dom_id: '#swagger-ui', dom_id: '#swagger-ui',
deepLinking: true, deepLinking: true,
presets: [ presets: [

View File

@ -36,7 +36,7 @@ func initServer() echoswagger.ApiRoot {
se.SetExternalDocs("Find out more about Swagger", "http://swagger.io"). se.SetExternalDocs("Find out more about Swagger", "http://swagger.io").
SetResponseContentType("application/xml", "application/json"). SetResponseContentType("application/xml", "application/json").
SetUI(echoswagger.UISetting{HideTop: true}). SetUI(echoswagger.UISetting{DetachSpec: true, HideTop: true}).
SetScheme("https", "http") SetScheme("https", "http")
PetController{}.Init(se.Group("pet", "/pet")) PetController{}.Init(se.Group("pet", "/pet"))

View File

@ -13,8 +13,6 @@
}, },
"version": "1.0.0" "version": "1.0.0"
}, },
"host": "example.com",
"basePath": "/",
"schemes": [ "schemes": [
"https", "https",
"http" "http"

View File

@ -59,6 +59,7 @@ func (r *Root) docHandler(docPath string) echo.HandlerFunc {
return c.String(http.StatusInternalServerError, err.Error()) return c.String(http.StatusInternalServerError, err.Error())
} }
params["spec"] = string(b) params["spec"] = string(b)
params["docPath"] = docPath
params["hideTop"] = true params["hideTop"] = true
} else { } else {
params["hideTop"] = r.ui.HideTop params["hideTop"] = r.ui.HideTop

23
spec.go
View File

@ -21,11 +21,20 @@ func (r *Root) specHandler(docPath string) echo.HandlerFunc {
if err != nil { if err != nil {
return c.String(http.StatusInternalServerError, err.Error()) return c.String(http.StatusInternalServerError, err.Error())
} }
var basePath string
if uri, err := url.ParseRequestURI(c.Request().Referer()); err == nil {
basePath = trimSuffixSlash(uri.Path, docPath)
spec.Host = uri.Host
} else {
basePath = trimSuffixSlash(c.Request().URL.Path, connectPath(docPath, SpecName))
spec.Host = c.Request().Host
}
spec.BasePath = basePath
return c.JSON(http.StatusOK, spec) return c.JSON(http.StatusOK, spec)
} }
} }
// Generate swagger spec data // Generate swagger spec data, without host & basePath info
func (r *Root) GetSpec(c echo.Context, docPath string) (Swagger, error) { func (r *Root) GetSpec(c echo.Context, docPath string) (Swagger, error) {
r.once.Do(func() { r.once.Do(func() {
r.err = r.genSpec(c) r.err = r.genSpec(c)
@ -34,17 +43,7 @@ func (r *Root) GetSpec(c echo.Context, docPath string) (Swagger, error) {
if r.err != nil { if r.err != nil {
return Swagger{}, r.err return Swagger{}, r.err
} }
swagger := *r.spec return *r.spec, nil
var basePath string
if uri, err := url.ParseRequestURI(c.Request().Referer()); err == nil {
basePath = trimSuffixSlash(uri.Path, docPath)
swagger.Host = uri.Host
} else {
basePath = trimSuffixSlash(c.Request().URL.Path, connectPath(docPath, SpecName))
swagger.Host = c.Request().Host
}
swagger.BasePath = connectPath(basePath)
return swagger, nil
} }
func (r *Root) genSpec(c echo.Context) error { func (r *Root) genSpec(c echo.Context) error {

View File

@ -20,7 +20,7 @@ func TestSpec(t *testing.T) {
req := httptest.NewRequest(echo.GET, "/doc/swagger.json", nil) req := httptest.NewRequest(echo.GET, "/doc/swagger.json", nil)
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
c := e.NewContext(req, rec) c := e.NewContext(req, rec)
j := `{"swagger":"2.0","info":{"title":"Project APIs","version":""},"host":"example.com","basePath":"/","paths":{}}` j := `{"swagger":"2.0","info":{"title":"Project APIs","version":""},"host":"example.com","paths":{}}`
if assert.NoError(t, r.(*Root).specHandler("/doc/")(c)) { if assert.NoError(t, r.(*Root).specHandler("/doc/")(c)) {
assert.Equal(t, http.StatusOK, rec.Code) assert.Equal(t, http.StatusOK, rec.Code)
assert.JSONEq(t, j, rec.Body.String()) assert.JSONEq(t, j, rec.Body.String())
@ -33,7 +33,22 @@ func TestSpec(t *testing.T) {
req := httptest.NewRequest(echo.GET, "/doc/swagger.json", nil) req := httptest.NewRequest(echo.GET, "/doc/swagger.json", nil)
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
c := e.NewContext(req, rec) c := e.NewContext(req, rec)
j := `{"swagger":"2.0","info":{"title":"Project APIs","version":""},"host":"example.com","basePath":"/","paths":{}}` j := `{"swagger":"2.0","info":{"title":"Project APIs","version":""},"paths":{}}`
s, err := r.(*Root).GetSpec(c, "/doc/")
assert.Nil(t, err)
rs, err := json.Marshal(s)
assert.Nil(t, err)
assert.JSONEq(t, j, string(rs))
})
t.Run("BasicIntegrated", func(t *testing.T) {
r := prepareApiRoot()
r.SetUI(UISetting{DetachSpec: false})
e := r.(*Root).echo
req := httptest.NewRequest(echo.GET, "/doc", nil)
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)
j := `{"swagger":"2.0","info":{"title":"Project APIs","version":""},"paths":{}}`
s, err := r.(*Root).GetSpec(c, "/doc/") s, err := r.(*Root).GetSpec(c, "/doc/")
assert.Nil(t, err) assert.Nil(t, err)
rs, err := json.Marshal(s) rs, err := json.Marshal(s)
@ -83,7 +98,7 @@ func TestSpec(t *testing.T) {
req := httptest.NewRequest(echo.GET, "/doc/swagger.json", nil) req := httptest.NewRequest(echo.GET, "/doc/swagger.json", nil)
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
c := e.NewContext(req, rec) c := e.NewContext(req, rec)
j := `{"swagger":"2.0","info":{"title":"Project APIs","version":""},"host":"example.com","basePath":"/","paths":{"/ping":{"get":{"responses":{"default":{"description":"successful operation"}}}},"/users/{id}":{"delete":{"tags":["Users"],"responses":{"default":{"description":"successful operation"}}}}},"tags":[{"name":"Users"}]}` j := `{"swagger":"2.0","info":{"title":"Project APIs","version":""},"host":"example.com","paths":{"/ping":{"get":{"responses":{"default":{"description":"successful operation"}}}},"/users/{id}":{"delete":{"tags":["Users"],"responses":{"default":{"description":"successful operation"}}}}},"tags":[{"name":"Users"}]}`
if assert.NoError(t, r.(*Root).specHandler("/doc")(c)) { if assert.NoError(t, r.(*Root).specHandler("/doc")(c)) {
assert.Equal(t, http.StatusOK, rec.Code) assert.Equal(t, http.StatusOK, rec.Code)
assert.JSONEq(t, j, rec.Body.String()) assert.JSONEq(t, j, rec.Body.String())
@ -105,21 +120,21 @@ func TestReferer(t *testing.T) {
host: "localhost:1323", host: "localhost:1323",
docPath: "/doc", docPath: "/doc",
name: "A", name: "A",
basePath: "/", basePath: "",
}, },
{ {
referer: "http://localhost:1323/doc", referer: "http://localhost:1323/doc",
host: "localhost:1323", host: "localhost:1323",
docPath: "/doc/", docPath: "/doc/",
name: "B", name: "B",
basePath: "/", basePath: "",
}, },
{ {
referer: "http://localhost:1323/doc/", referer: "http://localhost:1323/doc/",
host: "localhost:1323", host: "localhost:1323",
docPath: "/doc", docPath: "/doc",
name: "C", name: "C",
basePath: "/", basePath: "",
}, },
{ {
referer: "http://localhost:1323/api/v1/doc", referer: "http://localhost:1323/api/v1/doc",
@ -133,14 +148,14 @@ func TestReferer(t *testing.T) {
host: "127.0.0.1", host: "127.0.0.1",
docPath: "/doc", docPath: "/doc",
name: "E", name: "E",
basePath: "/", basePath: "",
}, },
{ {
referer: "http://user:pass@github.com", referer: "http://user:pass@github.com",
host: "github.com", host: "github.com",
docPath: "/", docPath: "/",
name: "F", name: "F",
basePath: "/", basePath: "",
}, },
{ {
referer: "https://www.github.com/v1/docs/?q=1", referer: "https://www.github.com/v1/docs/?q=1",
@ -154,7 +169,7 @@ func TestReferer(t *testing.T) {
host: "www.github.com", host: "www.github.com",
docPath: "", docPath: "",
name: "H", name: "H",
basePath: "/", basePath: "",
}, },
{ {
referer: "https://www.github.com/", referer: "https://www.github.com/",

View File

@ -12,7 +12,9 @@ import (
) )
func prepareApiRoot() ApiRoot { func prepareApiRoot() ApiRoot {
return New(echo.New(), "doc/", nil) r := New(echo.New(), "doc/", nil)
r.SetUI(UISetting{DetachSpec: true})
return r
} }
func prepareApiGroup() ApiGroup { func prepareApiGroup() ApiGroup {