*: update kube vendor to v1.7.4
Signed-off-by: Antonio Murdaca <runcom@redhat.com>
This commit is contained in:
parent
c67859731f
commit
d56bf090ce
1032 changed files with 273965 additions and 40081 deletions
24
vendor/github.com/emicklei/go-restful/README.md
generated
vendored
24
vendor/github.com/emicklei/go-restful/README.md
generated
vendored
|
@ -1,8 +1,13 @@
|
|||
go-restful
|
||||
==========
|
||||
|
||||
package for building REST-style Web Services using Google Go
|
||||
|
||||
[](https://travis-ci.org/emicklei/go-restful)
|
||||
[](https://goreportcard.com/report/github.com/emicklei/go-restful)
|
||||
[](https://godoc.org/github.com/emicklei/go-restful)
|
||||
|
||||
- [Code examples](https://github.com/emicklei/go-restful/tree/master/examples)
|
||||
|
||||
REST asks developers to use HTTP methods explicitly and in a way that's consistent with the protocol definition. This basic REST design principle establishes a one-to-one mapping between create, read, update, and delete (CRUD) operations and HTTP methods. According to this mapping:
|
||||
|
||||
- GET = Retrieve a representation of a resource
|
||||
|
@ -40,35 +45,30 @@ func (u UserResource) findUser(request *restful.Request, response *restful.Respo
|
|||
|
||||
- Routes for request → function mapping with path parameter (e.g. {id}) support
|
||||
- Configurable router:
|
||||
- Routing algorithm after [JSR311](http://jsr311.java.net/nonav/releases/1.1/spec/spec.html) that is implemented using (but does **not** accept) regular expressions (See RouterJSR311 which is used by default)
|
||||
- Fast routing algorithm that allows static elements, regular expressions and dynamic parameters in the URL path (e.g. /meetings/{id} or /static/{subpath:*}, See CurlyRouter)
|
||||
- (default) Fast routing algorithm that allows static elements, regular expressions and dynamic parameters in the URL path (e.g. /meetings/{id} or /static/{subpath:*}
|
||||
- Routing algorithm after [JSR311](http://jsr311.java.net/nonav/releases/1.1/spec/spec.html) that is implemented using (but does **not** accept) regular expressions
|
||||
- Request API for reading structs from JSON/XML and accesing parameters (path,query,header)
|
||||
- Response API for writing structs to JSON/XML and setting headers
|
||||
- Customizable encoding using EntityReaderWriter registration
|
||||
- Filters for intercepting the request → response flow on Service or Route level
|
||||
- Request-scoped variables using attributes
|
||||
- Containers for WebServices on different HTTP endpoints
|
||||
- Content encoding (gzip,deflate) of request and response payloads
|
||||
- Automatic responses on OPTIONS (using a filter)
|
||||
- Automatic CORS request handling (using a filter)
|
||||
- API declaration for Swagger UI (see swagger package)
|
||||
- API declaration for Swagger UI (see [go-restful-swagger12](https://github.com/emicklei/go-restful-swagger12),[go-restful-openapi](https://github.com/emicklei/go-restful-openapi))
|
||||
- Panic recovery to produce HTTP 500, customizable using RecoverHandler(...)
|
||||
- Route errors produce HTTP 404/405/406/415 errors, customizable using ServiceErrorHandler(...)
|
||||
- Configurable (trace) logging
|
||||
- Customizable encoding using EntityReaderWriter registration
|
||||
- Customizable gzip/deflate readers and writers using CompressorProvider registration
|
||||
|
||||
### Resources
|
||||
|
||||
- [Documentation on godoc.org](http://godoc.org/github.com/emicklei/go-restful)
|
||||
- [Code examples](https://github.com/emicklei/go-restful/tree/master/examples)
|
||||
- [Example posted on blog](http://ernestmicklei.com/2012/11/go-restful-first-working-example/)
|
||||
- [Design explained on blog](http://ernestmicklei.com/2012/11/go-restful-api-design/)
|
||||
- [sourcegraph](https://sourcegraph.com/github.com/emicklei/go-restful)
|
||||
- [gopkg.in](https://gopkg.in/emicklei/go-restful.v1)
|
||||
- [showcase: Mora - MongoDB REST Api server](https://github.com/emicklei/mora)
|
||||
|
||||
[](https://drone.io/github.com/emicklei/go-restful/latest)
|
||||
|
||||
(c) 2012 - 2015, http://ernestmicklei.com. MIT License
|
||||
|
||||
Type ```git shortlog -s``` for a full list of contributors.
|
||||
|
||||
© 2012 - 2017, http://ernestmicklei.com. MIT License. Contributions are welcome.
|
1
vendor/github.com/emicklei/go-restful/compressors.go
generated
vendored
1
vendor/github.com/emicklei/go-restful/compressors.go
generated
vendored
|
@ -9,6 +9,7 @@ import (
|
|||
"compress/zlib"
|
||||
)
|
||||
|
||||
// CompressorProvider describes a component that can provider compressors for the std methods.
|
||||
type CompressorProvider interface {
|
||||
// Returns a *gzip.Writer which needs to be released later.
|
||||
// Before using it, call Reset().
|
||||
|
|
21
vendor/github.com/emicklei/go-restful/container.go
generated
vendored
21
vendor/github.com/emicklei/go-restful/container.go
generated
vendored
|
@ -32,7 +32,7 @@ type Container struct {
|
|||
contentEncodingEnabled bool // default is false
|
||||
}
|
||||
|
||||
// NewContainer creates a new Container using a new ServeMux and default router (RouterJSR311)
|
||||
// NewContainer creates a new Container using a new ServeMux and default router (CurlyRouter)
|
||||
func NewContainer() *Container {
|
||||
return &Container{
|
||||
webServices: []*WebService{},
|
||||
|
@ -74,7 +74,7 @@ func (c *Container) DoNotRecover(doNot bool) {
|
|||
c.doNotRecover = doNot
|
||||
}
|
||||
|
||||
// Router changes the default Router (currently RouterJSR311)
|
||||
// Router changes the default Router (currently CurlyRouter)
|
||||
func (c *Container) Router(aRouter RouteSelector) {
|
||||
c.router = aRouter
|
||||
}
|
||||
|
@ -188,6 +188,17 @@ func writeServiceError(err ServiceError, req *Request, resp *Response) {
|
|||
resp.WriteErrorString(err.Code, err.Message)
|
||||
}
|
||||
|
||||
// Dispatch the incoming Http Request to a matching WebService.
|
||||
func (c *Container) Dispatch(httpWriter http.ResponseWriter, httpRequest *http.Request) {
|
||||
if httpWriter == nil {
|
||||
panic("httpWriter cannot be nil")
|
||||
}
|
||||
if httpRequest == nil {
|
||||
panic("httpRequest cannot be nil")
|
||||
}
|
||||
c.dispatch(httpWriter, httpRequest)
|
||||
}
|
||||
|
||||
// Dispatch the incoming Http Request to a matching WebService.
|
||||
func (c *Container) dispatch(httpWriter http.ResponseWriter, httpRequest *http.Request) {
|
||||
writer := httpWriter
|
||||
|
@ -208,12 +219,6 @@ func (c *Container) dispatch(httpWriter http.ResponseWriter, httpRequest *http.R
|
|||
}
|
||||
}()
|
||||
}
|
||||
// Install closing the request body (if any)
|
||||
defer func() {
|
||||
if nil != httpRequest.Body {
|
||||
httpRequest.Body.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
// Detect if compression is needed
|
||||
// assume without compression, test for override
|
||||
|
|
2
vendor/github.com/emicklei/go-restful/doc.go
generated
vendored
2
vendor/github.com/emicklei/go-restful/doc.go
generated
vendored
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Package restful, a lean package for creating REST-style WebServices without magic.
|
||||
Package restful , a lean package for creating REST-style WebServices without magic.
|
||||
|
||||
WebServices and Routes
|
||||
|
||||
|
|
5
vendor/github.com/emicklei/go-restful/log/log.go
generated
vendored
5
vendor/github.com/emicklei/go-restful/log/log.go
generated
vendored
|
@ -5,7 +5,7 @@ import (
|
|||
"os"
|
||||
)
|
||||
|
||||
// Logger corresponds to a minimal subset of the interface satisfied by stdlib log.Logger
|
||||
// StdLogger corresponds to a minimal subset of the interface satisfied by stdlib log.Logger
|
||||
type StdLogger interface {
|
||||
Print(v ...interface{})
|
||||
Printf(format string, v ...interface{})
|
||||
|
@ -18,14 +18,17 @@ func init() {
|
|||
SetLogger(stdlog.New(os.Stderr, "[restful] ", stdlog.LstdFlags|stdlog.Lshortfile))
|
||||
}
|
||||
|
||||
// SetLogger sets the logger for this package
|
||||
func SetLogger(customLogger StdLogger) {
|
||||
Logger = customLogger
|
||||
}
|
||||
|
||||
// Print delegates to the Logger
|
||||
func Print(v ...interface{}) {
|
||||
Logger.Print(v...)
|
||||
}
|
||||
|
||||
// Printf delegates to the Logger
|
||||
func Printf(format string, v ...interface{}) {
|
||||
Logger.Printf(format, v...)
|
||||
}
|
||||
|
|
23
vendor/github.com/emicklei/go-restful/request.go
generated
vendored
23
vendor/github.com/emicklei/go-restful/request.go
generated
vendored
|
@ -5,20 +5,15 @@ package restful
|
|||
// that can be found in the LICENSE file.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/zlib"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
var defaultRequestContentType string
|
||||
|
||||
var doCacheReadEntityBytes = false
|
||||
|
||||
// Request is a wrapper for a http Request that provides convenience methods
|
||||
type Request struct {
|
||||
Request *http.Request
|
||||
bodyContent *[]byte // to cache the request body for multiple reads of ReadEntity
|
||||
pathParameters map[string]string
|
||||
attributes map[string]interface{} // for storing request-scoped values
|
||||
selectedRoutePath string // root path + route path that matched the request, e.g. /meetings/{id}/attendees
|
||||
|
@ -41,12 +36,6 @@ func DefaultRequestContentType(mime string) {
|
|||
defaultRequestContentType = mime
|
||||
}
|
||||
|
||||
// SetCacheReadEntity controls whether the response data ([]byte) is cached such that ReadEntity is repeatable.
|
||||
// Default is true (due to backwardcompatibility). For better performance, you should set it to false if you don't need it.
|
||||
func SetCacheReadEntity(doCache bool) {
|
||||
doCacheReadEntityBytes = doCache
|
||||
}
|
||||
|
||||
// PathParameter accesses the Path parameter value by its name
|
||||
func (r *Request) PathParameter(name string) string {
|
||||
return r.pathParameters[name]
|
||||
|
@ -81,18 +70,6 @@ func (r *Request) ReadEntity(entityPointer interface{}) (err error) {
|
|||
contentType := r.Request.Header.Get(HEADER_ContentType)
|
||||
contentEncoding := r.Request.Header.Get(HEADER_ContentEncoding)
|
||||
|
||||
// OLD feature, cache the body for reads
|
||||
if doCacheReadEntityBytes {
|
||||
if r.bodyContent == nil {
|
||||
data, err := ioutil.ReadAll(r.Request.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.bodyContent = &data
|
||||
}
|
||||
r.Request.Body = ioutil.NopCloser(bytes.NewReader(*r.bodyContent))
|
||||
}
|
||||
|
||||
// check if the request body needs decompression
|
||||
if ENCODING_GZIP == contentEncoding {
|
||||
gzipReader := currentCompressorProvider.AcquireGzipReader()
|
||||
|
|
5
vendor/github.com/emicklei/go-restful/response.go
generated
vendored
5
vendor/github.com/emicklei/go-restful/response.go
generated
vendored
|
@ -9,7 +9,7 @@ import (
|
|||
"net/http"
|
||||
)
|
||||
|
||||
// DEPRECATED, use DefaultResponseContentType(mime)
|
||||
// DefaultResponseMimeType is DEPRECATED, use DefaultResponseContentType(mime)
|
||||
var DefaultResponseMimeType string
|
||||
|
||||
//PrettyPrintResponses controls the indentation feature of XML and JSON serialization
|
||||
|
@ -27,11 +27,12 @@ type Response struct {
|
|||
err error // err property is kept when WriteError is called
|
||||
}
|
||||
|
||||
// Creates a new response based on a http ResponseWriter.
|
||||
// NewResponse creates a new response based on a http ResponseWriter.
|
||||
func NewResponse(httpWriter http.ResponseWriter) *Response {
|
||||
return &Response{httpWriter, "", []string{}, http.StatusOK, 0, PrettyPrintResponses, nil} // empty content-types
|
||||
}
|
||||
|
||||
// DefaultResponseContentType set a default.
|
||||
// If Accept header matching fails, fall back to this type.
|
||||
// Valid values are restful.MIME_JSON and restful.MIME_XML
|
||||
// Example:
|
||||
|
|
3
vendor/github.com/emicklei/go-restful/route.go
generated
vendored
3
vendor/github.com/emicklei/go-restful/route.go
generated
vendored
|
@ -34,6 +34,9 @@ type Route struct {
|
|||
ParameterDocs []*Parameter
|
||||
ResponseErrors map[int]ResponseError
|
||||
ReadSample, WriteSample interface{} // structs that model an example request or response payload
|
||||
|
||||
// Extra information used to store custom information about the route.
|
||||
Metadata map[string]interface{}
|
||||
}
|
||||
|
||||
// Initialize for Route
|
||||
|
|
69
vendor/github.com/emicklei/go-restful/route_builder.go
generated
vendored
69
vendor/github.com/emicklei/go-restful/route_builder.go
generated
vendored
|
@ -5,10 +5,12 @@ package restful
|
|||
// that can be found in the LICENSE file.
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/emicklei/go-restful/log"
|
||||
)
|
||||
|
@ -22,6 +24,9 @@ type RouteBuilder struct {
|
|||
httpMethod string // required
|
||||
function RouteFunction // required
|
||||
filters []FilterFunction
|
||||
|
||||
typeNameHandleFunc TypeNameHandleFunction // required
|
||||
|
||||
// documentation
|
||||
doc string
|
||||
notes string
|
||||
|
@ -29,6 +34,7 @@ type RouteBuilder struct {
|
|||
readSample, writeSample interface{}
|
||||
parameters []*Parameter
|
||||
errorMap map[int]ResponseError
|
||||
metadata map[string]interface{}
|
||||
}
|
||||
|
||||
// Do evaluates each argument with the RouteBuilder itself.
|
||||
|
@ -92,8 +98,13 @@ func (b *RouteBuilder) Notes(notes string) *RouteBuilder {
|
|||
// Reads tells what resource type will be read from the request payload. Optional.
|
||||
// A parameter of type "body" is added ,required is set to true and the dataType is set to the qualified name of the sample's type.
|
||||
func (b *RouteBuilder) Reads(sample interface{}) *RouteBuilder {
|
||||
fn := b.typeNameHandleFunc
|
||||
if fn == nil {
|
||||
fn = reflectTypeName
|
||||
}
|
||||
typeAsName := fn(sample)
|
||||
|
||||
b.readSample = sample
|
||||
typeAsName := reflect.TypeOf(sample).String()
|
||||
bodyParameter := &Parameter{&ParameterData{Name: "body"}}
|
||||
bodyParameter.beBody()
|
||||
bodyParameter.Required(true)
|
||||
|
@ -145,9 +156,10 @@ func (b *RouteBuilder) ReturnsError(code int, message string, model interface{})
|
|||
// The model parameter is optional ; either pass a struct instance or use nil if not applicable.
|
||||
func (b *RouteBuilder) Returns(code int, message string, model interface{}) *RouteBuilder {
|
||||
err := ResponseError{
|
||||
Code: code,
|
||||
Message: message,
|
||||
Model: model,
|
||||
Code: code,
|
||||
Message: message,
|
||||
Model: model,
|
||||
IsDefault: false,
|
||||
}
|
||||
// lazy init because there is no NewRouteBuilder (yet)
|
||||
if b.errorMap == nil {
|
||||
|
@ -157,10 +169,36 @@ func (b *RouteBuilder) Returns(code int, message string, model interface{}) *Rou
|
|||
return b
|
||||
}
|
||||
|
||||
// DefaultReturns is a special Returns call that sets the default of the response ; the code is zero.
|
||||
func (b *RouteBuilder) DefaultReturns(message string, model interface{}) *RouteBuilder {
|
||||
b.Returns(0, message, model)
|
||||
// Modify the ResponseError just added/updated
|
||||
re := b.errorMap[0]
|
||||
// errorMap is initialized
|
||||
b.errorMap[0] = ResponseError{
|
||||
Code: re.Code,
|
||||
Message: re.Message,
|
||||
Model: re.Model,
|
||||
IsDefault: true,
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// Metadata adds or updates a key=value pair to the metadata map.
|
||||
func (b *RouteBuilder) Metadata(key string, value interface{}) *RouteBuilder {
|
||||
if b.metadata == nil {
|
||||
b.metadata = map[string]interface{}{}
|
||||
}
|
||||
b.metadata[key] = value
|
||||
return b
|
||||
}
|
||||
|
||||
// ResponseError represents a response; not necessarily an error.
|
||||
type ResponseError struct {
|
||||
Code int
|
||||
Message string
|
||||
Model interface{}
|
||||
Code int
|
||||
Message string
|
||||
Model interface{}
|
||||
IsDefault bool
|
||||
}
|
||||
|
||||
func (b *RouteBuilder) servicePath(path string) *RouteBuilder {
|
||||
|
@ -186,6 +224,13 @@ func (b *RouteBuilder) copyDefaults(rootProduces, rootConsumes []string) {
|
|||
}
|
||||
}
|
||||
|
||||
// typeNameHandler sets the function that will convert types to strings in the parameter
|
||||
// and model definitions.
|
||||
func (b *RouteBuilder) typeNameHandler(handler TypeNameHandleFunction) *RouteBuilder {
|
||||
b.typeNameHandleFunc = handler
|
||||
return b
|
||||
}
|
||||
|
||||
// Build creates a new Route using the specification details collected by the RouteBuilder
|
||||
func (b *RouteBuilder) Build() Route {
|
||||
pathExpr, err := newPathExpression(b.currentPath)
|
||||
|
@ -217,7 +262,8 @@ func (b *RouteBuilder) Build() Route {
|
|||
ParameterDocs: b.parameters,
|
||||
ResponseErrors: b.errorMap,
|
||||
ReadSample: b.readSample,
|
||||
WriteSample: b.writeSample}
|
||||
WriteSample: b.writeSample,
|
||||
Metadata: b.metadata}
|
||||
route.postBuild()
|
||||
return route
|
||||
}
|
||||
|
@ -226,6 +272,8 @@ func concatPath(path1, path2 string) string {
|
|||
return strings.TrimRight(path1, "/") + "/" + strings.TrimLeft(path2, "/")
|
||||
}
|
||||
|
||||
var anonymousFuncCount int32
|
||||
|
||||
// nameOfFunction returns the short name of the function f for documentation.
|
||||
// It uses a runtime feature for debugging ; its value may change for later Go versions.
|
||||
func nameOfFunction(f interface{}) string {
|
||||
|
@ -236,5 +284,10 @@ func nameOfFunction(f interface{}) string {
|
|||
last = strings.TrimSuffix(last, ")-fm") // Go 1.5
|
||||
last = strings.TrimSuffix(last, "·fm") // < Go 1.5
|
||||
last = strings.TrimSuffix(last, "-fm") // Go 1.5
|
||||
if last == "func1" { // this could mean conflicts in API docs
|
||||
val := atomic.AddInt32(&anonymousFuncCount, 1)
|
||||
last = "func" + fmt.Sprintf("%d", val)
|
||||
atomic.StoreInt32(&anonymousFuncCount, val)
|
||||
}
|
||||
return last
|
||||
}
|
||||
|
|
76
vendor/github.com/emicklei/go-restful/swagger/README.md
generated
vendored
76
vendor/github.com/emicklei/go-restful/swagger/README.md
generated
vendored
|
@ -1,76 +0,0 @@
|
|||
How to use Swagger UI with go-restful
|
||||
=
|
||||
|
||||
Get the Swagger UI sources (version 1.2 only)
|
||||
|
||||
git clone https://github.com/wordnik/swagger-ui.git
|
||||
|
||||
The project contains a "dist" folder.
|
||||
Its contents has all the Swagger UI files you need.
|
||||
|
||||
The `index.html` has an `url` set to `http://petstore.swagger.wordnik.com/api/api-docs`.
|
||||
You need to change that to match your WebService JSON endpoint e.g. `http://localhost:8080/apidocs.json`
|
||||
|
||||
Now, you can install the Swagger WebService for serving the Swagger specification in JSON.
|
||||
|
||||
config := swagger.Config{
|
||||
WebServices: restful.RegisteredWebServices(),
|
||||
ApiPath: "/apidocs.json",
|
||||
SwaggerPath: "/apidocs/",
|
||||
SwaggerFilePath: "/Users/emicklei/Projects/swagger-ui/dist"}
|
||||
swagger.InstallSwaggerService(config)
|
||||
|
||||
|
||||
Documenting Structs
|
||||
--
|
||||
|
||||
Currently there are 2 ways to document your structs in the go-restful Swagger.
|
||||
|
||||
###### By using struct tags
|
||||
- Use tag "description" to annotate a struct field with a description to show in the UI
|
||||
- Use tag "modelDescription" to annotate the struct itself with a description to show in the UI. The tag can be added in an field of the struct and in case that there are multiple definition, they will be appended with an empty line.
|
||||
|
||||
###### By using the SwaggerDoc method
|
||||
Here is an example with an `Address` struct and the documentation for each of the fields. The `""` is a special entry for **documenting the struct itself**.
|
||||
|
||||
type Address struct {
|
||||
Country string `json:"country,omitempty"`
|
||||
PostCode int `json:"postcode,omitempty"`
|
||||
}
|
||||
|
||||
func (Address) SwaggerDoc() map[string]string {
|
||||
return map[string]string{
|
||||
"": "Address doc",
|
||||
"country": "Country doc",
|
||||
"postcode": "PostCode doc",
|
||||
}
|
||||
}
|
||||
|
||||
This example will generate a JSON like this
|
||||
|
||||
{
|
||||
"Address": {
|
||||
"id": "Address",
|
||||
"description": "Address doc",
|
||||
"properties": {
|
||||
"country": {
|
||||
"type": "string",
|
||||
"description": "Country doc"
|
||||
},
|
||||
"postcode": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"description": "PostCode doc"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
**Very Important Notes:**
|
||||
- `SwaggerDoc()` is using a **NON-Pointer** receiver (e.g. func (Address) and not func (*Address))
|
||||
- The returned map should use as key the name of the field as defined in the JSON parameter (e.g. `"postcode"` and not `"PostCode"`)
|
||||
|
||||
Notes
|
||||
--
|
||||
- The Nickname of an Operation is automatically set by finding the name of the function. You can override it using RouteBuilder.Operation(..)
|
||||
- The WebServices field of swagger.Config can be used to control which service you want to expose and document ; you can have multiple configs and therefore multiple endpoints.
|
64
vendor/github.com/emicklei/go-restful/swagger/api_declaration_list.go
generated
vendored
64
vendor/github.com/emicklei/go-restful/swagger/api_declaration_list.go
generated
vendored
|
@ -1,64 +0,0 @@
|
|||
package swagger
|
||||
|
||||
// Copyright 2015 Ernest Micklei. All rights reserved.
|
||||
// Use of this source code is governed by a license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// ApiDeclarationList maintains an ordered list of ApiDeclaration.
|
||||
type ApiDeclarationList struct {
|
||||
List []ApiDeclaration
|
||||
}
|
||||
|
||||
// At returns the ApiDeclaration by its path unless absent, then ok is false
|
||||
func (l *ApiDeclarationList) At(path string) (a ApiDeclaration, ok bool) {
|
||||
for _, each := range l.List {
|
||||
if each.ResourcePath == path {
|
||||
return each, true
|
||||
}
|
||||
}
|
||||
return a, false
|
||||
}
|
||||
|
||||
// Put adds or replaces a ApiDeclaration with this name
|
||||
func (l *ApiDeclarationList) Put(path string, a ApiDeclaration) {
|
||||
// maybe replace existing
|
||||
for i, each := range l.List {
|
||||
if each.ResourcePath == path {
|
||||
// replace
|
||||
l.List[i] = a
|
||||
return
|
||||
}
|
||||
}
|
||||
// add
|
||||
l.List = append(l.List, a)
|
||||
}
|
||||
|
||||
// Do enumerates all the properties, each with its assigned name
|
||||
func (l *ApiDeclarationList) Do(block func(path string, decl ApiDeclaration)) {
|
||||
for _, each := range l.List {
|
||||
block(each.ResourcePath, each)
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalJSON writes the ModelPropertyList as if it was a map[string]ModelProperty
|
||||
func (l ApiDeclarationList) MarshalJSON() ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
encoder := json.NewEncoder(&buf)
|
||||
buf.WriteString("{\n")
|
||||
for i, each := range l.List {
|
||||
buf.WriteString("\"")
|
||||
buf.WriteString(each.ResourcePath)
|
||||
buf.WriteString("\": ")
|
||||
encoder.Encode(each)
|
||||
if i < len(l.List)-1 {
|
||||
buf.WriteString(",\n")
|
||||
}
|
||||
}
|
||||
buf.WriteString("}")
|
||||
return buf.Bytes(), nil
|
||||
}
|
46
vendor/github.com/emicklei/go-restful/swagger/config.go
generated
vendored
46
vendor/github.com/emicklei/go-restful/swagger/config.go
generated
vendored
|
@ -1,46 +0,0 @@
|
|||
package swagger
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"reflect"
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
)
|
||||
|
||||
// PostBuildDeclarationMapFunc can be used to modify the api declaration map.
|
||||
type PostBuildDeclarationMapFunc func(apiDeclarationMap *ApiDeclarationList)
|
||||
|
||||
// MapSchemaFormatFunc can be used to modify typeName at definition time.
|
||||
type MapSchemaFormatFunc func(typeName string) string
|
||||
|
||||
// MapModelTypeNameFunc can be used to return the desired typeName for a given
|
||||
// type. It will return false if the default name should be used.
|
||||
type MapModelTypeNameFunc func(t reflect.Type) (string, bool)
|
||||
|
||||
type Config struct {
|
||||
// url where the services are available, e.g. http://localhost:8080
|
||||
// if left empty then the basePath of Swagger is taken from the actual request
|
||||
WebServicesUrl string
|
||||
// path where the JSON api is avaiable , e.g. /apidocs
|
||||
ApiPath string
|
||||
// [optional] path where the swagger UI will be served, e.g. /swagger
|
||||
SwaggerPath string
|
||||
// [optional] location of folder containing Swagger HTML5 application index.html
|
||||
SwaggerFilePath string
|
||||
// api listing is constructed from this list of restful WebServices.
|
||||
WebServices []*restful.WebService
|
||||
// will serve all static content (scripts,pages,images)
|
||||
StaticHandler http.Handler
|
||||
// [optional] on default CORS (Cross-Origin-Resource-Sharing) is enabled.
|
||||
DisableCORS bool
|
||||
// Top-level API version. Is reflected in the resource listing.
|
||||
ApiVersion string
|
||||
// If set then call this handler after building the complete ApiDeclaration Map
|
||||
PostBuildHandler PostBuildDeclarationMapFunc
|
||||
// Swagger global info struct
|
||||
Info Info
|
||||
// [optional] If set, model builder should call this handler to get addition typename-to-swagger-format-field conversion.
|
||||
SchemaFormatHandler MapSchemaFormatFunc
|
||||
// [optional] If set, model builder should call this handler to retrieve the name for a given type.
|
||||
ModelTypeNameHandler MapModelTypeNameFunc
|
||||
}
|
467
vendor/github.com/emicklei/go-restful/swagger/model_builder.go
generated
vendored
467
vendor/github.com/emicklei/go-restful/swagger/model_builder.go
generated
vendored
|
@ -1,467 +0,0 @@
|
|||
package swagger
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ModelBuildable is used for extending Structs that need more control over
|
||||
// how the Model appears in the Swagger api declaration.
|
||||
type ModelBuildable interface {
|
||||
PostBuildModel(m *Model) *Model
|
||||
}
|
||||
|
||||
type modelBuilder struct {
|
||||
Models *ModelList
|
||||
Config *Config
|
||||
}
|
||||
|
||||
type documentable interface {
|
||||
SwaggerDoc() map[string]string
|
||||
}
|
||||
|
||||
// Check if this structure has a method with signature func (<theModel>) SwaggerDoc() map[string]string
|
||||
// If it exists, retrive the documentation and overwrite all struct tag descriptions
|
||||
func getDocFromMethodSwaggerDoc2(model reflect.Type) map[string]string {
|
||||
if docable, ok := reflect.New(model).Elem().Interface().(documentable); ok {
|
||||
return docable.SwaggerDoc()
|
||||
}
|
||||
return make(map[string]string)
|
||||
}
|
||||
|
||||
// addModelFrom creates and adds a Model to the builder and detects and calls
|
||||
// the post build hook for customizations
|
||||
func (b modelBuilder) addModelFrom(sample interface{}) {
|
||||
if modelOrNil := b.addModel(reflect.TypeOf(sample), ""); modelOrNil != nil {
|
||||
// allow customizations
|
||||
if buildable, ok := sample.(ModelBuildable); ok {
|
||||
modelOrNil = buildable.PostBuildModel(modelOrNil)
|
||||
b.Models.Put(modelOrNil.Id, *modelOrNil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (b modelBuilder) addModel(st reflect.Type, nameOverride string) *Model {
|
||||
// Turn pointers into simpler types so further checks are
|
||||
// correct.
|
||||
if st.Kind() == reflect.Ptr {
|
||||
st = st.Elem()
|
||||
}
|
||||
|
||||
modelName := b.keyFrom(st)
|
||||
if nameOverride != "" {
|
||||
modelName = nameOverride
|
||||
}
|
||||
// no models needed for primitive types
|
||||
if b.isPrimitiveType(modelName) {
|
||||
return nil
|
||||
}
|
||||
// golang encoding/json packages says array and slice values encode as
|
||||
// JSON arrays, except that []byte encodes as a base64-encoded string.
|
||||
// If we see a []byte here, treat it at as a primitive type (string)
|
||||
// and deal with it in buildArrayTypeProperty.
|
||||
if (st.Kind() == reflect.Slice || st.Kind() == reflect.Array) &&
|
||||
st.Elem().Kind() == reflect.Uint8 {
|
||||
return nil
|
||||
}
|
||||
// see if we already have visited this model
|
||||
if _, ok := b.Models.At(modelName); ok {
|
||||
return nil
|
||||
}
|
||||
sm := Model{
|
||||
Id: modelName,
|
||||
Required: []string{},
|
||||
Properties: ModelPropertyList{}}
|
||||
|
||||
// reference the model before further initializing (enables recursive structs)
|
||||
b.Models.Put(modelName, sm)
|
||||
|
||||
// check for slice or array
|
||||
if st.Kind() == reflect.Slice || st.Kind() == reflect.Array {
|
||||
b.addModel(st.Elem(), "")
|
||||
return &sm
|
||||
}
|
||||
// check for structure or primitive type
|
||||
if st.Kind() != reflect.Struct {
|
||||
return &sm
|
||||
}
|
||||
|
||||
fullDoc := getDocFromMethodSwaggerDoc2(st)
|
||||
modelDescriptions := []string{}
|
||||
|
||||
for i := 0; i < st.NumField(); i++ {
|
||||
field := st.Field(i)
|
||||
jsonName, modelDescription, prop := b.buildProperty(field, &sm, modelName)
|
||||
if len(modelDescription) > 0 {
|
||||
modelDescriptions = append(modelDescriptions, modelDescription)
|
||||
}
|
||||
|
||||
// add if not omitted
|
||||
if len(jsonName) != 0 {
|
||||
// update description
|
||||
if fieldDoc, ok := fullDoc[jsonName]; ok {
|
||||
prop.Description = fieldDoc
|
||||
}
|
||||
// update Required
|
||||
if b.isPropertyRequired(field) {
|
||||
sm.Required = append(sm.Required, jsonName)
|
||||
}
|
||||
sm.Properties.Put(jsonName, prop)
|
||||
}
|
||||
}
|
||||
|
||||
// We always overwrite documentation if SwaggerDoc method exists
|
||||
// "" is special for documenting the struct itself
|
||||
if modelDoc, ok := fullDoc[""]; ok {
|
||||
sm.Description = modelDoc
|
||||
} else if len(modelDescriptions) != 0 {
|
||||
sm.Description = strings.Join(modelDescriptions, "\n")
|
||||
}
|
||||
|
||||
// update model builder with completed model
|
||||
b.Models.Put(modelName, sm)
|
||||
|
||||
return &sm
|
||||
}
|
||||
|
||||
func (b modelBuilder) isPropertyRequired(field reflect.StructField) bool {
|
||||
required := true
|
||||
if jsonTag := field.Tag.Get("json"); jsonTag != "" {
|
||||
s := strings.Split(jsonTag, ",")
|
||||
if len(s) > 1 && s[1] == "omitempty" {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return required
|
||||
}
|
||||
|
||||
func (b modelBuilder) buildProperty(field reflect.StructField, model *Model, modelName string) (jsonName, modelDescription string, prop ModelProperty) {
|
||||
jsonName = b.jsonNameOfField(field)
|
||||
if len(jsonName) == 0 {
|
||||
// empty name signals skip property
|
||||
return "", "", prop
|
||||
}
|
||||
|
||||
if field.Name == "XMLName" && field.Type.String() == "xml.Name" {
|
||||
// property is metadata for the xml.Name attribute, can be skipped
|
||||
return "", "", prop
|
||||
}
|
||||
|
||||
if tag := field.Tag.Get("modelDescription"); tag != "" {
|
||||
modelDescription = tag
|
||||
}
|
||||
|
||||
prop.setPropertyMetadata(field)
|
||||
if prop.Type != nil {
|
||||
return jsonName, modelDescription, prop
|
||||
}
|
||||
fieldType := field.Type
|
||||
|
||||
// check if type is doing its own marshalling
|
||||
marshalerType := reflect.TypeOf((*json.Marshaler)(nil)).Elem()
|
||||
if fieldType.Implements(marshalerType) {
|
||||
var pType = "string"
|
||||
if prop.Type == nil {
|
||||
prop.Type = &pType
|
||||
}
|
||||
if prop.Format == "" {
|
||||
prop.Format = b.jsonSchemaFormat(b.keyFrom(fieldType))
|
||||
}
|
||||
return jsonName, modelDescription, prop
|
||||
}
|
||||
|
||||
// check if annotation says it is a string
|
||||
if jsonTag := field.Tag.Get("json"); jsonTag != "" {
|
||||
s := strings.Split(jsonTag, ",")
|
||||
if len(s) > 1 && s[1] == "string" {
|
||||
stringt := "string"
|
||||
prop.Type = &stringt
|
||||
return jsonName, modelDescription, prop
|
||||
}
|
||||
}
|
||||
|
||||
fieldKind := fieldType.Kind()
|
||||
switch {
|
||||
case fieldKind == reflect.Struct:
|
||||
jsonName, prop := b.buildStructTypeProperty(field, jsonName, model)
|
||||
return jsonName, modelDescription, prop
|
||||
case fieldKind == reflect.Slice || fieldKind == reflect.Array:
|
||||
jsonName, prop := b.buildArrayTypeProperty(field, jsonName, modelName)
|
||||
return jsonName, modelDescription, prop
|
||||
case fieldKind == reflect.Ptr:
|
||||
jsonName, prop := b.buildPointerTypeProperty(field, jsonName, modelName)
|
||||
return jsonName, modelDescription, prop
|
||||
case fieldKind == reflect.String:
|
||||
stringt := "string"
|
||||
prop.Type = &stringt
|
||||
return jsonName, modelDescription, prop
|
||||
case fieldKind == reflect.Map:
|
||||
// if it's a map, it's unstructured, and swagger 1.2 can't handle it
|
||||
objectType := "object"
|
||||
prop.Type = &objectType
|
||||
return jsonName, modelDescription, prop
|
||||
}
|
||||
|
||||
fieldTypeName := b.keyFrom(fieldType)
|
||||
if b.isPrimitiveType(fieldTypeName) {
|
||||
mapped := b.jsonSchemaType(fieldTypeName)
|
||||
prop.Type = &mapped
|
||||
prop.Format = b.jsonSchemaFormat(fieldTypeName)
|
||||
return jsonName, modelDescription, prop
|
||||
}
|
||||
modelType := b.keyFrom(fieldType)
|
||||
prop.Ref = &modelType
|
||||
|
||||
if fieldType.Name() == "" { // override type of anonymous structs
|
||||
nestedTypeName := modelName + "." + jsonName
|
||||
prop.Ref = &nestedTypeName
|
||||
b.addModel(fieldType, nestedTypeName)
|
||||
}
|
||||
return jsonName, modelDescription, prop
|
||||
}
|
||||
|
||||
func hasNamedJSONTag(field reflect.StructField) bool {
|
||||
parts := strings.Split(field.Tag.Get("json"), ",")
|
||||
if len(parts) == 0 {
|
||||
return false
|
||||
}
|
||||
for _, s := range parts[1:] {
|
||||
if s == "inline" {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return len(parts[0]) > 0
|
||||
}
|
||||
|
||||
func (b modelBuilder) buildStructTypeProperty(field reflect.StructField, jsonName string, model *Model) (nameJson string, prop ModelProperty) {
|
||||
prop.setPropertyMetadata(field)
|
||||
// Check for type override in tag
|
||||
if prop.Type != nil {
|
||||
return jsonName, prop
|
||||
}
|
||||
fieldType := field.Type
|
||||
// check for anonymous
|
||||
if len(fieldType.Name()) == 0 {
|
||||
// anonymous
|
||||
anonType := model.Id + "." + jsonName
|
||||
b.addModel(fieldType, anonType)
|
||||
prop.Ref = &anonType
|
||||
return jsonName, prop
|
||||
}
|
||||
|
||||
if field.Name == fieldType.Name() && field.Anonymous && !hasNamedJSONTag(field) {
|
||||
// embedded struct
|
||||
sub := modelBuilder{new(ModelList), b.Config}
|
||||
sub.addModel(fieldType, "")
|
||||
subKey := sub.keyFrom(fieldType)
|
||||
// merge properties from sub
|
||||
subModel, _ := sub.Models.At(subKey)
|
||||
subModel.Properties.Do(func(k string, v ModelProperty) {
|
||||
model.Properties.Put(k, v)
|
||||
// if subModel says this property is required then include it
|
||||
required := false
|
||||
for _, each := range subModel.Required {
|
||||
if k == each {
|
||||
required = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if required {
|
||||
model.Required = append(model.Required, k)
|
||||
}
|
||||
})
|
||||
// add all new referenced models
|
||||
sub.Models.Do(func(key string, sub Model) {
|
||||
if key != subKey {
|
||||
if _, ok := b.Models.At(key); !ok {
|
||||
b.Models.Put(key, sub)
|
||||
}
|
||||
}
|
||||
})
|
||||
// empty name signals skip property
|
||||
return "", prop
|
||||
}
|
||||
// simple struct
|
||||
b.addModel(fieldType, "")
|
||||
var pType = b.keyFrom(fieldType)
|
||||
prop.Ref = &pType
|
||||
return jsonName, prop
|
||||
}
|
||||
|
||||
func (b modelBuilder) buildArrayTypeProperty(field reflect.StructField, jsonName, modelName string) (nameJson string, prop ModelProperty) {
|
||||
// check for type override in tags
|
||||
prop.setPropertyMetadata(field)
|
||||
if prop.Type != nil {
|
||||
return jsonName, prop
|
||||
}
|
||||
fieldType := field.Type
|
||||
if fieldType.Elem().Kind() == reflect.Uint8 {
|
||||
stringt := "string"
|
||||
prop.Type = &stringt
|
||||
return jsonName, prop
|
||||
}
|
||||
var pType = "array"
|
||||
prop.Type = &pType
|
||||
isPrimitive := b.isPrimitiveType(fieldType.Elem().Name())
|
||||
elemTypeName := b.getElementTypeName(modelName, jsonName, fieldType.Elem())
|
||||
prop.Items = new(Item)
|
||||
if isPrimitive {
|
||||
mapped := b.jsonSchemaType(elemTypeName)
|
||||
prop.Items.Type = &mapped
|
||||
} else {
|
||||
prop.Items.Ref = &elemTypeName
|
||||
}
|
||||
// add|overwrite model for element type
|
||||
if fieldType.Elem().Kind() == reflect.Ptr {
|
||||
fieldType = fieldType.Elem()
|
||||
}
|
||||
if !isPrimitive {
|
||||
b.addModel(fieldType.Elem(), elemTypeName)
|
||||
}
|
||||
return jsonName, prop
|
||||
}
|
||||
|
||||
func (b modelBuilder) buildPointerTypeProperty(field reflect.StructField, jsonName, modelName string) (nameJson string, prop ModelProperty) {
|
||||
prop.setPropertyMetadata(field)
|
||||
// Check for type override in tags
|
||||
if prop.Type != nil {
|
||||
return jsonName, prop
|
||||
}
|
||||
fieldType := field.Type
|
||||
|
||||
// override type of pointer to list-likes
|
||||
if fieldType.Elem().Kind() == reflect.Slice || fieldType.Elem().Kind() == reflect.Array {
|
||||
var pType = "array"
|
||||
prop.Type = &pType
|
||||
isPrimitive := b.isPrimitiveType(fieldType.Elem().Elem().Name())
|
||||
elemName := b.getElementTypeName(modelName, jsonName, fieldType.Elem().Elem())
|
||||
if isPrimitive {
|
||||
primName := b.jsonSchemaType(elemName)
|
||||
prop.Items = &Item{Ref: &primName}
|
||||
} else {
|
||||
prop.Items = &Item{Ref: &elemName}
|
||||
}
|
||||
if !isPrimitive {
|
||||
// add|overwrite model for element type
|
||||
b.addModel(fieldType.Elem().Elem(), elemName)
|
||||
}
|
||||
} else {
|
||||
// non-array, pointer type
|
||||
fieldTypeName := b.keyFrom(fieldType.Elem())
|
||||
var pType = b.jsonSchemaType(fieldTypeName) // no star, include pkg path
|
||||
if b.isPrimitiveType(fieldTypeName) {
|
||||
prop.Type = &pType
|
||||
prop.Format = b.jsonSchemaFormat(fieldTypeName)
|
||||
return jsonName, prop
|
||||
}
|
||||
prop.Ref = &pType
|
||||
elemName := ""
|
||||
if fieldType.Elem().Name() == "" {
|
||||
elemName = modelName + "." + jsonName
|
||||
prop.Ref = &elemName
|
||||
}
|
||||
b.addModel(fieldType.Elem(), elemName)
|
||||
}
|
||||
return jsonName, prop
|
||||
}
|
||||
|
||||
func (b modelBuilder) getElementTypeName(modelName, jsonName string, t reflect.Type) string {
|
||||
if t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
if t.Name() == "" {
|
||||
return modelName + "." + jsonName
|
||||
}
|
||||
return b.keyFrom(t)
|
||||
}
|
||||
|
||||
func (b modelBuilder) keyFrom(st reflect.Type) string {
|
||||
key := st.String()
|
||||
if b.Config != nil && b.Config.ModelTypeNameHandler != nil {
|
||||
if name, ok := b.Config.ModelTypeNameHandler(st); ok {
|
||||
key = name
|
||||
}
|
||||
}
|
||||
if len(st.Name()) == 0 { // unnamed type
|
||||
// Swagger UI has special meaning for [
|
||||
key = strings.Replace(key, "[]", "||", -1)
|
||||
}
|
||||
return key
|
||||
}
|
||||
|
||||
// see also https://golang.org/ref/spec#Numeric_types
|
||||
func (b modelBuilder) isPrimitiveType(modelName string) bool {
|
||||
if len(modelName) == 0 {
|
||||
return false
|
||||
}
|
||||
return strings.Contains("uint uint8 uint16 uint32 uint64 int int8 int16 int32 int64 float32 float64 bool string byte rune time.Time", modelName)
|
||||
}
|
||||
|
||||
// jsonNameOfField returns the name of the field as it should appear in JSON format
|
||||
// An empty string indicates that this field is not part of the JSON representation
|
||||
func (b modelBuilder) jsonNameOfField(field reflect.StructField) string {
|
||||
if jsonTag := field.Tag.Get("json"); jsonTag != "" {
|
||||
s := strings.Split(jsonTag, ",")
|
||||
if s[0] == "-" {
|
||||
// empty name signals skip property
|
||||
return ""
|
||||
} else if s[0] != "" {
|
||||
return s[0]
|
||||
}
|
||||
}
|
||||
return field.Name
|
||||
}
|
||||
|
||||
// see also http://json-schema.org/latest/json-schema-core.html#anchor8
|
||||
func (b modelBuilder) jsonSchemaType(modelName string) string {
|
||||
schemaMap := map[string]string{
|
||||
"uint": "integer",
|
||||
"uint8": "integer",
|
||||
"uint16": "integer",
|
||||
"uint32": "integer",
|
||||
"uint64": "integer",
|
||||
|
||||
"int": "integer",
|
||||
"int8": "integer",
|
||||
"int16": "integer",
|
||||
"int32": "integer",
|
||||
"int64": "integer",
|
||||
|
||||
"byte": "integer",
|
||||
"float64": "number",
|
||||
"float32": "number",
|
||||
"bool": "boolean",
|
||||
"time.Time": "string",
|
||||
}
|
||||
mapped, ok := schemaMap[modelName]
|
||||
if !ok {
|
||||
return modelName // use as is (custom or struct)
|
||||
}
|
||||
return mapped
|
||||
}
|
||||
|
||||
func (b modelBuilder) jsonSchemaFormat(modelName string) string {
|
||||
if b.Config != nil && b.Config.SchemaFormatHandler != nil {
|
||||
if mapped := b.Config.SchemaFormatHandler(modelName); mapped != "" {
|
||||
return mapped
|
||||
}
|
||||
}
|
||||
schemaMap := map[string]string{
|
||||
"int": "int32",
|
||||
"int32": "int32",
|
||||
"int64": "int64",
|
||||
"byte": "byte",
|
||||
"uint": "integer",
|
||||
"uint8": "byte",
|
||||
"float64": "double",
|
||||
"float32": "float",
|
||||
"time.Time": "date-time",
|
||||
"*time.Time": "date-time",
|
||||
}
|
||||
mapped, ok := schemaMap[modelName]
|
||||
if !ok {
|
||||
return "" // no format
|
||||
}
|
||||
return mapped
|
||||
}
|
86
vendor/github.com/emicklei/go-restful/swagger/model_list.go
generated
vendored
86
vendor/github.com/emicklei/go-restful/swagger/model_list.go
generated
vendored
|
@ -1,86 +0,0 @@
|
|||
package swagger
|
||||
|
||||
// Copyright 2015 Ernest Micklei. All rights reserved.
|
||||
// Use of this source code is governed by a license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// NamedModel associates a name with a Model (not using its Id)
|
||||
type NamedModel struct {
|
||||
Name string
|
||||
Model Model
|
||||
}
|
||||
|
||||
// ModelList encapsulates a list of NamedModel (association)
|
||||
type ModelList struct {
|
||||
List []NamedModel
|
||||
}
|
||||
|
||||
// Put adds or replaces a Model by its name
|
||||
func (l *ModelList) Put(name string, model Model) {
|
||||
for i, each := range l.List {
|
||||
if each.Name == name {
|
||||
// replace
|
||||
l.List[i] = NamedModel{name, model}
|
||||
return
|
||||
}
|
||||
}
|
||||
// add
|
||||
l.List = append(l.List, NamedModel{name, model})
|
||||
}
|
||||
|
||||
// At returns a Model by its name, ok is false if absent
|
||||
func (l *ModelList) At(name string) (m Model, ok bool) {
|
||||
for _, each := range l.List {
|
||||
if each.Name == name {
|
||||
return each.Model, true
|
||||
}
|
||||
}
|
||||
return m, false
|
||||
}
|
||||
|
||||
// Do enumerates all the models, each with its assigned name
|
||||
func (l *ModelList) Do(block func(name string, value Model)) {
|
||||
for _, each := range l.List {
|
||||
block(each.Name, each.Model)
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalJSON writes the ModelList as if it was a map[string]Model
|
||||
func (l ModelList) MarshalJSON() ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
encoder := json.NewEncoder(&buf)
|
||||
buf.WriteString("{\n")
|
||||
for i, each := range l.List {
|
||||
buf.WriteString("\"")
|
||||
buf.WriteString(each.Name)
|
||||
buf.WriteString("\": ")
|
||||
encoder.Encode(each.Model)
|
||||
if i < len(l.List)-1 {
|
||||
buf.WriteString(",\n")
|
||||
}
|
||||
}
|
||||
buf.WriteString("}")
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON reads back a ModelList. This is an expensive operation.
|
||||
func (l *ModelList) UnmarshalJSON(data []byte) error {
|
||||
raw := map[string]interface{}{}
|
||||
json.NewDecoder(bytes.NewReader(data)).Decode(&raw)
|
||||
for k, v := range raw {
|
||||
// produces JSON bytes for each value
|
||||
data, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var m Model
|
||||
json.NewDecoder(bytes.NewReader(data)).Decode(&m)
|
||||
l.Put(k, m)
|
||||
}
|
||||
return nil
|
||||
}
|
81
vendor/github.com/emicklei/go-restful/swagger/model_property_ext.go
generated
vendored
81
vendor/github.com/emicklei/go-restful/swagger/model_property_ext.go
generated
vendored
|
@ -1,81 +0,0 @@
|
|||
package swagger
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (prop *ModelProperty) setDescription(field reflect.StructField) {
|
||||
if tag := field.Tag.Get("description"); tag != "" {
|
||||
prop.Description = tag
|
||||
}
|
||||
}
|
||||
|
||||
func (prop *ModelProperty) setDefaultValue(field reflect.StructField) {
|
||||
if tag := field.Tag.Get("default"); tag != "" {
|
||||
prop.DefaultValue = Special(tag)
|
||||
}
|
||||
}
|
||||
|
||||
func (prop *ModelProperty) setEnumValues(field reflect.StructField) {
|
||||
// We use | to separate the enum values. This value is chosen
|
||||
// since its unlikely to be useful in actual enumeration values.
|
||||
if tag := field.Tag.Get("enum"); tag != "" {
|
||||
prop.Enum = strings.Split(tag, "|")
|
||||
}
|
||||
}
|
||||
|
||||
func (prop *ModelProperty) setMaximum(field reflect.StructField) {
|
||||
if tag := field.Tag.Get("maximum"); tag != "" {
|
||||
prop.Maximum = tag
|
||||
}
|
||||
}
|
||||
|
||||
func (prop *ModelProperty) setType(field reflect.StructField) {
|
||||
if tag := field.Tag.Get("type"); tag != "" {
|
||||
// Check if the first two characters of the type tag are
|
||||
// intended to emulate slice/array behaviour.
|
||||
//
|
||||
// If type is intended to be a slice/array then add the
|
||||
// overriden type to the array item instead of the main property
|
||||
if len(tag) > 2 && tag[0:2] == "[]" {
|
||||
pType := "array"
|
||||
prop.Type = &pType
|
||||
prop.Items = new(Item)
|
||||
|
||||
iType := tag[2:]
|
||||
prop.Items.Type = &iType
|
||||
return
|
||||
}
|
||||
|
||||
prop.Type = &tag
|
||||
}
|
||||
}
|
||||
|
||||
func (prop *ModelProperty) setMinimum(field reflect.StructField) {
|
||||
if tag := field.Tag.Get("minimum"); tag != "" {
|
||||
prop.Minimum = tag
|
||||
}
|
||||
}
|
||||
|
||||
func (prop *ModelProperty) setUniqueItems(field reflect.StructField) {
|
||||
tag := field.Tag.Get("unique")
|
||||
switch tag {
|
||||
case "true":
|
||||
v := true
|
||||
prop.UniqueItems = &v
|
||||
case "false":
|
||||
v := false
|
||||
prop.UniqueItems = &v
|
||||
}
|
||||
}
|
||||
|
||||
func (prop *ModelProperty) setPropertyMetadata(field reflect.StructField) {
|
||||
prop.setDescription(field)
|
||||
prop.setEnumValues(field)
|
||||
prop.setMinimum(field)
|
||||
prop.setMaximum(field)
|
||||
prop.setUniqueItems(field)
|
||||
prop.setDefaultValue(field)
|
||||
prop.setType(field)
|
||||
}
|
87
vendor/github.com/emicklei/go-restful/swagger/model_property_list.go
generated
vendored
87
vendor/github.com/emicklei/go-restful/swagger/model_property_list.go
generated
vendored
|
@ -1,87 +0,0 @@
|
|||
package swagger
|
||||
|
||||
// Copyright 2015 Ernest Micklei. All rights reserved.
|
||||
// Use of this source code is governed by a license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// NamedModelProperty associates a name to a ModelProperty
|
||||
type NamedModelProperty struct {
|
||||
Name string
|
||||
Property ModelProperty
|
||||
}
|
||||
|
||||
// ModelPropertyList encapsulates a list of NamedModelProperty (association)
|
||||
type ModelPropertyList struct {
|
||||
List []NamedModelProperty
|
||||
}
|
||||
|
||||
// At returns the ModelPropety by its name unless absent, then ok is false
|
||||
func (l *ModelPropertyList) At(name string) (p ModelProperty, ok bool) {
|
||||
for _, each := range l.List {
|
||||
if each.Name == name {
|
||||
return each.Property, true
|
||||
}
|
||||
}
|
||||
return p, false
|
||||
}
|
||||
|
||||
// Put adds or replaces a ModelProperty with this name
|
||||
func (l *ModelPropertyList) Put(name string, prop ModelProperty) {
|
||||
// maybe replace existing
|
||||
for i, each := range l.List {
|
||||
if each.Name == name {
|
||||
// replace
|
||||
l.List[i] = NamedModelProperty{Name: name, Property: prop}
|
||||
return
|
||||
}
|
||||
}
|
||||
// add
|
||||
l.List = append(l.List, NamedModelProperty{Name: name, Property: prop})
|
||||
}
|
||||
|
||||
// Do enumerates all the properties, each with its assigned name
|
||||
func (l *ModelPropertyList) Do(block func(name string, value ModelProperty)) {
|
||||
for _, each := range l.List {
|
||||
block(each.Name, each.Property)
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalJSON writes the ModelPropertyList as if it was a map[string]ModelProperty
|
||||
func (l ModelPropertyList) MarshalJSON() ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
encoder := json.NewEncoder(&buf)
|
||||
buf.WriteString("{\n")
|
||||
for i, each := range l.List {
|
||||
buf.WriteString("\"")
|
||||
buf.WriteString(each.Name)
|
||||
buf.WriteString("\": ")
|
||||
encoder.Encode(each.Property)
|
||||
if i < len(l.List)-1 {
|
||||
buf.WriteString(",\n")
|
||||
}
|
||||
}
|
||||
buf.WriteString("}")
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON reads back a ModelPropertyList. This is an expensive operation.
|
||||
func (l *ModelPropertyList) UnmarshalJSON(data []byte) error {
|
||||
raw := map[string]interface{}{}
|
||||
json.NewDecoder(bytes.NewReader(data)).Decode(&raw)
|
||||
for k, v := range raw {
|
||||
// produces JSON bytes for each value
|
||||
data, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var m ModelProperty
|
||||
json.NewDecoder(bytes.NewReader(data)).Decode(&m)
|
||||
l.Put(k, m)
|
||||
}
|
||||
return nil
|
||||
}
|
36
vendor/github.com/emicklei/go-restful/swagger/ordered_route_map.go
generated
vendored
36
vendor/github.com/emicklei/go-restful/swagger/ordered_route_map.go
generated
vendored
|
@ -1,36 +0,0 @@
|
|||
package swagger
|
||||
|
||||
// Copyright 2015 Ernest Micklei. All rights reserved.
|
||||
// Use of this source code is governed by a license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
import "github.com/emicklei/go-restful"
|
||||
|
||||
type orderedRouteMap struct {
|
||||
elements map[string][]restful.Route
|
||||
keys []string
|
||||
}
|
||||
|
||||
func newOrderedRouteMap() *orderedRouteMap {
|
||||
return &orderedRouteMap{
|
||||
elements: map[string][]restful.Route{},
|
||||
keys: []string{},
|
||||
}
|
||||
}
|
||||
|
||||
func (o *orderedRouteMap) Add(key string, route restful.Route) {
|
||||
routes, ok := o.elements[key]
|
||||
if ok {
|
||||
routes = append(routes, route)
|
||||
o.elements[key] = routes
|
||||
return
|
||||
}
|
||||
o.elements[key] = []restful.Route{route}
|
||||
o.keys = append(o.keys, key)
|
||||
}
|
||||
|
||||
func (o *orderedRouteMap) Do(block func(key string, routes []restful.Route)) {
|
||||
for _, k := range o.keys {
|
||||
block(k, o.elements[k])
|
||||
}
|
||||
}
|
185
vendor/github.com/emicklei/go-restful/swagger/swagger.go
generated
vendored
185
vendor/github.com/emicklei/go-restful/swagger/swagger.go
generated
vendored
|
@ -1,185 +0,0 @@
|
|||
// Package swagger implements the structures of the Swagger
|
||||
// https://github.com/wordnik/swagger-spec/blob/master/versions/1.2.md
|
||||
package swagger
|
||||
|
||||
const swaggerVersion = "1.2"
|
||||
|
||||
// 4.3.3 Data Type Fields
|
||||
type DataTypeFields struct {
|
||||
Type *string `json:"type,omitempty"` // if Ref not used
|
||||
Ref *string `json:"$ref,omitempty"` // if Type not used
|
||||
Format string `json:"format,omitempty"`
|
||||
DefaultValue Special `json:"defaultValue,omitempty"`
|
||||
Enum []string `json:"enum,omitempty"`
|
||||
Minimum string `json:"minimum,omitempty"`
|
||||
Maximum string `json:"maximum,omitempty"`
|
||||
Items *Item `json:"items,omitempty"`
|
||||
UniqueItems *bool `json:"uniqueItems,omitempty"`
|
||||
}
|
||||
|
||||
type Special string
|
||||
|
||||
// 4.3.4 Items Object
|
||||
type Item struct {
|
||||
Type *string `json:"type,omitempty"`
|
||||
Ref *string `json:"$ref,omitempty"`
|
||||
Format string `json:"format,omitempty"`
|
||||
}
|
||||
|
||||
// 5.1 Resource Listing
|
||||
type ResourceListing struct {
|
||||
SwaggerVersion string `json:"swaggerVersion"` // e.g 1.2
|
||||
Apis []Resource `json:"apis"`
|
||||
ApiVersion string `json:"apiVersion"`
|
||||
Info Info `json:"info"`
|
||||
Authorizations []Authorization `json:"authorizations,omitempty"`
|
||||
}
|
||||
|
||||
// 5.1.2 Resource Object
|
||||
type Resource struct {
|
||||
Path string `json:"path"` // relative or absolute, must start with /
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
// 5.1.3 Info Object
|
||||
type Info struct {
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
TermsOfServiceUrl string `json:"termsOfServiceUrl,omitempty"`
|
||||
Contact string `json:"contact,omitempty"`
|
||||
License string `json:"license,omitempty"`
|
||||
LicenseUrl string `json:"licenseUrl,omitempty"`
|
||||
}
|
||||
|
||||
// 5.1.5
|
||||
type Authorization struct {
|
||||
Type string `json:"type"`
|
||||
PassAs string `json:"passAs"`
|
||||
Keyname string `json:"keyname"`
|
||||
Scopes []Scope `json:"scopes"`
|
||||
GrantTypes []GrantType `json:"grandTypes"`
|
||||
}
|
||||
|
||||
// 5.1.6, 5.2.11
|
||||
type Scope struct {
|
||||
// Required. The name of the scope.
|
||||
Scope string `json:"scope"`
|
||||
// Recommended. A short description of the scope.
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
// 5.1.7
|
||||
type GrantType struct {
|
||||
Implicit Implicit `json:"implicit"`
|
||||
AuthorizationCode AuthorizationCode `json:"authorization_code"`
|
||||
}
|
||||
|
||||
// 5.1.8 Implicit Object
|
||||
type Implicit struct {
|
||||
// Required. The login endpoint definition.
|
||||
loginEndpoint LoginEndpoint `json:"loginEndpoint"`
|
||||
// An optional alternative name to standard "access_token" OAuth2 parameter.
|
||||
TokenName string `json:"tokenName"`
|
||||
}
|
||||
|
||||
// 5.1.9 Authorization Code Object
|
||||
type AuthorizationCode struct {
|
||||
TokenRequestEndpoint TokenRequestEndpoint `json:"tokenRequestEndpoint"`
|
||||
TokenEndpoint TokenEndpoint `json:"tokenEndpoint"`
|
||||
}
|
||||
|
||||
// 5.1.10 Login Endpoint Object
|
||||
type LoginEndpoint struct {
|
||||
// Required. The URL of the authorization endpoint for the implicit grant flow. The value SHOULD be in a URL format.
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
// 5.1.11 Token Request Endpoint Object
|
||||
type TokenRequestEndpoint struct {
|
||||
// Required. The URL of the authorization endpoint for the authentication code grant flow. The value SHOULD be in a URL format.
|
||||
Url string `json:"url"`
|
||||
// An optional alternative name to standard "client_id" OAuth2 parameter.
|
||||
ClientIdName string `json:"clientIdName"`
|
||||
// An optional alternative name to the standard "client_secret" OAuth2 parameter.
|
||||
ClientSecretName string `json:"clientSecretName"`
|
||||
}
|
||||
|
||||
// 5.1.12 Token Endpoint Object
|
||||
type TokenEndpoint struct {
|
||||
// Required. The URL of the token endpoint for the authentication code grant flow. The value SHOULD be in a URL format.
|
||||
Url string `json:"url"`
|
||||
// An optional alternative name to standard "access_token" OAuth2 parameter.
|
||||
TokenName string `json:"tokenName"`
|
||||
}
|
||||
|
||||
// 5.2 API Declaration
|
||||
type ApiDeclaration struct {
|
||||
SwaggerVersion string `json:"swaggerVersion"`
|
||||
ApiVersion string `json:"apiVersion"`
|
||||
BasePath string `json:"basePath"`
|
||||
ResourcePath string `json:"resourcePath"` // must start with /
|
||||
Info Info `json:"info"`
|
||||
Apis []Api `json:"apis,omitempty"`
|
||||
Models ModelList `json:"models,omitempty"`
|
||||
Produces []string `json:"produces,omitempty"`
|
||||
Consumes []string `json:"consumes,omitempty"`
|
||||
Authorizations []Authorization `json:"authorizations,omitempty"`
|
||||
}
|
||||
|
||||
// 5.2.2 API Object
|
||||
type Api struct {
|
||||
Path string `json:"path"` // relative or absolute, must start with /
|
||||
Description string `json:"description"`
|
||||
Operations []Operation `json:"operations,omitempty"`
|
||||
}
|
||||
|
||||
// 5.2.3 Operation Object
|
||||
type Operation struct {
|
||||
DataTypeFields
|
||||
Method string `json:"method"`
|
||||
Summary string `json:"summary,omitempty"`
|
||||
Notes string `json:"notes,omitempty"`
|
||||
Nickname string `json:"nickname"`
|
||||
Authorizations []Authorization `json:"authorizations,omitempty"`
|
||||
Parameters []Parameter `json:"parameters"`
|
||||
ResponseMessages []ResponseMessage `json:"responseMessages,omitempty"` // optional
|
||||
Produces []string `json:"produces,omitempty"`
|
||||
Consumes []string `json:"consumes,omitempty"`
|
||||
Deprecated string `json:"deprecated,omitempty"`
|
||||
}
|
||||
|
||||
// 5.2.4 Parameter Object
|
||||
type Parameter struct {
|
||||
DataTypeFields
|
||||
ParamType string `json:"paramType"` // path,query,body,header,form
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Required bool `json:"required"`
|
||||
AllowMultiple bool `json:"allowMultiple"`
|
||||
}
|
||||
|
||||
// 5.2.5 Response Message Object
|
||||
type ResponseMessage struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
ResponseModel string `json:"responseModel,omitempty"`
|
||||
}
|
||||
|
||||
// 5.2.6, 5.2.7 Models Object
|
||||
type Model struct {
|
||||
Id string `json:"id"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Required []string `json:"required,omitempty"`
|
||||
Properties ModelPropertyList `json:"properties"`
|
||||
SubTypes []string `json:"subTypes,omitempty"`
|
||||
Discriminator string `json:"discriminator,omitempty"`
|
||||
}
|
||||
|
||||
// 5.2.8 Properties Object
|
||||
type ModelProperty struct {
|
||||
DataTypeFields
|
||||
Description string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
// 5.2.10
|
||||
type Authorizations map[string]Authorization
|
21
vendor/github.com/emicklei/go-restful/swagger/swagger_builder.go
generated
vendored
21
vendor/github.com/emicklei/go-restful/swagger/swagger_builder.go
generated
vendored
|
@ -1,21 +0,0 @@
|
|||
package swagger
|
||||
|
||||
type SwaggerBuilder struct {
|
||||
SwaggerService
|
||||
}
|
||||
|
||||
func NewSwaggerBuilder(config Config) *SwaggerBuilder {
|
||||
return &SwaggerBuilder{*newSwaggerService(config)}
|
||||
}
|
||||
|
||||
func (sb SwaggerBuilder) ProduceListing() ResourceListing {
|
||||
return sb.SwaggerService.produceListing()
|
||||
}
|
||||
|
||||
func (sb SwaggerBuilder) ProduceAllDeclarations() map[string]ApiDeclaration {
|
||||
return sb.SwaggerService.produceAllDeclarations()
|
||||
}
|
||||
|
||||
func (sb SwaggerBuilder) ProduceDeclarations(route string) (*ApiDeclaration, bool) {
|
||||
return sb.SwaggerService.produceDeclarations(route)
|
||||
}
|
440
vendor/github.com/emicklei/go-restful/swagger/swagger_webservice.go
generated
vendored
440
vendor/github.com/emicklei/go-restful/swagger/swagger_webservice.go
generated
vendored
|
@ -1,440 +0,0 @@
|
|||
package swagger
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
// "github.com/emicklei/hopwatch"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/emicklei/go-restful/log"
|
||||
)
|
||||
|
||||
type SwaggerService struct {
|
||||
config Config
|
||||
apiDeclarationMap *ApiDeclarationList
|
||||
}
|
||||
|
||||
func newSwaggerService(config Config) *SwaggerService {
|
||||
sws := &SwaggerService{
|
||||
config: config,
|
||||
apiDeclarationMap: new(ApiDeclarationList)}
|
||||
|
||||
// Build all ApiDeclarations
|
||||
for _, each := range config.WebServices {
|
||||
rootPath := each.RootPath()
|
||||
// skip the api service itself
|
||||
if rootPath != config.ApiPath {
|
||||
if rootPath == "" || rootPath == "/" {
|
||||
// use routes
|
||||
for _, route := range each.Routes() {
|
||||
entry := staticPathFromRoute(route)
|
||||
_, exists := sws.apiDeclarationMap.At(entry)
|
||||
if !exists {
|
||||
sws.apiDeclarationMap.Put(entry, sws.composeDeclaration(each, entry))
|
||||
}
|
||||
}
|
||||
} else { // use root path
|
||||
sws.apiDeclarationMap.Put(each.RootPath(), sws.composeDeclaration(each, each.RootPath()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if specified then call the PostBuilderHandler
|
||||
if config.PostBuildHandler != nil {
|
||||
config.PostBuildHandler(sws.apiDeclarationMap)
|
||||
}
|
||||
return sws
|
||||
}
|
||||
|
||||
// LogInfo is the function that is called when this package needs to log. It defaults to log.Printf
|
||||
var LogInfo = func(format string, v ...interface{}) {
|
||||
// use the restful package-wide logger
|
||||
log.Printf(format, v...)
|
||||
}
|
||||
|
||||
// InstallSwaggerService add the WebService that provides the API documentation of all services
|
||||
// conform the Swagger documentation specifcation. (https://github.com/wordnik/swagger-core/wiki).
|
||||
func InstallSwaggerService(aSwaggerConfig Config) {
|
||||
RegisterSwaggerService(aSwaggerConfig, restful.DefaultContainer)
|
||||
}
|
||||
|
||||
// RegisterSwaggerService add the WebService that provides the API documentation of all services
|
||||
// conform the Swagger documentation specifcation. (https://github.com/wordnik/swagger-core/wiki).
|
||||
func RegisterSwaggerService(config Config, wsContainer *restful.Container) {
|
||||
sws := newSwaggerService(config)
|
||||
ws := new(restful.WebService)
|
||||
ws.Path(config.ApiPath)
|
||||
ws.Produces(restful.MIME_JSON)
|
||||
if config.DisableCORS {
|
||||
ws.Filter(enableCORS)
|
||||
}
|
||||
ws.Route(ws.GET("/").To(sws.getListing))
|
||||
ws.Route(ws.GET("/{a}").To(sws.getDeclarations))
|
||||
ws.Route(ws.GET("/{a}/{b}").To(sws.getDeclarations))
|
||||
ws.Route(ws.GET("/{a}/{b}/{c}").To(sws.getDeclarations))
|
||||
ws.Route(ws.GET("/{a}/{b}/{c}/{d}").To(sws.getDeclarations))
|
||||
ws.Route(ws.GET("/{a}/{b}/{c}/{d}/{e}").To(sws.getDeclarations))
|
||||
ws.Route(ws.GET("/{a}/{b}/{c}/{d}/{e}/{f}").To(sws.getDeclarations))
|
||||
ws.Route(ws.GET("/{a}/{b}/{c}/{d}/{e}/{f}/{g}").To(sws.getDeclarations))
|
||||
LogInfo("[restful/swagger] listing is available at %v%v", config.WebServicesUrl, config.ApiPath)
|
||||
wsContainer.Add(ws)
|
||||
|
||||
// Check paths for UI serving
|
||||
if config.StaticHandler == nil && config.SwaggerFilePath != "" && config.SwaggerPath != "" {
|
||||
swaggerPathSlash := config.SwaggerPath
|
||||
// path must end with slash /
|
||||
if "/" != config.SwaggerPath[len(config.SwaggerPath)-1:] {
|
||||
LogInfo("[restful/swagger] use corrected SwaggerPath ; must end with slash (/)")
|
||||
swaggerPathSlash += "/"
|
||||
}
|
||||
|
||||
LogInfo("[restful/swagger] %v%v is mapped to folder %v", config.WebServicesUrl, swaggerPathSlash, config.SwaggerFilePath)
|
||||
wsContainer.Handle(swaggerPathSlash, http.StripPrefix(swaggerPathSlash, http.FileServer(http.Dir(config.SwaggerFilePath))))
|
||||
|
||||
//if we define a custom static handler use it
|
||||
} else if config.StaticHandler != nil && config.SwaggerPath != "" {
|
||||
swaggerPathSlash := config.SwaggerPath
|
||||
// path must end with slash /
|
||||
if "/" != config.SwaggerPath[len(config.SwaggerPath)-1:] {
|
||||
LogInfo("[restful/swagger] use corrected SwaggerFilePath ; must end with slash (/)")
|
||||
swaggerPathSlash += "/"
|
||||
|
||||
}
|
||||
LogInfo("[restful/swagger] %v%v is mapped to custom Handler %T", config.WebServicesUrl, swaggerPathSlash, config.StaticHandler)
|
||||
wsContainer.Handle(swaggerPathSlash, config.StaticHandler)
|
||||
|
||||
} else {
|
||||
LogInfo("[restful/swagger] Swagger(File)Path is empty ; no UI is served")
|
||||
}
|
||||
}
|
||||
|
||||
func staticPathFromRoute(r restful.Route) string {
|
||||
static := r.Path
|
||||
bracket := strings.Index(static, "{")
|
||||
if bracket <= 1 { // result cannot be empty
|
||||
return static
|
||||
}
|
||||
if bracket != -1 {
|
||||
static = r.Path[:bracket]
|
||||
}
|
||||
if strings.HasSuffix(static, "/") {
|
||||
return static[:len(static)-1]
|
||||
} else {
|
||||
return static
|
||||
}
|
||||
}
|
||||
|
||||
func enableCORS(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) {
|
||||
if origin := req.HeaderParameter(restful.HEADER_Origin); origin != "" {
|
||||
// prevent duplicate header
|
||||
if len(resp.Header().Get(restful.HEADER_AccessControlAllowOrigin)) == 0 {
|
||||
resp.AddHeader(restful.HEADER_AccessControlAllowOrigin, origin)
|
||||
}
|
||||
}
|
||||
chain.ProcessFilter(req, resp)
|
||||
}
|
||||
|
||||
func (sws SwaggerService) getListing(req *restful.Request, resp *restful.Response) {
|
||||
listing := sws.produceListing()
|
||||
resp.WriteAsJson(listing)
|
||||
}
|
||||
|
||||
func (sws SwaggerService) produceListing() ResourceListing {
|
||||
listing := ResourceListing{SwaggerVersion: swaggerVersion, ApiVersion: sws.config.ApiVersion, Info: sws.config.Info}
|
||||
sws.apiDeclarationMap.Do(func(k string, v ApiDeclaration) {
|
||||
ref := Resource{Path: k}
|
||||
if len(v.Apis) > 0 { // use description of first (could still be empty)
|
||||
ref.Description = v.Apis[0].Description
|
||||
}
|
||||
listing.Apis = append(listing.Apis, ref)
|
||||
})
|
||||
return listing
|
||||
}
|
||||
|
||||
func (sws SwaggerService) getDeclarations(req *restful.Request, resp *restful.Response) {
|
||||
decl, ok := sws.produceDeclarations(composeRootPath(req))
|
||||
if !ok {
|
||||
resp.WriteErrorString(http.StatusNotFound, "ApiDeclaration not found")
|
||||
return
|
||||
}
|
||||
// unless WebServicesUrl is given
|
||||
if len(sws.config.WebServicesUrl) == 0 {
|
||||
// update base path from the actual request
|
||||
// TODO how to detect https? assume http for now
|
||||
var host string
|
||||
// X-Forwarded-Host or Host or Request.Host
|
||||
hostvalues, ok := req.Request.Header["X-Forwarded-Host"] // apache specific?
|
||||
if !ok || len(hostvalues) == 0 {
|
||||
forwarded, ok := req.Request.Header["Host"] // without reverse-proxy
|
||||
if !ok || len(forwarded) == 0 {
|
||||
// fallback to Host field
|
||||
host = req.Request.Host
|
||||
} else {
|
||||
host = forwarded[0]
|
||||
}
|
||||
} else {
|
||||
host = hostvalues[0]
|
||||
}
|
||||
// inspect Referer for the scheme (http vs https)
|
||||
scheme := "http"
|
||||
if referer := req.Request.Header["Referer"]; len(referer) > 0 {
|
||||
if strings.HasPrefix(referer[0], "https") {
|
||||
scheme = "https"
|
||||
}
|
||||
}
|
||||
decl.BasePath = fmt.Sprintf("%s://%s", scheme, host)
|
||||
}
|
||||
resp.WriteAsJson(decl)
|
||||
}
|
||||
|
||||
func (sws SwaggerService) produceAllDeclarations() map[string]ApiDeclaration {
|
||||
decls := map[string]ApiDeclaration{}
|
||||
sws.apiDeclarationMap.Do(func(k string, v ApiDeclaration) {
|
||||
decls[k] = v
|
||||
})
|
||||
return decls
|
||||
}
|
||||
|
||||
func (sws SwaggerService) produceDeclarations(route string) (*ApiDeclaration, bool) {
|
||||
decl, ok := sws.apiDeclarationMap.At(route)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
decl.BasePath = sws.config.WebServicesUrl
|
||||
return &decl, true
|
||||
}
|
||||
|
||||
// composeDeclaration uses all routes and parameters to create a ApiDeclaration
|
||||
func (sws SwaggerService) composeDeclaration(ws *restful.WebService, pathPrefix string) ApiDeclaration {
|
||||
decl := ApiDeclaration{
|
||||
SwaggerVersion: swaggerVersion,
|
||||
BasePath: sws.config.WebServicesUrl,
|
||||
ResourcePath: pathPrefix,
|
||||
Models: ModelList{},
|
||||
ApiVersion: ws.Version()}
|
||||
|
||||
// collect any path parameters
|
||||
rootParams := []Parameter{}
|
||||
for _, param := range ws.PathParameters() {
|
||||
rootParams = append(rootParams, asSwaggerParameter(param.Data()))
|
||||
}
|
||||
// aggregate by path
|
||||
pathToRoutes := newOrderedRouteMap()
|
||||
for _, other := range ws.Routes() {
|
||||
if strings.HasPrefix(other.Path, pathPrefix) {
|
||||
pathToRoutes.Add(other.Path, other)
|
||||
}
|
||||
}
|
||||
pathToRoutes.Do(func(path string, routes []restful.Route) {
|
||||
api := Api{Path: strings.TrimSuffix(withoutWildcard(path), "/"), Description: ws.Documentation()}
|
||||
voidString := "void"
|
||||
for _, route := range routes {
|
||||
operation := Operation{
|
||||
Method: route.Method,
|
||||
Summary: route.Doc,
|
||||
Notes: route.Notes,
|
||||
// Type gets overwritten if there is a write sample
|
||||
DataTypeFields: DataTypeFields{Type: &voidString},
|
||||
Parameters: []Parameter{},
|
||||
Nickname: route.Operation,
|
||||
ResponseMessages: composeResponseMessages(route, &decl, &sws.config)}
|
||||
|
||||
operation.Consumes = route.Consumes
|
||||
operation.Produces = route.Produces
|
||||
|
||||
// share root params if any
|
||||
for _, swparam := range rootParams {
|
||||
operation.Parameters = append(operation.Parameters, swparam)
|
||||
}
|
||||
// route specific params
|
||||
for _, param := range route.ParameterDocs {
|
||||
operation.Parameters = append(operation.Parameters, asSwaggerParameter(param.Data()))
|
||||
}
|
||||
|
||||
sws.addModelsFromRouteTo(&operation, route, &decl)
|
||||
api.Operations = append(api.Operations, operation)
|
||||
}
|
||||
decl.Apis = append(decl.Apis, api)
|
||||
})
|
||||
return decl
|
||||
}
|
||||
|
||||
func withoutWildcard(path string) string {
|
||||
if strings.HasSuffix(path, ":*}") {
|
||||
return path[0:len(path)-3] + "}"
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
// composeResponseMessages takes the ResponseErrors (if any) and creates ResponseMessages from them.
|
||||
func composeResponseMessages(route restful.Route, decl *ApiDeclaration, config *Config) (messages []ResponseMessage) {
|
||||
if route.ResponseErrors == nil {
|
||||
return messages
|
||||
}
|
||||
// sort by code
|
||||
codes := sort.IntSlice{}
|
||||
for code := range route.ResponseErrors {
|
||||
codes = append(codes, code)
|
||||
}
|
||||
codes.Sort()
|
||||
for _, code := range codes {
|
||||
each := route.ResponseErrors[code]
|
||||
message := ResponseMessage{
|
||||
Code: code,
|
||||
Message: each.Message,
|
||||
}
|
||||
if each.Model != nil {
|
||||
st := reflect.TypeOf(each.Model)
|
||||
isCollection, st := detectCollectionType(st)
|
||||
modelName := modelBuilder{}.keyFrom(st)
|
||||
if isCollection {
|
||||
modelName = "array[" + modelName + "]"
|
||||
}
|
||||
modelBuilder{Models: &decl.Models, Config: config}.addModel(st, "")
|
||||
// reference the model
|
||||
message.ResponseModel = modelName
|
||||
}
|
||||
messages = append(messages, message)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// addModelsFromRoute takes any read or write sample from the Route and creates a Swagger model from it.
|
||||
func (sws SwaggerService) addModelsFromRouteTo(operation *Operation, route restful.Route, decl *ApiDeclaration) {
|
||||
if route.ReadSample != nil {
|
||||
sws.addModelFromSampleTo(operation, false, route.ReadSample, &decl.Models)
|
||||
}
|
||||
if route.WriteSample != nil {
|
||||
sws.addModelFromSampleTo(operation, true, route.WriteSample, &decl.Models)
|
||||
}
|
||||
}
|
||||
|
||||
func detectCollectionType(st reflect.Type) (bool, reflect.Type) {
|
||||
isCollection := false
|
||||
if st.Kind() == reflect.Slice || st.Kind() == reflect.Array {
|
||||
st = st.Elem()
|
||||
isCollection = true
|
||||
} else {
|
||||
if st.Kind() == reflect.Ptr {
|
||||
if st.Elem().Kind() == reflect.Slice || st.Elem().Kind() == reflect.Array {
|
||||
st = st.Elem().Elem()
|
||||
isCollection = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return isCollection, st
|
||||
}
|
||||
|
||||
// addModelFromSample creates and adds (or overwrites) a Model from a sample resource
|
||||
func (sws SwaggerService) addModelFromSampleTo(operation *Operation, isResponse bool, sample interface{}, models *ModelList) {
|
||||
if isResponse {
|
||||
type_, items := asDataType(sample, &sws.config)
|
||||
operation.Type = type_
|
||||
operation.Items = items
|
||||
}
|
||||
modelBuilder{Models: models, Config: &sws.config}.addModelFrom(sample)
|
||||
}
|
||||
|
||||
func asSwaggerParameter(param restful.ParameterData) Parameter {
|
||||
return Parameter{
|
||||
DataTypeFields: DataTypeFields{
|
||||
Type: ¶m.DataType,
|
||||
Format: asFormat(param.DataType, param.DataFormat),
|
||||
DefaultValue: Special(param.DefaultValue),
|
||||
},
|
||||
Name: param.Name,
|
||||
Description: param.Description,
|
||||
ParamType: asParamType(param.Kind),
|
||||
|
||||
Required: param.Required}
|
||||
}
|
||||
|
||||
// Between 1..7 path parameters is supported
|
||||
func composeRootPath(req *restful.Request) string {
|
||||
path := "/" + req.PathParameter("a")
|
||||
b := req.PathParameter("b")
|
||||
if b == "" {
|
||||
return path
|
||||
}
|
||||
path = path + "/" + b
|
||||
c := req.PathParameter("c")
|
||||
if c == "" {
|
||||
return path
|
||||
}
|
||||
path = path + "/" + c
|
||||
d := req.PathParameter("d")
|
||||
if d == "" {
|
||||
return path
|
||||
}
|
||||
path = path + "/" + d
|
||||
e := req.PathParameter("e")
|
||||
if e == "" {
|
||||
return path
|
||||
}
|
||||
path = path + "/" + e
|
||||
f := req.PathParameter("f")
|
||||
if f == "" {
|
||||
return path
|
||||
}
|
||||
path = path + "/" + f
|
||||
g := req.PathParameter("g")
|
||||
if g == "" {
|
||||
return path
|
||||
}
|
||||
return path + "/" + g
|
||||
}
|
||||
|
||||
func asFormat(dataType string, dataFormat string) string {
|
||||
if dataFormat != "" {
|
||||
return dataFormat
|
||||
}
|
||||
return "" // TODO
|
||||
}
|
||||
|
||||
func asParamType(kind int) string {
|
||||
switch {
|
||||
case kind == restful.PathParameterKind:
|
||||
return "path"
|
||||
case kind == restful.QueryParameterKind:
|
||||
return "query"
|
||||
case kind == restful.BodyParameterKind:
|
||||
return "body"
|
||||
case kind == restful.HeaderParameterKind:
|
||||
return "header"
|
||||
case kind == restful.FormParameterKind:
|
||||
return "form"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func asDataType(any interface{}, config *Config) (*string, *Item) {
|
||||
// If it's not a collection, return the suggested model name
|
||||
st := reflect.TypeOf(any)
|
||||
isCollection, st := detectCollectionType(st)
|
||||
modelName := modelBuilder{}.keyFrom(st)
|
||||
// if it's not a collection we are done
|
||||
if !isCollection {
|
||||
return &modelName, nil
|
||||
}
|
||||
|
||||
// XXX: This is not very elegant
|
||||
// We create an Item object referring to the given model
|
||||
models := ModelList{}
|
||||
mb := modelBuilder{Models: &models, Config: config}
|
||||
mb.addModelFrom(any)
|
||||
|
||||
elemTypeName := mb.getElementTypeName(modelName, "", st)
|
||||
item := new(Item)
|
||||
if mb.isPrimitiveType(elemTypeName) {
|
||||
mapped := mb.jsonSchemaType(elemTypeName)
|
||||
item.Type = &mapped
|
||||
} else {
|
||||
item.Ref = &elemTypeName
|
||||
}
|
||||
tmp := "array"
|
||||
return &tmp, item
|
||||
}
|
36
vendor/github.com/emicklei/go-restful/web_service.go
generated
vendored
36
vendor/github.com/emicklei/go-restful/web_service.go
generated
vendored
|
@ -3,6 +3,7 @@ package restful
|
|||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"reflect"
|
||||
"sync"
|
||||
|
||||
"github.com/emicklei/go-restful/log"
|
||||
|
@ -24,6 +25,8 @@ type WebService struct {
|
|||
documentation string
|
||||
apiVersion string
|
||||
|
||||
typeNameHandleFunc TypeNameHandleFunction
|
||||
|
||||
dynamicRoutes bool
|
||||
|
||||
// protects 'routes' if dynamic routes are enabled
|
||||
|
@ -34,6 +37,25 @@ func (w *WebService) SetDynamicRoutes(enable bool) {
|
|||
w.dynamicRoutes = enable
|
||||
}
|
||||
|
||||
// TypeNameHandleFunction declares functions that can handle translating the name of a sample object
|
||||
// into the restful documentation for the service.
|
||||
type TypeNameHandleFunction func(sample interface{}) string
|
||||
|
||||
// TypeNameHandler sets the function that will convert types to strings in the parameter
|
||||
// and model definitions. If not set, the web service will invoke
|
||||
// reflect.TypeOf(object).String().
|
||||
func (w *WebService) TypeNameHandler(handler TypeNameHandleFunction) *WebService {
|
||||
w.typeNameHandleFunc = handler
|
||||
return w
|
||||
}
|
||||
|
||||
// reflectTypeName is the default TypeNameHandleFunction and for a given object
|
||||
// returns the name that Go identifies it with (e.g. "string" or "v1.Object") via
|
||||
// the reflection API.
|
||||
func reflectTypeName(sample interface{}) string {
|
||||
return reflect.TypeOf(sample).String()
|
||||
}
|
||||
|
||||
// compilePathExpression ensures that the path is compiled into a RegEx for those routers that need it.
|
||||
func (w *WebService) compilePathExpression() {
|
||||
compiled, err := newPathExpression(w.rootPath)
|
||||
|
@ -174,7 +196,7 @@ func (w *WebService) RemoveRoute(path, method string) error {
|
|||
|
||||
// Method creates a new RouteBuilder and initialize its http method
|
||||
func (w *WebService) Method(httpMethod string) *RouteBuilder {
|
||||
return new(RouteBuilder).servicePath(w.rootPath).Method(httpMethod)
|
||||
return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method(httpMethod)
|
||||
}
|
||||
|
||||
// Produces specifies that this WebService can produce one or more MIME types.
|
||||
|
@ -239,30 +261,30 @@ func (w *WebService) Documentation() string {
|
|||
|
||||
// HEAD is a shortcut for .Method("HEAD").Path(subPath)
|
||||
func (w *WebService) HEAD(subPath string) *RouteBuilder {
|
||||
return new(RouteBuilder).servicePath(w.rootPath).Method("HEAD").Path(subPath)
|
||||
return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("HEAD").Path(subPath)
|
||||
}
|
||||
|
||||
// GET is a shortcut for .Method("GET").Path(subPath)
|
||||
func (w *WebService) GET(subPath string) *RouteBuilder {
|
||||
return new(RouteBuilder).servicePath(w.rootPath).Method("GET").Path(subPath)
|
||||
return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("GET").Path(subPath)
|
||||
}
|
||||
|
||||
// POST is a shortcut for .Method("POST").Path(subPath)
|
||||
func (w *WebService) POST(subPath string) *RouteBuilder {
|
||||
return new(RouteBuilder).servicePath(w.rootPath).Method("POST").Path(subPath)
|
||||
return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("POST").Path(subPath)
|
||||
}
|
||||
|
||||
// PUT is a shortcut for .Method("PUT").Path(subPath)
|
||||
func (w *WebService) PUT(subPath string) *RouteBuilder {
|
||||
return new(RouteBuilder).servicePath(w.rootPath).Method("PUT").Path(subPath)
|
||||
return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("PUT").Path(subPath)
|
||||
}
|
||||
|
||||
// PATCH is a shortcut for .Method("PATCH").Path(subPath)
|
||||
func (w *WebService) PATCH(subPath string) *RouteBuilder {
|
||||
return new(RouteBuilder).servicePath(w.rootPath).Method("PATCH").Path(subPath)
|
||||
return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("PATCH").Path(subPath)
|
||||
}
|
||||
|
||||
// DELETE is a shortcut for .Method("DELETE").Path(subPath)
|
||||
func (w *WebService) DELETE(subPath string) *RouteBuilder {
|
||||
return new(RouteBuilder).servicePath(w.rootPath).Method("DELETE").Path(subPath)
|
||||
return new(RouteBuilder).typeNameHandler(w.typeNameHandleFunc).servicePath(w.rootPath).Method("DELETE").Path(subPath)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue