Add SetUI & other http methods

This commit is contained in:
ElvinChan 2018-09-03 22:52:30 +08:00
parent 7b5e1d762c
commit 0a9d6de748
6 changed files with 464 additions and 51 deletions

View File

@ -1,14 +1,17 @@
package echoswagger
// CDN refer to https://www.jsdelivr.com/package/npm/swagger-ui-dist
const DefaultCDN = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@3.18.1"
const SwaggerUIContent = `{{define "swagger"}}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{.title}}</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@3.17.6/swagger-ui.css" crossorigin="anonymous" />
<link rel="icon" type="image/png" href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@3.17.6/favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@3.17.6/favicon-16x16.png" sizes="16x16" />
<link rel="stylesheet" href="{{.cdn}}/swagger-ui.css" crossorigin="anonymous" />
<link rel="icon" type="image/png" href="{{.cdn}}/favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="{{.cdn}}/favicon-16x16.png" sizes="16x16" />
<style>
html
{
@ -29,14 +32,19 @@ const SwaggerUIContent = `{{define "swagger"}}
margin:0;
background: #fafafa;
}
{{if .hideTop}}#swagger-ui>.swagger-container>.topbar
{
display: none;
}{{end}}
</style>
</head>
<body>
<div id="swagger-ui"></div>
<script src="https://cdn.jsdelivr.net/npm/swagger-ui-dist@3.17.6/swagger-ui-bundle.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/swagger-ui-dist@3.17.6/swagger-ui-standalone-preset.js" crossorigin="anonymous"></script>
<script src="{{.cdn}}/swagger-ui-bundle.js" crossorigin="anonymous"></script>
<script src="{{.cdn}}/swagger-ui-standalone-preset.js" crossorigin="anonymous"></script>
<script>
window.onload = function() {

View File

@ -37,11 +37,18 @@ func (r *Root) docHandler(swaggerPath string) echo.HandlerFunc {
panic(err)
}
cdn := DefaultCDN
if r.ui.CDN != "" {
cdn = r.ui.CDN
}
return func(c echo.Context) error {
buf := new(bytes.Buffer)
t.Execute(buf, map[string]interface{}{
"title": r.spec.Info.Title,
"url": c.Scheme() + "://" + c.Request().Host + swaggerPath,
"hideTop": r.ui.HideTop,
"cdn": cdn,
})
return c.HTMLBlob(http.StatusOK, buf.Bytes())
}
@ -62,14 +69,13 @@ func (r *RawDefineDic) getKey(v reflect.Value) (bool, string) {
return false, name
}
func (r *routers) appendRoute(method string, route *echo.Route) *api {
func (r *routers) appendRoute(route *echo.Route) *api {
opr := Operation{
Responses: make(map[string]*Response),
}
a := api{
route: route,
defs: r.defs,
method: method,
operation: opr,
}
r.apis = append(r.apis, a)

12
spec.go
View File

@ -69,10 +69,10 @@ func (r *Root) transfer(a *api) error {
}
if p, ok := r.spec.Paths[path]; ok {
p.(*Path).oprationAssign(a.method, &a.operation)
p.(*Path).oprationAssign(a.route.Method, &a.operation)
} else {
p := &Path{}
p.oprationAssign(a.method, &a.operation)
p.oprationAssign(a.route.Method, &a.operation)
r.spec.Paths[path] = p
}
return nil
@ -86,10 +86,14 @@ func (p *Path) oprationAssign(method string, operation *Operation) {
p.Post = operation
case echo.PUT:
p.Put = operation
case echo.PATCH:
p.Patch = operation
case echo.DELETE:
p.Delete = operation
case echo.OPTIONS:
p.Options = operation
case echo.HEAD:
p.Head = operation
case echo.PATCH:
p.Patch = operation
}
}

View File

@ -37,7 +37,7 @@ func isValidParam(t reflect.Type, nest, inner bool) bool {
case reflect.Ptr:
return isValidParam(t.Elem(), nest, inner)
case reflect.Struct:
if t == reflect.TypeOf(time.Time{}) {
if t == reflect.TypeOf(time.Time{}) && (!nest || nest && inner) {
return true
} else if !inner {
for i := 0; i < t.NumField(); i++ {

View File

@ -21,23 +21,32 @@ Notice:
*/
type ApiRouter interface {
// GET overrides `Echo#GET()` for sub-routes within the ApiGroup.
// GET overrides `Echo#GET()` and creates Api.
GET(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) Api
// POST overrides `Echo#POST()` for sub-routes within the ApiGroup.
// POST overrides `Echo#POST()` and creates Api.
POST(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) Api
// PUT overrides `Echo#PUT()` for sub-routes within the ApiGroup.
// PUT overrides `Echo#PUT()` and creates Api.
PUT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) Api
// DELETE overrides `Echo#DELETE()` for sub-routes within the ApiGroup.
// DELETE overrides `Echo#DELETE()` and creates Api.
DELETE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) Api
// OPTIONS overrides `Echo#OPTIONS()` and creates Api.
OPTIONS(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) Api
// HEAD overrides `Echo#HEAD()` and creates Api.
HEAD(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) Api
// PATCH overrides `Echo#PATCH()` and creates Api.
PATCH(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) Api
}
type ApiRoot interface {
ApiRouter
// ApiGroup creates ApiGroup. Use this instead of Echo#ApiGroup.
// Group overrides `Echo#Group()` and creates ApiGroup.
Group(name, prefix string, m ...echo.MiddlewareFunc) ApiGroup
// SetRequestContentType sets request content types.
@ -58,13 +67,16 @@ type ApiRoot interface {
// AddSecurityOAuth2 adds `SecurityDefinition` with type oauth2.
AddSecurityOAuth2(name, desc string, flow OAuth2FlowType, authorizationUrl, tokenUrl string, scopes map[string]string) ApiRoot
// SetUI sets UI setting.
SetUI(ui UISetting) ApiRoot
// GetRaw returns raw `Swagger`. Only special case should use.
GetRaw() *Swagger
// SetRaw sets raw `Swagger` to ApiRoot. Only special case should use.
SetRaw(s *Swagger) ApiRoot
// Echo returns the embeded echo instance
// Echo returns the embedded Echo instance
Echo() *echo.Echo
}
@ -78,16 +90,16 @@ type ApiGroup interface {
SetExternalDocs(desc, url string) ApiGroup
// SetSecurity sets Security for all operations within the ApiGroup
// which names are reigisters by AddSecurity... functions.
// which names are reigistered by AddSecurity... functions.
SetSecurity(names ...string) ApiGroup
// SetSecurity sets Security with scopes for all operations
// within the ApiGroup which names are reigisters
// SetSecurityWithScope sets Security with scopes for all operations
// within the ApiGroup which names are reigistered
// by AddSecurity... functions.
// Should only use when Security type is oauth2.
SetSecurityWithScope(s map[string][]string) ApiGroup
// EchoGroup returns `*echo.Group` within the ApiGroup.
// EchoGroup returns the embedded `echo.Group` instance.
EchoGroup() *echo.Group
}
@ -96,36 +108,41 @@ type Api interface {
AddParamPath(p interface{}, name, desc string) Api
// AddParamPathNested adds path parameters nested in p.
// P must be struct type.
AddParamPathNested(p interface{}) Api
// AddParamQuery adds query parameter.
AddParamQuery(p interface{}, name, desc string, required bool) Api
// AddParamQueryNested adds query parameters nested in p.
// P must be struct type.
AddParamQueryNested(p interface{}) Api
// AddParamForm adds formData parameter.
AddParamForm(p interface{}, name, desc string, required bool) Api
// AddParamFormNested adds formData parameters nested in p.
// P must be struct type.
AddParamFormNested(p interface{}) Api
// AddParamHeader adds header parameter.
AddParamHeader(p interface{}, name, desc string, required bool) Api
// AddParamHeaderNested adds header parameters nested in p.
// P must be struct type.
AddParamHeaderNested(p interface{}) Api
// AddParamBody adds body parameter.
AddParamBody(p interface{}, name, desc string, required bool) Api
// AddParamBody adds file parameter.
// AddParamFile adds file parameter.
AddParamFile(name, desc string, required bool) Api
// AddResponse adds response for Api.
// Header must be struct type.
AddResponse(code int, desc string, schema interface{}, header interface{}) Api
// SetResponseContentType sets request content types.
// SetRequestContentType sets request content types.
SetRequestContentType(types ...string) Api
// SetResponseContentType sets response content types.
@ -134,7 +151,7 @@ type Api interface {
// SetOperationId sets operationId
SetOperationId(id string) Api
// SetDescription marks Api as deprecated.
// SetDeprecated marks Api as deprecated.
SetDeprecated() Api
// SetDescription sets description.
@ -143,19 +160,20 @@ type Api interface {
// SetExternalDocs sets external docs.
SetExternalDocs(desc, url string) Api
// SetExternalDocs sets summary.
// SetSummary sets summary.
SetSummary(summary string) Api
// SetSecurity sets Security which names are reigisters
// SetSecurity sets Security which names are reigistered
// by AddSecurity... functions.
SetSecurity(names ...string) Api
// SetSecurity sets Security for Api which names are
// reigisters by AddSecurity... functions.
// SetSecurityWithScope sets Security for Api which names are
// reigistered by AddSecurity... functions.
// Should only use when Security type is oauth2.
SetSecurityWithScope(s map[string][]string) Api
// TODO return echo.Router
// Route returns the embedded `echo.Route` instance.
Route() *echo.Route
}
type routers struct {
@ -168,6 +186,7 @@ type Root struct {
spec *Swagger
echo *echo.Echo
groups []group
ui UISetting
once sync.Once
err error
}
@ -183,7 +202,6 @@ type api struct {
route *echo.Route
defs *RawDefineDic
security []map[string][]string
method string
operation Operation
}
@ -227,24 +245,36 @@ func New(e *echo.Echo, basePath, docPath string, i *Info) ApiRoot {
}
func (r *Root) GET(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) Api {
return r.appendRoute(echo.GET, r.echo.GET(path, h, m...))
return r.appendRoute(r.echo.GET(path, h, m...))
}
func (r *Root) POST(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) Api {
return r.appendRoute(echo.POST, r.echo.POST(path, h, m...))
return r.appendRoute(r.echo.POST(path, h, m...))
}
func (r *Root) PUT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) Api {
return r.appendRoute(echo.PUT, r.echo.PUT(path, h, m...))
return r.appendRoute(r.echo.PUT(path, h, m...))
}
func (r *Root) DELETE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) Api {
return r.appendRoute(echo.DELETE, r.echo.DELETE(path, h, m...))
return r.appendRoute(r.echo.DELETE(path, h, m...))
}
func (r *Root) OPTIONS(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) Api {
return r.appendRoute(r.echo.OPTIONS(path, h, m...))
}
func (r *Root) HEAD(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) Api {
return r.appendRoute(r.echo.HEAD(path, h, m...))
}
func (r *Root) PATCH(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) Api {
return r.appendRoute(r.echo.PATCH(path, h, m...))
}
func (r *Root) Group(name, prefix string, m ...echo.MiddlewareFunc) ApiGroup {
if name == "" {
panic("echowagger: invalid name of ApiGroup")
panic("echoswagger: invalid name of ApiGroup")
}
echoGroup := r.echo.Group(prefix, m...)
group := group{
@ -330,6 +360,11 @@ func (r *Root) AddSecurityOAuth2(name, desc string, flow OAuth2FlowType, authori
return r
}
func (r *Root) SetUI(ui UISetting) ApiRoot {
r.ui = ui
return r
}
func (r *Root) GetRaw() *Swagger {
return r.spec
}
@ -344,25 +379,43 @@ func (r *Root) Echo() *echo.Echo {
}
func (g *group) GET(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) Api {
a := g.appendRoute(echo.GET, g.echoGroup.GET(path, h, m...))
a := g.appendRoute(g.echoGroup.GET(path, h, m...))
a.operation.Tags = []string{g.tag.Name}
return a
}
func (g *group) POST(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) Api {
a := g.appendRoute(echo.POST, g.echoGroup.POST(path, h, m...))
a := g.appendRoute(g.echoGroup.POST(path, h, m...))
a.operation.Tags = []string{g.tag.Name}
return a
}
func (g *group) PUT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) Api {
a := g.appendRoute(echo.PUT, g.echoGroup.PUT(path, h, m...))
a := g.appendRoute(g.echoGroup.PUT(path, h, m...))
a.operation.Tags = []string{g.tag.Name}
return a
}
func (g *group) DELETE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) Api {
a := g.appendRoute(echo.DELETE, g.echoGroup.DELETE(path, h, m...))
a := g.appendRoute(g.echoGroup.DELETE(path, h, m...))
a.operation.Tags = []string{g.tag.Name}
return a
}
func (g *group) OPTIONS(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) Api {
a := g.appendRoute(g.echoGroup.OPTIONS(path, h, m...))
a.operation.Tags = []string{g.tag.Name}
return a
}
func (g *group) HEAD(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) Api {
a := g.appendRoute(g.echoGroup.HEAD(path, h, m...))
a.operation.Tags = []string{g.tag.Name}
return a
}
func (g *group) PATCH(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) Api {
a := g.appendRoute(g.echoGroup.PATCH(path, h, m...))
a.operation.Tags = []string{g.tag.Name}
return a
}
@ -445,7 +498,6 @@ func (a *api) AddParamFile(name, desc string, required bool) Api {
return a
}
// Notice: header must be nested in a struct.
func (a *api) AddResponse(code int, desc string, schema interface{}, header interface{}) Api {
r := &Response{
Description: desc,
@ -522,3 +574,7 @@ func (a *api) SetSecurityWithScope(s map[string][]string) Api {
a.security = setSecurityWithScope(a.security, s)
return a
}
func (a *api) Route() *echo.Route {
return a.route
}

View File

@ -1,12 +1,31 @@
package echoswagger
import (
"net/http"
"net/http/httptest"
"strconv"
"testing"
"time"
"github.com/labstack/echo"
"github.com/stretchr/testify/assert"
)
func prepareApiRoot() ApiRoot {
return New(echo.New(), "/", "doc/", nil)
}
func prepareApiGroup() ApiGroup {
r := prepareApiRoot()
return r.Group("G", "/g")
}
func prepareApi() Api {
g := prepareApiGroup()
var h func(e echo.Context) error
return g.POST("", h)
}
func TestNew(t *testing.T) {
tests := []struct {
echo *echo.Echo
@ -56,22 +75,342 @@ func TestNew(t *testing.T) {
apiRoot := New(tt.echo, tt.basePath, tt.docPath, tt.info)
assert.NotNil(t, apiRoot.(*Root))
root := apiRoot.(*Root)
assert.NotNil(t, root.spec)
r := apiRoot.(*Root)
assert.NotNil(t, r.spec)
assert.Equal(t, root.spec.BasePath, tt.basePath)
assert.Equal(t, r.spec.BasePath, tt.basePath)
if tt.info == nil {
assert.Equal(t, root.spec.Info.Title, "Project APIs")
assert.Equal(t, r.spec.Info.Title, "Project APIs")
} else {
assert.Equal(t, root.spec.Info, tt.info)
assert.Equal(t, r.spec.Info, tt.info)
}
assert.NotNil(t, root.echo)
assert.Len(t, root.echo.Routes(), 2)
res := root.echo.Routes()
assert.NotNil(t, r.echo)
assert.Len(t, r.echo.Routes(), 2)
res := r.echo.Routes()
paths := []string{res[0].Path, res[1].Path}
assert.ElementsMatch(t, paths, tt.expectPaths)
}
})
}
}
func TestGroup(t *testing.T) {
r := prepareApiRoot()
t.Run("Normal", func(t *testing.T) {
g := r.Group("Users", "users")
assert.Equal(t, g.(*group).defs, r.(*Root).defs)
})
t.Run("Invalid name", func(t *testing.T) {
assert.Panics(t, func() {
r.Group("", "")
})
})
t.Run("Repeat name", func(t *testing.T) {
ga := r.Group("Users", "users")
assert.Equal(t, ga.(*group).tag.Name, "Users_1")
gb := r.Group("Users", "users")
assert.Equal(t, gb.(*group).tag.Name, "Users_2")
})
}
func TestRouters(t *testing.T) {
r := prepareApiRoot()
var h echo.HandlerFunc
r.GET("/:id", h)
r.POST("/:id", h)
r.PUT("/:id", h)
r.DELETE("/:id", h)
r.OPTIONS("/:id", h)
r.HEAD("/:id", h)
r.PATCH("/:id", h)
assert.Len(t, r.(*Root).apis, 7)
g := prepareApiGroup()
g.GET("/:id", h)
g.POST("/:id", h)
g.PUT("/:id", h)
g.DELETE("/:id", h)
g.OPTIONS("/:id", h)
g.HEAD("/:id", h)
g.PATCH("/:id", h)
assert.Len(t, g.(*group).apis, 7)
}
func TestAddParam(t *testing.T) {
name := "name"
desc := "Param desc"
type nested struct {
Name string `json:"name" form:"name" query:"name"`
Enable bool `json:"-" form:"-" query:"-"`
}
t.Run("File", func(t *testing.T) {
a := prepareApi()
a.AddParamFile(name, desc, true)
assert.Len(t, a.(*api).operation.Parameters, 1)
assert.Equal(t, a.(*api).operation.Parameters[0].Name, name)
assert.Equal(t, a.(*api).operation.Parameters[0].In, string(ParamInFormData))
assert.Equal(t, a.(*api).operation.Parameters[0].Description, desc)
assert.Equal(t, a.(*api).operation.Parameters[0].Required, true)
assert.Equal(t, a.(*api).operation.Parameters[0].Type, "file")
})
t.Run("Path", func(t *testing.T) {
a := prepareApi()
a.AddParamPath(time.Now(), name, desc)
assert.Len(t, a.(*api).operation.Parameters, 1)
assert.Equal(t, a.(*api).operation.Parameters[0].Name, name)
assert.Equal(t, a.(*api).operation.Parameters[0].In, string(ParamInPath))
assert.Equal(t, a.(*api).operation.Parameters[0].Description, desc)
assert.Equal(t, a.(*api).operation.Parameters[0].Required, true)
assert.Equal(t, a.(*api).operation.Parameters[0].Type, "string")
a.AddParamPathNested(&nested{})
assert.Len(t, a.(*api).operation.Parameters, 2)
assert.Equal(t, a.(*api).operation.Parameters[1].Name, "name_")
assert.Equal(t, a.(*api).operation.Parameters[1].In, string(ParamInPath))
assert.Equal(t, a.(*api).operation.Parameters[1].Type, "string")
})
t.Run("Query", func(t *testing.T) {
a := prepareApi()
a.AddParamQuery(time.Now(), name, desc, true)
assert.Len(t, a.(*api).operation.Parameters, 1)
assert.Equal(t, a.(*api).operation.Parameters[0].Name, name)
assert.Equal(t, a.(*api).operation.Parameters[0].In, string(ParamInQuery))
assert.Equal(t, a.(*api).operation.Parameters[0].Description, desc)
assert.Equal(t, a.(*api).operation.Parameters[0].Required, true)
assert.Equal(t, a.(*api).operation.Parameters[0].Type, "string")
a.AddParamQueryNested(&nested{})
assert.Len(t, a.(*api).operation.Parameters, 2)
assert.Equal(t, a.(*api).operation.Parameters[1].Name, "name_")
assert.Equal(t, a.(*api).operation.Parameters[1].In, string(ParamInQuery))
assert.Equal(t, a.(*api).operation.Parameters[1].Type, "string")
})
t.Run("FormData", func(t *testing.T) {
a := prepareApi()
a.AddParamForm(time.Now(), name, desc, true)
assert.Len(t, a.(*api).operation.Parameters, 1)
assert.Equal(t, a.(*api).operation.Parameters[0].Name, name)
assert.Equal(t, a.(*api).operation.Parameters[0].In, string(ParamInFormData))
assert.Equal(t, a.(*api).operation.Parameters[0].Description, desc)
assert.Equal(t, a.(*api).operation.Parameters[0].Required, true)
assert.Equal(t, a.(*api).operation.Parameters[0].Type, "string")
a.AddParamFormNested(&nested{})
assert.Len(t, a.(*api).operation.Parameters, 2)
assert.Equal(t, a.(*api).operation.Parameters[1].Name, "name_")
assert.Equal(t, a.(*api).operation.Parameters[1].In, string(ParamInFormData))
assert.Equal(t, a.(*api).operation.Parameters[1].Type, "string")
})
t.Run("Header", func(t *testing.T) {
a := prepareApi()
a.AddParamHeader(time.Now(), name, desc, true)
assert.Len(t, a.(*api).operation.Parameters, 1)
assert.Equal(t, a.(*api).operation.Parameters[0].Name, name)
assert.Equal(t, a.(*api).operation.Parameters[0].In, string(ParamInHeader))
assert.Equal(t, a.(*api).operation.Parameters[0].Description, desc)
assert.Equal(t, a.(*api).operation.Parameters[0].Required, true)
assert.Equal(t, a.(*api).operation.Parameters[0].Type, "string")
a.AddParamHeaderNested(&nested{})
assert.Len(t, a.(*api).operation.Parameters, 2)
assert.Equal(t, a.(*api).operation.Parameters[1].Name, "name_")
assert.Equal(t, a.(*api).operation.Parameters[1].In, string(ParamInHeader))
assert.Equal(t, a.(*api).operation.Parameters[1].Type, "string")
})
}
func TestAddSchema(t *testing.T) {
type body struct {
Name string `json:"name"`
Enable bool `json:"-"`
}
t.Run("Multiple", func(t *testing.T) {
a := prepareApi()
a.AddParamBody(&body{}, "body", "body desc", true)
assert.Len(t, a.(*api).operation.Parameters, 1)
assert.Equal(t, a.(*api).operation.Parameters[0].Name, "body")
assert.Equal(t, a.(*api).operation.Parameters[0].In, string(ParamInBody))
assert.Equal(t, a.(*api).operation.Parameters[0].Description, "body desc")
assert.Equal(t, a.(*api).operation.Parameters[0].Required, true)
assert.Panics(t, func() {
a.AddParamBody(body{}, "body", "body desc", true)
})
})
t.Run("GetKey", func(t *testing.T) {
a := prepareApi()
a.AddParamBody(&body{}, "body", "body desc", true)
assert.Len(t, a.(*api).operation.Parameters, 1)
assert.Equal(t, a.(*api).operation.Parameters[0].Name, "body")
assert.Equal(t, a.(*api).operation.Parameters[0].In, string(ParamInBody))
assert.Equal(t, a.(*api).operation.Parameters[0].Description, "body desc")
assert.Equal(t, a.(*api).operation.Parameters[0].Required, true)
a.AddResponse(http.StatusOK, "response desc", body{}, nil)
ca := strconv.Itoa(http.StatusOK)
assert.Len(t, a.(*api).operation.Responses, 1)
assert.Equal(t, a.(*api).operation.Responses[ca].Description, "response desc")
assert.NotNil(t, a.(*api).defs)
da := a.(*api).defs
assert.Len(t, (*da), 1)
assert.NotNil(t, (*da)["body"])
a.AddResponse(http.StatusBadRequest, "response desc", body{Name: "name"}, nil)
cb := strconv.Itoa(http.StatusBadRequest)
assert.Len(t, a.(*api).operation.Responses, 2)
assert.Equal(t, a.(*api).operation.Responses[cb].Description, "response desc")
assert.NotNil(t, a.(*api).defs)
db := a.(*api).defs
assert.Len(t, (*db), 2)
assert.NotNil(t, (*db)["body"])
})
}
func TestAddResponse(t *testing.T) {
a := prepareApi()
a.AddResponse(http.StatusOK, "successful", nil, nil)
var f = func() {}
assert.Panics(t, func() {
a.AddResponse(http.StatusBadRequest, "bad request", f, nil)
})
assert.Panics(t, func() {
a.AddResponse(http.StatusBadRequest, "bad request", nil, time.Now())
})
}
func TestUI(t *testing.T) {
r := New(echo.New(), "/", "doc/", nil)
cdn := "https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/3.18.1"
r.SetUI(UISetting{
HideTop: true,
CDN: cdn,
})
se := r.(*Root)
req := httptest.NewRequest(echo.GET, "/doc/", nil)
rec := httptest.NewRecorder()
c := se.echo.NewContext(req, rec)
h := se.docHandler("/doc/swagger.json")
if assert.NoError(t, h(c)) {
assert.Equal(t, http.StatusOK, rec.Code)
assert.Contains(t, rec.Body.String(), cdn)
assert.Contains(t, rec.Body.String(), "#swagger-ui>.swagger-container>.topbar")
}
}
func TestRaw(t *testing.T) {
r := prepareApiRoot()
s := r.GetRaw()
assert.NotNil(t, s)
assert.NotNil(t, s.Info)
assert.Equal(t, s.Info.Version, "")
s.Info.Version = "1.0"
r.SetRaw(s)
assert.Equal(t, s.Info.Version, "1.0")
}
func TestContentType(t *testing.T) {
c := []string{"application/x-www-form-urlencoded", "multipart/form-data"}
p := []string{"application/vnd.github.v3+json", "application/vnd.github.v3.raw+json", "application/vnd.github.v3.text+json"}
t.Run("In Root", func(t *testing.T) {
r := prepareApiRoot()
r.SetRequestContentType(c...)
r.SetResponseContentType(p...)
assert.NotNil(t, r.(*Root))
assert.NotNil(t, r.(*Root).spec)
assert.Len(t, r.(*Root).spec.Consumes, 2)
assert.ElementsMatch(t, r.(*Root).spec.Consumes, c)
assert.Len(t, r.(*Root).spec.Produces, 3)
assert.ElementsMatch(t, r.(*Root).spec.Produces, p)
})
t.Run("In Api", func(t *testing.T) {
a := prepareApi()
a.SetRequestContentType(c...)
a.SetResponseContentType(p...)
assert.NotNil(t, a.(*api))
assert.Len(t, a.(*api).operation.Consumes, 2)
assert.ElementsMatch(t, a.(*api).operation.Consumes, c)
assert.Len(t, a.(*api).operation.Produces, 3)
assert.ElementsMatch(t, a.(*api).operation.Produces, p)
})
}
func TestOperationId(t *testing.T) {
id := "TestOperation"
a := prepareApi()
a.SetOperationId(id)
assert.Equal(t, a.(*api).operation.OperationID, id)
}
func TestDeprecated(t *testing.T) {
a := prepareApi()
a.SetDeprecated()
assert.Equal(t, a.(*api).operation.Deprecated, true)
}
func TestDescription(t *testing.T) {
d := "Test desc"
g := prepareApiGroup()
g.SetDescription(d)
assert.Equal(t, g.(*group).tag.Description, d)
a := prepareApi()
a.SetDescription(d)
assert.Equal(t, a.(*api).operation.Description, d)
}
func TestExternalDocs(t *testing.T) {
e := ExternalDocs{
Description: "Test desc",
URL: "http://127.0.0.1/",
}
r := prepareApiRoot()
r.SetExternalDocs(e.Description, e.URL)
assert.Equal(t, r.(*Root).spec.ExternalDocs, &e)
g := prepareApiGroup()
g.SetExternalDocs(e.Description, e.URL)
assert.Equal(t, g.(*group).tag.ExternalDocs, &e)
a := prepareApi()
a.SetExternalDocs(e.Description, e.URL)
assert.Equal(t, a.(*api).operation.ExternalDocs, &e)
}
func TestSummary(t *testing.T) {
s := "Test summary"
a := prepareApi()
a.SetSummary(s)
assert.Equal(t, a.(*api).operation.Summary, s)
}
func TestEcho(t *testing.T) {
r := prepareApiRoot()
assert.NotNil(t, r.Echo())
g := prepareApiGroup()
assert.NotNil(t, g.EchoGroup())
a := prepareApi()
assert.NotNil(t, a.Route())
}