package echoSwagger import ( "html/template" "net/http" "path/filepath" "regexp" "github.com/ghodss/yaml" "github.com/labstack/echo/v4" swaggerFiles "github.com/swaggo/files/v2" "github.com/swaggo/swag" ) // Config stores echoSwagger configuration variables. type Config struct { // The url pointing to API definition (normally swagger.json or swagger.yaml). Default is `mockedSwag.json`. URLs []string DocExpansion string DomID string InstanceName string DeepLinking bool PersistAuthorization bool SyntaxHighlight bool // The information for OAuth2 integration, if any. OAuth *OAuthConfig } // OAuthConfig stores configuration for Swagger UI OAuth2 integration. See // https://swagger.io/docs/open-source-tools/swagger-ui/usage/oauth2/ for further details. type OAuthConfig struct { // The ID of the client sent to the OAuth2 IAM provider. ClientId string // The OAuth2 realm that the client should operate in. If not applicable, use empty string. Realm string // The name to display for the application in the authentication popup. AppName string } // URL presents the url pointing to API definition (normally swagger.json or swagger.yaml). func URL(url string) func(*Config) { return func(c *Config) { c.URLs = append(c.URLs, url) } } // DeepLinking true, false. func DeepLinking(deepLinking bool) func(*Config) { return func(c *Config) { c.DeepLinking = deepLinking } } // SyntaxHighlight true, false. func SyntaxHighlight(syntaxHighlight bool) func(*Config) { return func(c *Config) { c.SyntaxHighlight = syntaxHighlight } } // DocExpansion list, full, none. func DocExpansion(docExpansion string) func(*Config) { return func(c *Config) { c.DocExpansion = docExpansion } } // DomID #swagger-ui. func DomID(domID string) func(*Config) { return func(c *Config) { c.DomID = domID } } // InstanceName specified swag instance name. func InstanceName(instanceName string) func(*Config) { return func(c *Config) { c.InstanceName = instanceName } } // PersistAuthorization Persist authorization information over browser close/refresh. // Defaults to false. func PersistAuthorization(persistAuthorization bool) func(*Config) { return func(c *Config) { c.PersistAuthorization = persistAuthorization } } func OAuth(config *OAuthConfig) func(*Config) { return func(c *Config) { c.OAuth = config } } func newConfig(configFns ...func(*Config)) *Config { config := Config{ URLs: []string{"doc.json", "doc.yaml"}, DocExpansion: "list", DomID: "swagger-ui", InstanceName: "swagger", DeepLinking: true, PersistAuthorization: false, SyntaxHighlight: true, } for _, fn := range configFns { fn(&config) } if config.InstanceName == "" { config.InstanceName = swag.Name } return &config } // WrapHandler wraps swaggerFiles.Handler and returns echo.HandlerFunc var WrapHandler = EchoWrapHandler() // EchoWrapHandler wraps `http.Handler` into `echo.HandlerFunc`. func EchoWrapHandler(options ...func(*Config)) echo.HandlerFunc { config := newConfig(options...) // create a template with name index, _ := template.New("swagger_index.html").Parse(indexTemplate) var re = regexp.MustCompile(`^(.*/)([^?].*)?[?|.]*$`) return func(c echo.Context) error { if c.Request().Method != http.MethodGet { return echo.NewHTTPError(http.StatusMethodNotAllowed, http.StatusText(http.StatusMethodNotAllowed)) } matches := re.FindStringSubmatch(c.Request().RequestURI) path := matches[2] switch filepath.Ext(path) { case ".html": c.Response().Header().Set("Content-Type", "text/html; charset=utf-8") case ".css": c.Response().Header().Set("Content-Type", "text/css; charset=utf-8") case ".js": c.Response().Header().Set("Content-Type", "application/javascript") case ".json": c.Response().Header().Set("Content-Type", "application/json; charset=utf-8") case ".yaml": c.Response().Header().Set("Content-Type", "text/plain; charset=utf-8") case ".png": c.Response().Header().Set("Content-Type", "image/png") } response := c.Response() // This check fixes an error introduced here: https://github.com/labstack/echo/blob/8da8e161380fd926d4341721f0328f1e94d6d0a2/response.go#L86-L88 if _, ok := response.Writer.(http.Flusher); ok { defer response.Flush() } switch path { case "": _ = c.Redirect(http.StatusMovedPermanently, matches[1]+"/"+"index.html") case "index.html": _ = index.Execute(c.Response().Writer, config) case "doc.json": doc, err := swag.ReadDoc(config.InstanceName) if err != nil { c.Error(err) return nil } _, _ = c.Response().Writer.Write([]byte(doc)) case "doc.yaml": jsonString, err := swag.ReadDoc(config.InstanceName) if err != nil { c.Error(err) return nil } doc, err := yaml.JSONToYAML([]byte(jsonString)) if err != nil { c.Error(err) return nil } _, _ = c.Response().Writer.Write(doc) default: c.Request().URL.Path = matches[2] http.FileServer(http.FS(swaggerFiles.FS)).ServeHTTP(c.Response(), c.Request()) } return nil } } const indexTemplate = ` Swagger UI
`