Add SetUI & other http methods
This commit is contained in:
		
							parent
							
								
									7b5e1d762c
								
							
						
					
					
						commit
						0a9d6de748
					
				
							
								
								
									
										18
									
								
								assets.go
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								assets.go
									
									
									
									
									
								
							| @ -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() { | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										10
									
								
								internal.go
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								internal.go
									
									
									
									
									
								
							| @ -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
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								spec.go
									
									
									
									
									
								
							| @ -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 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -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++ { | ||||
|  | ||||
							
								
								
									
										114
									
								
								wrapper.go
									
									
									
									
									
								
							
							
						
						
									
										114
									
								
								wrapper.go
									
									
									
									
									
								
							| @ -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 | ||||
| } | ||||
|  | ||||
							
								
								
									
										355
									
								
								wrapper_test.go
									
									
									
									
									
								
							
							
						
						
									
										355
									
								
								wrapper_test.go
									
									
									
									
									
								
							| @ -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()) | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user