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()}
	rootParams := []Parameter{}
	for _, param := range ws.PathParameters() {
		rootParams = append(rootParams, asSwaggerParameter(param.Data()))
	}
	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(path, "/"), Description: ws.Documentation()}
		voidString := "void"
		for _, route := range routes {
			operation := Operation{
				Method:  route.Method,
				Summary: route.Doc,
				Notes:   route.Notes,
				DataTypeFields:   DataTypeFields{Type: &voidString},
				Parameters:       []Parameter{},
				Nickname:         route.Operation,
				ResponseMessages: composeResponseMessages(route, &decl)}
			operation.Consumes = route.Consumes
			operation.Produces = route.Produces
			for _, swparam := range rootParams {
				operation.Parameters = append(operation.Parameters, swparam)
			}
			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
}
composeDeclaration uses all routes and parameters to create a ApiDeclaration
package swagger
import (
	"fmt"
	"github.com/emicklei/go-restful"
	"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)}
	for _, each := range config.WebServices {
		rootPath := each.RootPath()
		if rootPath != config.ApiPath {
			if rootPath == "" || rootPath == "/" {
				for _, route := range each.Routes() {
					entry := staticPathFromRoute(route)
					_, exists := sws.apiDeclarationMap.At(entry)
					if !exists {
						sws.apiDeclarationMap.Put(entry, sws.composeDeclaration(each, entry))
					}
				}
			} else {  
				sws.apiDeclarationMap.Put(each.RootPath(), sws.composeDeclaration(each, each.RootPath()))
			}
		}
	}
	if config.PostBuildHandler != nil {
		config.PostBuildHandler(sws.apiDeclarationMap)
	}
	return sws
}
var LogInfo = func(format string, v ...interface{}) {
	log.Printf(format, v...)
}
func InstallSwaggerService(aSwaggerConfig Config) {
	RegisterSwaggerService(aSwaggerConfig, restful.DefaultContainer)
}
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)
	if config.StaticHandler == nil && config.SwaggerFilePath != "" && config.SwaggerPath != "" {
		swaggerPathSlash := config.SwaggerPath
		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))))
	} else if config.StaticHandler != nil && config.SwaggerPath != "" {
		swaggerPathSlash := config.SwaggerPath
		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 {  
		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 != "" {
		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 {  
			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
	}
	if len(sws.config.WebServicesUrl) == 0 {
		var host string
		hostvalues, ok := req.Request.Header["X-Forwarded-Host"]  
		if !ok || len(hostvalues) == 0 {
			forwarded, ok := req.Request.Header["Host"]  
			if !ok || len(forwarded) == 0 {
				host = req.Request.Host
			} else {
				host = forwarded[0]
			}
		} else {
			host = hostvalues[0]
		}
		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
}