├── .gitignore ├── v3 ├── static │ ├── swagger-ui.js.gz │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── swagger-ui.css.gz │ ├── oauth2-redirect.html.gz │ ├── swagger-ui-bundle.js.gz │ ├── swagger-ui-standalone-preset.js.gz │ └── embed.go ├── cdn.go ├── embedded.go ├── gen │ └── gen.go └── handler.go ├── v4 ├── static │ ├── swagger-ui.js.gz │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── swagger-ui.css.gz │ ├── oauth2-redirect.html.gz │ ├── swagger-ui-bundle.js.gz │ ├── swagger-ui-standalone-preset.js.gz │ └── embed.go ├── cdn.go ├── embedded.go ├── gen │ └── gen.go └── handler.go ├── v5 ├── static │ ├── swagger-ui.js.gz │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── swagger-ui.css.gz │ ├── oauth2-redirect.html.gz │ ├── swagger-ui-bundle.js.gz │ ├── swagger-ui-standalone-preset.js.gz │ └── embed.go ├── cdn.go ├── embedded.go ├── gen │ └── gen.go └── handler.go ├── dev_test.go ├── v4cdn ├── cdn.go └── handler.go ├── v5cdn ├── cdn.go └── handler.go ├── .github ├── ISSUE_TEMPLATE │ ├── feature_request.md │ ├── question.md │ └── bug_report.md └── workflows │ ├── gorelease.yml │ ├── cloc.yml │ ├── golangci-lint.yml │ └── release-assets.yml ├── v3emb ├── cdn.go ├── embedded.go └── handler.go ├── v4emb ├── cdn.go ├── embedded.go └── handler.go ├── v5emb ├── cdn.go ├── embedded.go └── handler.go ├── doc.go ├── v3cdn ├── cdn.go └── handler.go ├── go.mod ├── config.go ├── .golangci.yml ├── internal ├── handler.go └── index.tpl.go ├── README.md ├── cmd └── swgui │ └── swgui.go ├── Makefile ├── go.sum ├── LICENSE └── swagger.json /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | /*.coverprofile 3 | /.vscode 4 | /bench-*.txt 5 | /vendor 6 | -------------------------------------------------------------------------------- /v3/static/swagger-ui.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swaggest/swgui/HEAD/v3/static/swagger-ui.js.gz -------------------------------------------------------------------------------- /v4/static/swagger-ui.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swaggest/swgui/HEAD/v4/static/swagger-ui.js.gz -------------------------------------------------------------------------------- /v5/static/swagger-ui.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swaggest/swgui/HEAD/v5/static/swagger-ui.js.gz -------------------------------------------------------------------------------- /v3/static/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swaggest/swgui/HEAD/v3/static/favicon-16x16.png -------------------------------------------------------------------------------- /v3/static/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swaggest/swgui/HEAD/v3/static/favicon-32x32.png -------------------------------------------------------------------------------- /v3/static/swagger-ui.css.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swaggest/swgui/HEAD/v3/static/swagger-ui.css.gz -------------------------------------------------------------------------------- /v4/static/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swaggest/swgui/HEAD/v4/static/favicon-16x16.png -------------------------------------------------------------------------------- /v4/static/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swaggest/swgui/HEAD/v4/static/favicon-32x32.png -------------------------------------------------------------------------------- /v4/static/swagger-ui.css.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swaggest/swgui/HEAD/v4/static/swagger-ui.css.gz -------------------------------------------------------------------------------- /v5/static/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swaggest/swgui/HEAD/v5/static/favicon-16x16.png -------------------------------------------------------------------------------- /v5/static/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swaggest/swgui/HEAD/v5/static/favicon-32x32.png -------------------------------------------------------------------------------- /v5/static/swagger-ui.css.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swaggest/swgui/HEAD/v5/static/swagger-ui.css.gz -------------------------------------------------------------------------------- /dev_test.go: -------------------------------------------------------------------------------- 1 | package swgui_test 2 | 3 | import _ "github.com/bool64/dev" // Include CI/Dev scripts to project. 4 | -------------------------------------------------------------------------------- /v3/static/oauth2-redirect.html.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swaggest/swgui/HEAD/v3/static/oauth2-redirect.html.gz -------------------------------------------------------------------------------- /v3/static/swagger-ui-bundle.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swaggest/swgui/HEAD/v3/static/swagger-ui-bundle.js.gz -------------------------------------------------------------------------------- /v4/static/oauth2-redirect.html.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swaggest/swgui/HEAD/v4/static/oauth2-redirect.html.gz -------------------------------------------------------------------------------- /v4/static/swagger-ui-bundle.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swaggest/swgui/HEAD/v4/static/swagger-ui-bundle.js.gz -------------------------------------------------------------------------------- /v5/static/oauth2-redirect.html.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swaggest/swgui/HEAD/v5/static/oauth2-redirect.html.gz -------------------------------------------------------------------------------- /v5/static/swagger-ui-bundle.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swaggest/swgui/HEAD/v5/static/swagger-ui-bundle.js.gz -------------------------------------------------------------------------------- /v3/static/swagger-ui-standalone-preset.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swaggest/swgui/HEAD/v3/static/swagger-ui-standalone-preset.js.gz -------------------------------------------------------------------------------- /v4/static/swagger-ui-standalone-preset.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swaggest/swgui/HEAD/v4/static/swagger-ui-standalone-preset.js.gz -------------------------------------------------------------------------------- /v5/static/swagger-ui-standalone-preset.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swaggest/swgui/HEAD/v5/static/swagger-ui-standalone-preset.js.gz -------------------------------------------------------------------------------- /v3/static/embed.go: -------------------------------------------------------------------------------- 1 | //go:build go1.16 2 | // +build go1.16 3 | 4 | // Package static contains files to embed. 5 | package static 6 | 7 | import ( 8 | "embed" 9 | ) 10 | 11 | // FS holds embedded assets. 12 | // 13 | //go:embed *.png *.gz 14 | var FS embed.FS 15 | -------------------------------------------------------------------------------- /v4/static/embed.go: -------------------------------------------------------------------------------- 1 | //go:build go1.16 2 | // +build go1.16 3 | 4 | // Package static contains files to embed. 5 | package static 6 | 7 | import ( 8 | "embed" 9 | ) 10 | 11 | // FS holds embedded static assets. 12 | // 13 | //go:embed *.png *.gz 14 | var FS embed.FS 15 | -------------------------------------------------------------------------------- /v5/static/embed.go: -------------------------------------------------------------------------------- 1 | //go:build go1.16 2 | // +build go1.16 3 | 4 | // Package static contains files to embed. 5 | package static 6 | 7 | import ( 8 | "embed" 9 | ) 10 | 11 | // FS holds embedded static assets. 12 | // 13 | //go:embed *.png *.gz 14 | var FS embed.FS 15 | -------------------------------------------------------------------------------- /v4cdn/cdn.go: -------------------------------------------------------------------------------- 1 | package v4cdn 2 | 3 | const ( 4 | // AssetsBase is a base URL for the assets. 5 | AssetsBase = "https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/4.18.3/" 6 | 7 | // FaviconBase is a base URL for favicons. 8 | FaviconBase = "https://petstore.swagger.io/" 9 | ) 10 | -------------------------------------------------------------------------------- /v5cdn/cdn.go: -------------------------------------------------------------------------------- 1 | package v5cdn 2 | 3 | const ( 4 | // AssetsBase is a base URL for the assets. 5 | AssetsBase = "https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/5.29.1/" 6 | 7 | // FaviconBase is a base URL for favicons. 8 | FaviconBase = "https://petstore.swagger.io/" 9 | ) 10 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | Please use discussions https://github.com/swaggest/swgui/discussions/categories/ideas to share feature ideas. 11 | -------------------------------------------------------------------------------- /v3/cdn.go: -------------------------------------------------------------------------------- 1 | //go:build swguicdn 2 | // +build swguicdn 3 | 4 | package v3 5 | 6 | import ( 7 | "net/http" 8 | 9 | "github.com/swaggest/swgui/v3cdn" 10 | ) 11 | 12 | var staticServer http.Handler 13 | 14 | const ( 15 | assetsBase = v3cdn.AssetsBase 16 | faviconBase = v3cdn.FaviconBase 17 | ) 18 | -------------------------------------------------------------------------------- /v4/cdn.go: -------------------------------------------------------------------------------- 1 | //go:build swguicdn 2 | // +build swguicdn 3 | 4 | package v4 5 | 6 | import ( 7 | "net/http" 8 | 9 | "github.com/swaggest/swgui/v4cdn" 10 | ) 11 | 12 | var staticServer http.Handler 13 | 14 | const ( 15 | assetsBase = v4cdn.AssetsBase 16 | faviconBase = v4cdn.FaviconBase 17 | ) 18 | -------------------------------------------------------------------------------- /v5/cdn.go: -------------------------------------------------------------------------------- 1 | //go:build swguicdn 2 | // +build swguicdn 3 | 4 | package v5 5 | 6 | import ( 7 | "net/http" 8 | 9 | "github.com/swaggest/swgui/v5cdn" 10 | ) 11 | 12 | var staticServer http.Handler 13 | 14 | const ( 15 | assetsBase = v5cdn.AssetsBase 16 | faviconBase = v5cdn.FaviconBase 17 | ) 18 | -------------------------------------------------------------------------------- /v3emb/cdn.go: -------------------------------------------------------------------------------- 1 | //go:build swguicdn 2 | // +build swguicdn 3 | 4 | package v3emb 5 | 6 | import ( 7 | "net/http" 8 | 9 | "github.com/swaggest/swgui/v3cdn" 10 | ) 11 | 12 | var staticServer http.Handler 13 | 14 | const ( 15 | assetsBase = v3cdn.AssetsBase 16 | faviconBase = v3cdn.FaviconBase 17 | ) 18 | -------------------------------------------------------------------------------- /v4emb/cdn.go: -------------------------------------------------------------------------------- 1 | //go:build swguicdn 2 | // +build swguicdn 3 | 4 | package v4emb 5 | 6 | import ( 7 | "net/http" 8 | 9 | "github.com/swaggest/swgui/v4cdn" 10 | ) 11 | 12 | var staticServer http.Handler 13 | 14 | const ( 15 | assetsBase = v4cdn.AssetsBase 16 | faviconBase = v4cdn.FaviconBase 17 | ) 18 | -------------------------------------------------------------------------------- /v5emb/cdn.go: -------------------------------------------------------------------------------- 1 | //go:build swguicdn 2 | // +build swguicdn 3 | 4 | package v5emb 5 | 6 | import ( 7 | "net/http" 8 | 9 | "github.com/swaggest/swgui/v5cdn" 10 | ) 11 | 12 | var staticServer http.Handler 13 | 14 | const ( 15 | assetsBase = v5cdn.AssetsBase 16 | faviconBase = v5cdn.FaviconBase 17 | ) 18 | -------------------------------------------------------------------------------- /v3/embedded.go: -------------------------------------------------------------------------------- 1 | //go:build !swguicdn 2 | // +build !swguicdn 3 | 4 | package v3 5 | 6 | import "github.com/shurcooL/httpgzip" 7 | 8 | var staticServer = httpgzip.FileServer(assets, httpgzip.FileServerOptions{}) 9 | 10 | const ( 11 | assetsBase = "{{ .BasePath }}" 12 | faviconBase = "{{ .BasePath }}" 13 | ) 14 | -------------------------------------------------------------------------------- /v4/embedded.go: -------------------------------------------------------------------------------- 1 | //go:build !swguicdn 2 | // +build !swguicdn 3 | 4 | package v4 5 | 6 | import "github.com/shurcooL/httpgzip" 7 | 8 | var staticServer = httpgzip.FileServer(assets, httpgzip.FileServerOptions{}) 9 | 10 | const ( 11 | assetsBase = "{{ .BasePath }}" 12 | faviconBase = "{{ .BasePath }}" 13 | ) 14 | -------------------------------------------------------------------------------- /v5/embedded.go: -------------------------------------------------------------------------------- 1 | //go:build !swguicdn 2 | // +build !swguicdn 3 | 4 | package v5 5 | 6 | import "github.com/shurcooL/httpgzip" 7 | 8 | var staticServer = httpgzip.FileServer(assets, httpgzip.FileServerOptions{}) 9 | 10 | const ( 11 | assetsBase = "{{ .BasePath }}" 12 | faviconBase = "{{ .BasePath }}" 13 | ) 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question 3 | about: Any question about features or usage 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | Please use discussions https://github.com/swaggest/swgui/discussions/categories/q-a to make your question more discoverable by other folks. 11 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | // Package swgui provide a http FileSystem handler for swagger UI interface 2 | // 3 | // How to generate asset files: 4 | // 5 | // 1. Install tools: 6 | // 7 | // go get -u github.com/shurcooL/vfsgen 8 | // 9 | // 2. Generate file: 10 | // 11 | // At root folder, run command: 12 | // 13 | // go generate 14 | package swgui 15 | -------------------------------------------------------------------------------- /v3cdn/cdn.go: -------------------------------------------------------------------------------- 1 | // Package v3cdn provides Swagger UI v3 via CDN. 2 | package v3cdn 3 | 4 | const ( 5 | // AssetsBase is a base URL for the assets. 6 | AssetsBase = "https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/3.52.4/" 7 | 8 | // FaviconBase is a base URL for favicons. 9 | FaviconBase = "https://petstore.swagger.io/" 10 | ) 11 | -------------------------------------------------------------------------------- /v3emb/embedded.go: -------------------------------------------------------------------------------- 1 | //go:build go1.16 && !swguicdn 2 | // +build go1.16,!swguicdn 3 | 4 | package v3emb 5 | 6 | import ( 7 | "github.com/swaggest/swgui/v3/static" 8 | "github.com/vearutop/statigz" 9 | ) 10 | 11 | var staticServer = statigz.FileServer(static.FS) 12 | 13 | const ( 14 | assetsBase = "{{ .BasePath }}" 15 | faviconBase = "{{ .BasePath }}" 16 | ) 17 | -------------------------------------------------------------------------------- /v4emb/embedded.go: -------------------------------------------------------------------------------- 1 | //go:build go1.16 && !swguicdn 2 | // +build go1.16,!swguicdn 3 | 4 | package v4emb 5 | 6 | import ( 7 | "github.com/swaggest/swgui/v4/static" 8 | "github.com/vearutop/statigz" 9 | ) 10 | 11 | var staticServer = statigz.FileServer(static.FS) 12 | 13 | const ( 14 | assetsBase = "{{ .BasePath }}" 15 | faviconBase = "{{ .BasePath }}" 16 | ) 17 | -------------------------------------------------------------------------------- /v5emb/embedded.go: -------------------------------------------------------------------------------- 1 | //go:build go1.16 && !swguicdn 2 | // +build go1.16,!swguicdn 3 | 4 | package v5emb 5 | 6 | import ( 7 | "github.com/swaggest/swgui/v5/static" 8 | "github.com/vearutop/statigz" 9 | ) 10 | 11 | var staticServer = statigz.FileServer(static.FS) 12 | 13 | const ( 14 | assetsBase = "{{ .BasePath }}" 15 | faviconBase = "{{ .BasePath }}" 16 | ) 17 | -------------------------------------------------------------------------------- /v3/gen/gen.go: -------------------------------------------------------------------------------- 1 | // Package main generates legacy assets. 2 | package main 3 | 4 | import ( 5 | "log" 6 | "net/http" 7 | 8 | "github.com/shurcooL/vfsgen" 9 | ) 10 | 11 | func main() { 12 | var fs http.FileSystem = http.Dir("./v3/static") 13 | 14 | err := vfsgen.Generate(fs, vfsgen.Options{ 15 | BuildTags: "!swguicdn", 16 | PackageName: "v3", 17 | Filename: "v3/static.go", 18 | }) 19 | if err != nil { 20 | log.Fatalln(err) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /v4/gen/gen.go: -------------------------------------------------------------------------------- 1 | // Package main generates legacy static assets. 2 | package main 3 | 4 | import ( 5 | "log" 6 | "net/http" 7 | 8 | "github.com/shurcooL/vfsgen" 9 | ) 10 | 11 | func main() { 12 | var fs http.FileSystem = http.Dir("./v4/static") 13 | 14 | err := vfsgen.Generate(fs, vfsgen.Options{ 15 | BuildTags: "!swguicdn", 16 | PackageName: "v4", 17 | Filename: "v4/static.go", 18 | }) 19 | if err != nil { 20 | log.Fatalln(err) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /v5/gen/gen.go: -------------------------------------------------------------------------------- 1 | // Package main generates legacy static assets. 2 | package main 3 | 4 | import ( 5 | "log" 6 | "net/http" 7 | 8 | "github.com/shurcooL/vfsgen" 9 | ) 10 | 11 | func main() { 12 | var fs http.FileSystem = http.Dir("./v5/static") 13 | 14 | err := vfsgen.Generate(fs, vfsgen.Options{ 15 | BuildTags: "!swguicdn", 16 | PackageName: "v5", 17 | Filename: "v5/static.go", 18 | }) 19 | if err != nil { 20 | log.Fatalln(err) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/swaggest/swgui 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/bool64/dev v0.2.43 7 | github.com/shurcooL/httpgzip v0.0.0-20190720172056-320755c1c1b0 8 | github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 9 | github.com/vearutop/statigz v1.4.0 10 | ) 11 | 12 | require ( 13 | github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect 14 | golang.org/x/net v0.8.0 // indirect 15 | golang.org/x/text v0.8.0 // indirect 16 | ) 17 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | If feasible/relevant, please provide a code snippet (inline or with Go playground) to reproduce the issue. 15 | 16 | 17 | **Expected behavior** 18 | A clear and concise description of what you expected to happen. 19 | 20 | **Additional context** 21 | Add any other context about the problem here. 22 | -------------------------------------------------------------------------------- /v3cdn/handler.go: -------------------------------------------------------------------------------- 1 | package v3cdn 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/swaggest/swgui" 7 | "github.com/swaggest/swgui/internal" 8 | ) 9 | 10 | // Handler handle swagger UI request. 11 | type Handler = internal.Handler 12 | 13 | // NewWithConfig creates configurable handler constructor. 14 | func NewWithConfig(config swgui.Config) func(title, swaggerJSONPath string, basePath string) http.Handler { 15 | return func(title, swaggerJSONPath string, basePath string) http.Handler { 16 | if config.Title == "" { 17 | config.Title = title 18 | } 19 | 20 | if config.SwaggerJSON == "" { 21 | config.SwaggerJSON = swaggerJSONPath 22 | } 23 | 24 | if config.BasePath == "" { 25 | config.BasePath = basePath 26 | } 27 | 28 | return NewHandlerWithConfig(config) 29 | } 30 | } 31 | 32 | // New creates HTTP handler for Swagger UI. 33 | func New(title, swaggerJSONPath string, basePath string) http.Handler { 34 | return NewHandler(title, swaggerJSONPath, basePath) 35 | } 36 | 37 | // NewHandler creates HTTP handler for Swagger UI. 38 | func NewHandler(title, swaggerJSONPath string, basePath string) *Handler { 39 | return NewHandlerWithConfig(swgui.Config{ 40 | Title: title, 41 | SwaggerJSON: swaggerJSONPath, 42 | BasePath: basePath, 43 | }) 44 | } 45 | 46 | // NewHandlerWithConfig creates HTTP handler for Swagger UI. 47 | func NewHandlerWithConfig(config swgui.Config) *Handler { 48 | return internal.NewHandlerWithConfig(config, AssetsBase, FaviconBase, nil) 49 | } 50 | -------------------------------------------------------------------------------- /.github/workflows/gorelease.yml: -------------------------------------------------------------------------------- 1 | # This script is provided by github.com/bool64/dev. 2 | name: gorelease 3 | on: 4 | pull_request: 5 | 6 | # Cancel the workflow in progress in newer build is about to start. 7 | concurrency: 8 | group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} 9 | cancel-in-progress: true 10 | 11 | env: 12 | GO_VERSION: stable 13 | jobs: 14 | gorelease: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Install Go 18 | uses: actions/setup-go@v5 19 | with: 20 | go-version: ${{ env.GO_VERSION }} 21 | - name: Checkout code 22 | uses: actions/checkout@v4 23 | - name: Gorelease cache 24 | uses: actions/cache@v4 25 | with: 26 | path: | 27 | ~/go/bin/gorelease 28 | key: ${{ runner.os }}-gorelease-generic 29 | - name: Gorelease 30 | id: gorelease 31 | run: | 32 | test -e ~/go/bin/gorelease || go install golang.org/x/exp/cmd/gorelease@latest 33 | OUTPUT=$(gorelease 2>&1 || exit 0) 34 | echo "${OUTPUT}" 35 | echo "report<> $GITHUB_OUTPUT && echo "$OUTPUT" >> $GITHUB_OUTPUT && echo "EOF" >> $GITHUB_OUTPUT 36 | - name: Comment report 37 | continue-on-error: true 38 | uses: marocchino/sticky-pull-request-comment@v2 39 | with: 40 | header: gorelease 41 | message: | 42 | ### Go API Changes 43 | 44 |
45 |             ${{ steps.gorelease.outputs.report }}
46 |             
-------------------------------------------------------------------------------- /v4/handler.go: -------------------------------------------------------------------------------- 1 | // Package v4 provides Swagger UI v4 assets. 2 | package v4 3 | 4 | import ( 5 | "net/http" 6 | 7 | "github.com/swaggest/swgui" 8 | "github.com/swaggest/swgui/internal" 9 | ) 10 | 11 | // Handler handles swagger UI request. 12 | type Handler = internal.Handler 13 | 14 | // NewWithConfig creates configurable handler constructor. 15 | func NewWithConfig(config swgui.Config) func(title, swaggerJSONPath string, basePath string) http.Handler { 16 | return func(title, swaggerJSONPath string, basePath string) http.Handler { 17 | if config.Title == "" { 18 | config.Title = title 19 | } 20 | 21 | if config.SwaggerJSON == "" { 22 | config.SwaggerJSON = swaggerJSONPath 23 | } 24 | 25 | if config.BasePath == "" { 26 | config.BasePath = basePath 27 | } 28 | 29 | return NewHandlerWithConfig(config) 30 | } 31 | } 32 | 33 | // New creates HTTP handler for Swagger UI. 34 | func New(title, swaggerJSONPath string, basePath string) http.Handler { 35 | return NewHandler(title, swaggerJSONPath, basePath) 36 | } 37 | 38 | // NewHandler creates HTTP handler for Swagger UI. 39 | func NewHandler(title, swaggerJSONPath string, basePath string) *Handler { 40 | return NewHandlerWithConfig(swgui.Config{ 41 | Title: title, 42 | SwaggerJSON: swaggerJSONPath, 43 | BasePath: basePath, 44 | }) 45 | } 46 | 47 | // NewHandlerWithConfig creates HTTP handler for Swagger UI. 48 | func NewHandlerWithConfig(config swgui.Config) *Handler { 49 | return internal.NewHandlerWithConfig(config, assetsBase, faviconBase, staticServer) 50 | } 51 | -------------------------------------------------------------------------------- /v4cdn/handler.go: -------------------------------------------------------------------------------- 1 | // Package v4cdn provides Swagger UI v4 via CDN. 2 | package v4cdn 3 | 4 | import ( 5 | "net/http" 6 | 7 | "github.com/swaggest/swgui" 8 | "github.com/swaggest/swgui/internal" 9 | ) 10 | 11 | // Handler handle swagger UI request. 12 | type Handler = internal.Handler 13 | 14 | // NewWithConfig creates configurable handler constructor. 15 | func NewWithConfig(config swgui.Config) func(title, swaggerJSONPath string, basePath string) http.Handler { 16 | return func(title, swaggerJSONPath string, basePath string) http.Handler { 17 | if config.Title == "" { 18 | config.Title = title 19 | } 20 | 21 | if config.SwaggerJSON == "" { 22 | config.SwaggerJSON = swaggerJSONPath 23 | } 24 | 25 | if config.BasePath == "" { 26 | config.BasePath = basePath 27 | } 28 | 29 | return NewHandlerWithConfig(config) 30 | } 31 | } 32 | 33 | // New creates HTTP handler for Swagger UI. 34 | func New(title, swaggerJSONPath string, basePath string) http.Handler { 35 | return NewHandler(title, swaggerJSONPath, basePath) 36 | } 37 | 38 | // NewHandler creates HTTP handler for Swagger UI. 39 | func NewHandler(title, swaggerJSONPath string, basePath string) *Handler { 40 | return NewHandlerWithConfig(swgui.Config{ 41 | Title: title, 42 | SwaggerJSON: swaggerJSONPath, 43 | BasePath: basePath, 44 | }) 45 | } 46 | 47 | // NewHandlerWithConfig creates HTTP handler for Swagger UI. 48 | func NewHandlerWithConfig(config swgui.Config) *Handler { 49 | return internal.NewHandlerWithConfig(config, AssetsBase, FaviconBase, nil) 50 | } 51 | -------------------------------------------------------------------------------- /v5/handler.go: -------------------------------------------------------------------------------- 1 | // Package v5 provides Swagger UI v5 assets. 2 | package v5 3 | 4 | import ( 5 | "net/http" 6 | 7 | "github.com/swaggest/swgui" 8 | "github.com/swaggest/swgui/internal" 9 | ) 10 | 11 | // Handler handles swagger UI request. 12 | type Handler = internal.Handler 13 | 14 | // NewWithConfig creates configurable handler constructor. 15 | func NewWithConfig(config swgui.Config) func(title, swaggerJSONPath string, basePath string) http.Handler { 16 | return func(title, swaggerJSONPath string, basePath string) http.Handler { 17 | if config.Title == "" { 18 | config.Title = title 19 | } 20 | 21 | if config.SwaggerJSON == "" { 22 | config.SwaggerJSON = swaggerJSONPath 23 | } 24 | 25 | if config.BasePath == "" { 26 | config.BasePath = basePath 27 | } 28 | 29 | return NewHandlerWithConfig(config) 30 | } 31 | } 32 | 33 | // New creates HTTP handler for Swagger UI. 34 | func New(title, swaggerJSONPath string, basePath string) http.Handler { 35 | return NewHandler(title, swaggerJSONPath, basePath) 36 | } 37 | 38 | // NewHandler creates HTTP handler for Swagger UI. 39 | func NewHandler(title, swaggerJSONPath string, basePath string) *Handler { 40 | return NewHandlerWithConfig(swgui.Config{ 41 | Title: title, 42 | SwaggerJSON: swaggerJSONPath, 43 | BasePath: basePath, 44 | }) 45 | } 46 | 47 | // NewHandlerWithConfig creates HTTP handler for Swagger UI. 48 | func NewHandlerWithConfig(config swgui.Config) *Handler { 49 | return internal.NewHandlerWithConfig(config, assetsBase, faviconBase, staticServer) 50 | } 51 | -------------------------------------------------------------------------------- /v5cdn/handler.go: -------------------------------------------------------------------------------- 1 | // Package v5cdn provides Swagger UI v5 via CDN. 2 | package v5cdn 3 | 4 | import ( 5 | "net/http" 6 | 7 | "github.com/swaggest/swgui" 8 | "github.com/swaggest/swgui/internal" 9 | ) 10 | 11 | // Handler handle swagger UI request. 12 | type Handler = internal.Handler 13 | 14 | // NewWithConfig creates configurable handler constructor. 15 | func NewWithConfig(config swgui.Config) func(title, swaggerJSONPath string, basePath string) http.Handler { 16 | return func(title, swaggerJSONPath string, basePath string) http.Handler { 17 | if config.Title == "" { 18 | config.Title = title 19 | } 20 | 21 | if config.SwaggerJSON == "" { 22 | config.SwaggerJSON = swaggerJSONPath 23 | } 24 | 25 | if config.BasePath == "" { 26 | config.BasePath = basePath 27 | } 28 | 29 | return NewHandlerWithConfig(config) 30 | } 31 | } 32 | 33 | // New creates HTTP handler for Swagger UI. 34 | func New(title, swaggerJSONPath string, basePath string) http.Handler { 35 | return NewHandler(title, swaggerJSONPath, basePath) 36 | } 37 | 38 | // NewHandler creates HTTP handler for Swagger UI. 39 | func NewHandler(title, swaggerJSONPath string, basePath string) *Handler { 40 | return NewHandlerWithConfig(swgui.Config{ 41 | Title: title, 42 | SwaggerJSON: swaggerJSONPath, 43 | BasePath: basePath, 44 | }) 45 | } 46 | 47 | // NewHandlerWithConfig creates HTTP handler for Swagger UI. 48 | func NewHandlerWithConfig(config swgui.Config) *Handler { 49 | return internal.NewHandlerWithConfig(config, AssetsBase, FaviconBase, nil) 50 | } 51 | -------------------------------------------------------------------------------- /v3/handler.go: -------------------------------------------------------------------------------- 1 | // Package v3 provides embedded Swagger UI v3 assets. 2 | package v3 3 | 4 | import ( 5 | "net/http" 6 | 7 | "github.com/swaggest/swgui" 8 | "github.com/swaggest/swgui/internal" 9 | ) 10 | 11 | // Handler handles swagger UI request. 12 | type Handler = internal.Handler 13 | 14 | // New creates HTTP handler for Swagger UI. 15 | func New(title, swaggerJSONPath string, basePath string) http.Handler { 16 | return NewHandler(title, swaggerJSONPath, basePath) 17 | } 18 | 19 | // NewWithConfig creates configurable handler constructor. 20 | func NewWithConfig(config swgui.Config) func(title, swaggerJSONPath string, basePath string) http.Handler { 21 | return func(title, swaggerJSONPath string, basePath string) http.Handler { 22 | if config.Title == "" { 23 | config.Title = title 24 | } 25 | 26 | if config.SwaggerJSON == "" { 27 | config.SwaggerJSON = swaggerJSONPath 28 | } 29 | 30 | if config.BasePath == "" { 31 | config.BasePath = basePath 32 | } 33 | 34 | return NewHandlerWithConfig(config) 35 | } 36 | } 37 | 38 | // NewHandler creates HTTP handler for Swagger UI. 39 | func NewHandler(title, swaggerJSONPath string, basePath string) *Handler { 40 | return NewHandlerWithConfig(swgui.Config{ 41 | Title: title, 42 | SwaggerJSON: swaggerJSONPath, 43 | BasePath: basePath, 44 | }) 45 | } 46 | 47 | // NewHandlerWithConfig returns a HTTP handler for swagger UI. 48 | func NewHandlerWithConfig(config swgui.Config) *Handler { 49 | return internal.NewHandlerWithConfig(config, assetsBase, faviconBase, staticServer) 50 | } 51 | -------------------------------------------------------------------------------- /v3emb/handler.go: -------------------------------------------------------------------------------- 1 | // Package v3emb provides Swagger UI v3 with Go embed. 2 | package v3emb 3 | 4 | import ( 5 | "net/http" 6 | 7 | "github.com/swaggest/swgui" 8 | "github.com/swaggest/swgui/internal" 9 | ) 10 | 11 | // Handler handles swagger UI request. 12 | type Handler = internal.Handler 13 | 14 | // NewWithConfig creates configurable handler constructor. 15 | func NewWithConfig(config swgui.Config) func(title, swaggerJSONPath string, basePath string) http.Handler { 16 | return func(title, swaggerJSONPath string, basePath string) http.Handler { 17 | if config.Title == "" { 18 | config.Title = title 19 | } 20 | 21 | if config.SwaggerJSON == "" { 22 | config.SwaggerJSON = swaggerJSONPath 23 | } 24 | 25 | if config.BasePath == "" { 26 | config.BasePath = basePath 27 | } 28 | 29 | return NewHandlerWithConfig(config) 30 | } 31 | } 32 | 33 | // New creates HTTP handler for Swagger UI. 34 | func New(title, swaggerJSONPath string, basePath string) http.Handler { 35 | return NewHandler(title, swaggerJSONPath, basePath) 36 | } 37 | 38 | // NewHandler creates HTTP handler for Swagger UI. 39 | func NewHandler(title, swaggerJSONPath string, basePath string) *Handler { 40 | return NewHandlerWithConfig(swgui.Config{ 41 | Title: title, 42 | SwaggerJSON: swaggerJSONPath, 43 | BasePath: basePath, 44 | }) 45 | } 46 | 47 | // NewHandlerWithConfig creates HTTP handler for Swagger UI. 48 | func NewHandlerWithConfig(config swgui.Config) *Handler { 49 | return internal.NewHandlerWithConfig(config, assetsBase, faviconBase, staticServer) 50 | } 51 | -------------------------------------------------------------------------------- /v4emb/handler.go: -------------------------------------------------------------------------------- 1 | // Package v4emb provides Swagger UI v4 with Go embed. 2 | package v4emb 3 | 4 | import ( 5 | "net/http" 6 | 7 | "github.com/swaggest/swgui" 8 | "github.com/swaggest/swgui/internal" 9 | ) 10 | 11 | // Handler handles swagger UI request. 12 | type Handler = internal.Handler 13 | 14 | // NewWithConfig creates configurable handler constructor. 15 | func NewWithConfig(config swgui.Config) func(title, swaggerJSONPath string, basePath string) http.Handler { 16 | return func(title, swaggerJSONPath string, basePath string) http.Handler { 17 | if config.Title == "" { 18 | config.Title = title 19 | } 20 | 21 | if config.SwaggerJSON == "" { 22 | config.SwaggerJSON = swaggerJSONPath 23 | } 24 | 25 | if config.BasePath == "" { 26 | config.BasePath = basePath 27 | } 28 | 29 | return NewHandlerWithConfig(config) 30 | } 31 | } 32 | 33 | // New creates HTTP handler for Swagger UI. 34 | func New(title, swaggerJSONPath string, basePath string) http.Handler { 35 | return NewHandler(title, swaggerJSONPath, basePath) 36 | } 37 | 38 | // NewHandler creates HTTP handler for Swagger UI. 39 | func NewHandler(title, swaggerJSONPath string, basePath string) *Handler { 40 | return NewHandlerWithConfig(swgui.Config{ 41 | Title: title, 42 | SwaggerJSON: swaggerJSONPath, 43 | BasePath: basePath, 44 | }) 45 | } 46 | 47 | // NewHandlerWithConfig creates HTTP handler for Swagger UI. 48 | func NewHandlerWithConfig(config swgui.Config) *Handler { 49 | return internal.NewHandlerWithConfig(config, assetsBase, faviconBase, staticServer) 50 | } 51 | -------------------------------------------------------------------------------- /v5emb/handler.go: -------------------------------------------------------------------------------- 1 | // Package v5emb provides Swagger UI v4 with Go embed. 2 | package v5emb 3 | 4 | import ( 5 | "net/http" 6 | 7 | "github.com/swaggest/swgui" 8 | "github.com/swaggest/swgui/internal" 9 | ) 10 | 11 | // Handler handles swagger UI request. 12 | type Handler = internal.Handler 13 | 14 | // NewWithConfig creates configurable handler constructor. 15 | func NewWithConfig(config swgui.Config) func(title, swaggerJSONPath string, basePath string) http.Handler { 16 | return func(title, swaggerJSONPath string, basePath string) http.Handler { 17 | if config.Title == "" { 18 | config.Title = title 19 | } 20 | 21 | if config.SwaggerJSON == "" { 22 | config.SwaggerJSON = swaggerJSONPath 23 | } 24 | 25 | if config.BasePath == "" { 26 | config.BasePath = basePath 27 | } 28 | 29 | return NewHandlerWithConfig(config) 30 | } 31 | } 32 | 33 | // New creates HTTP handler for Swagger UI. 34 | func New(title, swaggerJSONPath string, basePath string) http.Handler { 35 | return NewHandler(title, swaggerJSONPath, basePath) 36 | } 37 | 38 | // NewHandler creates HTTP handler for Swagger UI. 39 | func NewHandler(title, swaggerJSONPath string, basePath string) *Handler { 40 | return NewHandlerWithConfig(swgui.Config{ 41 | Title: title, 42 | SwaggerJSON: swaggerJSONPath, 43 | BasePath: basePath, 44 | }) 45 | } 46 | 47 | // NewHandlerWithConfig creates HTTP handler for Swagger UI. 48 | func NewHandlerWithConfig(config swgui.Config) *Handler { 49 | return internal.NewHandlerWithConfig(config, assetsBase, faviconBase, staticServer) 50 | } 51 | -------------------------------------------------------------------------------- /config.go: -------------------------------------------------------------------------------- 1 | package swgui 2 | 3 | import "html/template" 4 | 5 | // Config is used for Swagger UI handler configuration. 6 | type Config struct { 7 | Title string `json:"title"` // Title of index file. 8 | SwaggerJSON string `json:"swaggerJsonUrl"` // URL to openapi.json/swagger.json document specification. 9 | BasePath string `json:"basePath"` // Base URL to docs. 10 | 11 | // InternalBasePath is used to override BasePath if external 12 | // url differs from internal one. 13 | InternalBasePath string `json:"-"` 14 | 15 | ShowTopBar bool `json:"showTopBar"` // Show navigation top bar, hidden by default. 16 | HideCurl bool `json:"hideCurl"` // Hide curl code snippet. 17 | JsonEditor bool `json:"jsonEditor"` // Enable visual json editor support (experimental, can fail with complex schemas). 18 | PreAuthorizeApiKey map[string]string `json:"preAuthorizeApiKey"` // Map of security name to key value. 19 | 20 | // SettingsUI contains keys and plain javascript values of SwaggerUIBundle configuration. 21 | // Overrides default values. 22 | // See https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/ for available options. 23 | SettingsUI map[string]string `json:"-"` 24 | 25 | // Proxy enables proxying requests through swgui handler. 26 | // Can be useful if API is not directly available due to CORS policy. 27 | Proxy bool `json:"-"` 28 | 29 | AppendHead template.HTML `json:"-"` 30 | AppendHTML template.HTML `json:"-"` 31 | PrependHTML template.HTML `json:"-"` 32 | } 33 | -------------------------------------------------------------------------------- /.github/workflows/cloc.yml: -------------------------------------------------------------------------------- 1 | # This script is provided by github.com/bool64/dev. 2 | name: cloc 3 | on: 4 | pull_request: 5 | 6 | # Cancel the workflow in progress in newer build is about to start. 7 | concurrency: 8 | group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} 9 | cancel-in-progress: true 10 | 11 | jobs: 12 | cloc: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout code 16 | uses: actions/checkout@v4 17 | with: 18 | path: pr 19 | - name: Checkout base code 20 | uses: actions/checkout@v4 21 | with: 22 | ref: ${{ github.event.pull_request.base.sha }} 23 | path: base 24 | - name: Count lines of code 25 | id: loc 26 | run: | 27 | curl -sLO https://github.com/vearutop/sccdiff/releases/download/v1.0.3/linux_amd64.tar.gz && tar xf linux_amd64.tar.gz 28 | sccdiff_hash=$(git hash-object ./sccdiff) 29 | [ "$sccdiff_hash" == "ae8a07b687bd3dba60861584efe724351aa7ff63" ] || (echo "::error::unexpected hash for sccdiff, possible tampering: $sccdiff_hash" && exit 1) 30 | OUTPUT=$(cd pr && ../sccdiff -basedir ../base) 31 | echo "${OUTPUT}" 32 | echo "diff<> $GITHUB_OUTPUT && echo "$OUTPUT" >> $GITHUB_OUTPUT && echo "EOF" >> $GITHUB_OUTPUT 33 | 34 | - name: Comment lines of code 35 | continue-on-error: true 36 | uses: marocchino/sticky-pull-request-comment@v2 37 | with: 38 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 39 | header: LOC 40 | message: | 41 | ### Lines Of Code 42 | 43 | ${{ steps.loc.outputs.diff }} 44 | -------------------------------------------------------------------------------- /.github/workflows/golangci-lint.yml: -------------------------------------------------------------------------------- 1 | # This script is provided by github.com/bool64/dev. 2 | name: lint 3 | on: 4 | push: 5 | tags: 6 | - v* 7 | branches: 8 | - master 9 | - main 10 | pull_request: 11 | 12 | # Cancel the workflow in progress in newer build is about to start. 13 | concurrency: 14 | group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} 15 | cancel-in-progress: true 16 | 17 | jobs: 18 | golangci: 19 | name: golangci-lint 20 | runs-on: ubuntu-latest 21 | steps: 22 | - uses: actions/setup-go@v5 23 | with: 24 | go-version: stable 25 | - uses: actions/checkout@v4 26 | - name: golangci-lint 27 | uses: golangci/golangci-lint-action@v8.0.0 28 | with: 29 | # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. 30 | version: v2.4.0 31 | 32 | # Optional: working directory, useful for monorepos 33 | # working-directory: somedir 34 | 35 | # Optional: golangci-lint command line arguments. 36 | # args: --issues-exit-code=0 37 | 38 | # Optional: show only new issues if it's a pull request. The default value is `false`. 39 | # only-new-issues: true 40 | 41 | # Optional: if set to true then the action will use pre-installed Go. 42 | # skip-go-installation: true 43 | 44 | # Optional: if set to true then the action don't cache or restore ~/go/pkg. 45 | # skip-pkg-cache: true 46 | 47 | # Optional: if set to true then the action don't cache or restore ~/.cache/go-build. 48 | # skip-build-cache: true -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | # See https://golangci-lint.run/docs/linters/configuration/ 2 | version: "2" 3 | run: 4 | tests: true 5 | linters: 6 | default: all 7 | disable: 8 | - errcheck 9 | - funlen 10 | - noctx 11 | - revive 12 | - cyclop 13 | - err113 14 | - noinlineerr 15 | - wsl_v5 16 | - funcorder 17 | - copyloopvar 18 | - depguard 19 | - dupword 20 | - errname 21 | - exhaustruct 22 | - forbidigo 23 | - forcetypeassert 24 | - gochecknoglobals 25 | - intrange 26 | - ireturn 27 | - lll 28 | - mnd 29 | - nonamedreturns 30 | - paralleltest 31 | - recvcheck 32 | - tagalign 33 | - tagliatelle 34 | - testableexamples 35 | - testifylint 36 | - varnamelen 37 | - wrapcheck 38 | settings: 39 | dupl: 40 | threshold: 100 41 | errcheck: 42 | check-type-assertions: true 43 | check-blank: true 44 | gocyclo: 45 | min-complexity: 20 46 | misspell: 47 | locale: US 48 | unparam: 49 | check-exported: true 50 | exclusions: 51 | generated: lax 52 | rules: 53 | - linters: 54 | - gosec 55 | - dupl 56 | - funlen 57 | - goconst 58 | - mnd 59 | - noctx 60 | - unparam 61 | - unused 62 | path: _test.go 63 | - linters: 64 | - errcheck 65 | - gosec 66 | path: example_ 67 | - linters: 68 | - revive 69 | text: 'unused-parameter: parameter' 70 | paths: 71 | - third_party$ 72 | - builtin$ 73 | - examples$ 74 | formatters: 75 | enable: 76 | - gci 77 | - gofmt 78 | - gofumpt 79 | - goimports 80 | exclusions: 81 | generated: lax 82 | paths: 83 | - third_party$ 84 | - builtin$ 85 | - examples$ 86 | -------------------------------------------------------------------------------- /internal/handler.go: -------------------------------------------------------------------------------- 1 | // Package internal provides internal handler implementation. 2 | package internal 3 | 4 | import ( 5 | "encoding/json" 6 | "html/template" 7 | "io" 8 | "net/http" 9 | "strings" 10 | 11 | "github.com/swaggest/swgui" 12 | ) 13 | 14 | // Handler handles swagger UI request. 15 | type Handler struct { 16 | swgui.Config 17 | 18 | ConfigJson template.JS 19 | 20 | tpl *template.Template 21 | staticServer http.Handler 22 | } 23 | 24 | // NewHandlerWithConfig returns a HTTP handler for swagger UI. 25 | func NewHandlerWithConfig(config swgui.Config, assetsBase, faviconBase string, staticServer http.Handler) *Handler { 26 | config.BasePath = strings.TrimSuffix(config.BasePath, "/") + "/" 27 | 28 | h := &Handler{ 29 | Config: config, 30 | } 31 | 32 | if h.InternalBasePath == "" { 33 | h.InternalBasePath = h.BasePath 34 | } 35 | 36 | h.InternalBasePath = strings.TrimSuffix(h.InternalBasePath, "/") + "/" 37 | 38 | j, err := json.Marshal(h.Config) 39 | if err != nil { 40 | panic(err) 41 | } 42 | 43 | h.ConfigJson = template.JS(j) //nolint:gosec // Data is well formed. 44 | 45 | h.tpl, err = template.New("index").Parse(IndexTpl(assetsBase, faviconBase, config)) 46 | if err != nil { 47 | panic(err) 48 | } 49 | 50 | if staticServer != nil { 51 | h.staticServer = http.StripPrefix(h.InternalBasePath, staticServer) 52 | } 53 | 54 | return h 55 | } 56 | 57 | // ServeHTTP implements http.Handler interface to handle swagger UI request. 58 | func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 59 | if strings.TrimSuffix(r.URL.Path, "/") != strings.TrimSuffix(h.InternalBasePath, "/") && h.staticServer != nil { 60 | h.staticServer.ServeHTTP(w, r) 61 | 62 | return 63 | } 64 | 65 | if u := r.URL.Query().Get("proxy"); u != "" && h.Proxy { 66 | h.proxyRequest(u, w, r) 67 | 68 | return 69 | } 70 | 71 | w.Header().Set("Content-Type", "text/html") 72 | 73 | if err := h.tpl.Execute(w, h); err != nil { 74 | http.Error(w, err.Error(), http.StatusInternalServerError) 75 | } 76 | } 77 | 78 | func (h *Handler) proxyRequest(u string, w http.ResponseWriter, r *http.Request) { 79 | b := r.Body 80 | defer b.Close() 81 | 82 | req, err := http.NewRequest(r.Method, u, b) 83 | if err != nil { 84 | http.Error(w, err.Error(), http.StatusInternalServerError) 85 | 86 | return 87 | } 88 | 89 | req.Header = r.Header 90 | 91 | resp, err := http.DefaultTransport.RoundTrip(req) 92 | if err != nil { 93 | http.Error(w, err.Error(), http.StatusInternalServerError) 94 | 95 | return 96 | } 97 | defer resp.Body.Close() 98 | 99 | hd := w.Header() 100 | 101 | for k, vv := range resp.Header { 102 | for _, v := range vv { 103 | hd.Add(k, v) 104 | } 105 | } 106 | 107 | w.WriteHeader(resp.StatusCode) 108 | 109 | if _, err := io.Copy(w, resp.Body); err != nil { 110 | http.Error(w, err.Error(), http.StatusInternalServerError) 111 | 112 | return 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /.github/workflows/release-assets.yml: -------------------------------------------------------------------------------- 1 | # This script is provided by github.com/bool64/dev. 2 | 3 | # This script uploads application binaries as GitHub release assets. 4 | name: release-assets 5 | on: 6 | release: 7 | types: 8 | - created 9 | env: 10 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 11 | GO_VERSION: stable 12 | jobs: 13 | build: 14 | name: Upload Release Assets 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Install Go 18 | uses: actions/setup-go@v5 19 | with: 20 | go-version: ${{ env.GO_VERSION }} 21 | - name: Checkout code 22 | uses: actions/checkout@v4 23 | - name: Build artifacts 24 | run: | 25 | make release-assets 26 | - name: Upload linux_amd64.tar.gz 27 | if: hashFiles('linux_amd64.tar.gz') != '' 28 | uses: actions/upload-release-asset@v1 29 | with: 30 | upload_url: ${{ github.event.release.upload_url }} 31 | asset_path: ./linux_amd64.tar.gz 32 | asset_name: linux_amd64.tar.gz 33 | asset_content_type: application/tar+gzip 34 | - name: Upload linux_amd64_dbg.tar.gz 35 | if: hashFiles('linux_amd64_dbg.tar.gz') != '' 36 | uses: actions/upload-release-asset@v1 37 | with: 38 | upload_url: ${{ github.event.release.upload_url }} 39 | asset_path: ./linux_amd64_dbg.tar.gz 40 | asset_name: linux_amd64_dbg.tar.gz 41 | asset_content_type: application/tar+gzip 42 | - name: Upload linux_arm64.tar.gz 43 | if: hashFiles('linux_arm64.tar.gz') != '' 44 | uses: actions/upload-release-asset@v1 45 | with: 46 | upload_url: ${{ github.event.release.upload_url }} 47 | asset_path: ./linux_arm64.tar.gz 48 | asset_name: linux_arm64.tar.gz 49 | asset_content_type: application/tar+gzip 50 | - name: Upload linux_arm.tar.gz 51 | if: hashFiles('linux_arm.tar.gz') != '' 52 | uses: actions/upload-release-asset@v1 53 | with: 54 | upload_url: ${{ github.event.release.upload_url }} 55 | asset_path: ./linux_arm.tar.gz 56 | asset_name: linux_arm.tar.gz 57 | asset_content_type: application/tar+gzip 58 | - name: Upload darwin_amd64.tar.gz 59 | if: hashFiles('darwin_amd64.tar.gz') != '' 60 | uses: actions/upload-release-asset@v1 61 | with: 62 | upload_url: ${{ github.event.release.upload_url }} 63 | asset_path: ./darwin_amd64.tar.gz 64 | asset_name: darwin_amd64.tar.gz 65 | asset_content_type: application/tar+gzip 66 | - name: Upload darwin_arm64.tar.gz 67 | if: hashFiles('darwin_arm64.tar.gz') != '' 68 | uses: actions/upload-release-asset@v1 69 | with: 70 | upload_url: ${{ github.event.release.upload_url }} 71 | asset_path: ./darwin_arm64.tar.gz 72 | asset_name: darwin_arm64.tar.gz 73 | asset_content_type: application/tar+gzip 74 | - name: Upload windows_amd64.zip 75 | if: hashFiles('windows_amd64.zip') != '' 76 | uses: actions/upload-release-asset@v1 77 | with: 78 | upload_url: ${{ github.event.release.upload_url }} 79 | asset_path: ./windows_amd64.zip 80 | asset_name: windows_amd64.zip 81 | asset_content_type: application/zip 82 | 83 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Swagger UI 2 | 3 | [![GoDevDoc](https://img.shields.io/badge/dev-doc-00ADD8?logo=go)](https://pkg.go.dev/github.com/swaggest/swgui) 4 | 5 | Package `swgui` (Swagger UI) provides HTTP handler to serve Swagger UI. All assets are embedded in Go source code, so 6 | just build and run. 7 | 8 | ### V5 9 | 10 | Static assets for `v5` are built from Swagger 11 | UI [v5.29.1](https://github.com/swagger-api/swagger-ui/releases/tag/v5.29.1). 12 | 13 | [CDN-based](https://cdnjs.com/libraries/swagger-ui) `v5cdn` uses Swagger 14 | UI [v5.29.1](https://github.com/swagger-api/swagger-ui/releases/tag/v5.29.1). 15 | 16 | ### V4 17 | 18 | Static assets for `v4` are built from Swagger 19 | UI [v4.19.1](https://github.com/swagger-api/swagger-ui/releases/tag/v4.19.1). 20 | 21 | [CDN-based](https://cdnjs.com/libraries/swagger-ui) `v4cdn` uses Swagger 22 | UI [v4.18.3](https://github.com/swagger-api/swagger-ui/releases/tag/v4.18.3). 23 | 24 | ### V3 25 | 26 | Static assets for `v3` are built from Swagger 27 | UI [v3.52.5](https://github.com/swagger-api/swagger-ui/releases/tag/v3.52.5). 28 | 29 | [CDN-based](https://cdnjs.com/libraries/swagger-ui) `v3cdn` uses Swagger 30 | UI [v3.52.4](https://github.com/swagger-api/swagger-ui/releases/tag/v3.52.4). 31 | 32 | ## How to use 33 | 34 | ```go 35 | package main 36 | 37 | import ( 38 | "net/http" 39 | 40 | "github.com/swaggest/swgui/v5emb" 41 | ) 42 | 43 | func main() { 44 | http.Handle("/api1/docs/", v5emb.New( 45 | "Petstore", 46 | "https://petstore3.swagger.io/api/v3/openapi.json", 47 | "/api1/docs/", 48 | )) 49 | 50 | http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) { 51 | _, _ = writer.Write([]byte("Hello World!")) 52 | }) 53 | 54 | println("docs at http://localhost:8080/api1/docs/") 55 | _ = http.ListenAndServe("localhost:8080", http.DefaultServeMux) 56 | } 57 | ``` 58 | 59 | 60 | If you use `go1.16` or later, you can import natively embedded assets with `"github.com/swaggest/swgui/v5emb"`, it may 61 | help to lower application memory usage. 62 | 63 | ## Use CDN for assets 64 | 65 | In order to reduce binary size you can import `github.com/swaggest/swgui/v3cdn` to use CDN hosted assets. 66 | 67 | Also you can use `swguicdn` build tag to enable CDN mode for `github.com/swaggest/swgui/v3` import. 68 | 69 | Be aware that CDN mode may be considered inappropriate for security or networking reasons. 70 | 71 | ## Documentation viewer CLI tool 72 | 73 | Install `swgui`. 74 | 75 | ``` 76 | go install github.com/swaggest/swgui/cmd/swgui@latest 77 | ``` 78 | 79 | Or download binary from [releases](https://github.com/swaggest/swgui/releases). 80 | 81 | ### Linux AMD64 82 | 83 | ``` 84 | wget https://github.com/swaggest/swgui/releases/latest/download/linux_amd64.tar.gz && tar xf linux_amd64.tar.gz && rm linux_amd64.tar.gz 85 | ./swgui -version 86 | ``` 87 | 88 | ### Macos Intel 89 | 90 | ``` 91 | wget https://github.com/swaggest/swgui/releases/latest/download/darwin_amd64.tar.gz && tar xf darwin_amd64.tar.gz && rm darwin_amd64.tar.gz 92 | codesign -s - ./swgui 93 | ./swgui -version 94 | ``` 95 | 96 | ### Macos Apple Silicon (M1, etc...) 97 | 98 | ``` 99 | wget https://github.com/swaggest/swgui/releases/latest/download/darwin_arm64.tar.gz && tar xf darwin_arm64.tar.gz && rm darwin_arm64.tar.gz 100 | codesign -s - ./swgui 101 | ./swgui -version 102 | ``` 103 | 104 | Open spec file. 105 | 106 | ``` 107 | swgui my-openapi.yaml 108 | ``` 109 | -------------------------------------------------------------------------------- /internal/index.tpl.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "sort" 5 | "strings" 6 | 7 | "github.com/swaggest/swgui" 8 | ) 9 | 10 | // IndexTpl creates page template. 11 | // 12 | //nolint:funlen // The template is long. 13 | func IndexTpl(assetsBase, faviconBase string, cfg swgui.Config) string { 14 | settings := map[string]string{ 15 | "url": "url", 16 | "dom_id": "'#swagger-ui'", 17 | "deepLinking": "true", 18 | "presets": `[ 19 | SwaggerUIBundle.presets.apis, 20 | SwaggerUIStandalonePreset 21 | ]`, 22 | "plugins": `[ 23 | SwaggerUIBundle.plugins.DownloadUrl 24 | ]`, 25 | "layout": `"StandaloneLayout"`, 26 | "showExtensions": "true", 27 | "showCommonExtensions": "true", 28 | "validatorUrl": "null", 29 | "defaultModelsExpandDepth": "-1", // Hides schemas, override with value "1" in Config.SettingsUI to show schemas. 30 | `onComplete`: `function() { 31 | if (cfg.preAuthorizeApiKey) { 32 | for (var name in cfg.preAuthorizeApiKey) { 33 | ui.preauthorizeApiKey(name, cfg.preAuthorizeApiKey[name]); 34 | } 35 | } 36 | 37 | var dom = document.querySelector('.scheme-container select'); 38 | for (var key in dom) { 39 | if (key.startsWith("__reactInternalInstance$")) { 40 | var compInternals = dom[key]._currentElement; 41 | var compWrapper = compInternals._owner; 42 | compWrapper._instance.setScheme(window.location.protocol.slice(0,-1)); 43 | } 44 | } 45 | }`, 46 | } 47 | 48 | for k, v := range cfg.SettingsUI { 49 | settings[k] = v 50 | } 51 | 52 | if cfg.Proxy && settings["requestInterceptor"] == "" { 53 | settings["requestInterceptor"] = `proxyRequest` 54 | } 55 | 56 | settingsStr := make([]string, 0, len(settings)) 57 | for k, v := range settings { 58 | settingsStr = append(settingsStr, "\t\t\t"+k+": "+v) 59 | } 60 | 61 | sort.Strings(settingsStr) 62 | 63 | return ` 64 | 65 | 66 | 67 | 68 | {{ .Title }} - Swagger UI 69 | 70 | 71 | 72 | 90 | 91 | 100 | 101 | {{ .AppendHead }} 102 | 103 | 104 | 105 | {{ .PrependHTML }} 106 | 107 |
108 | 109 | 110 | 111 | 149 | 150 | {{ .AppendHTML }} 151 | 152 | 153 | 154 | ` 155 | } 156 | -------------------------------------------------------------------------------- /cmd/swgui/swgui.go: -------------------------------------------------------------------------------- 1 | // Package main provides CLI tool to inspect OpenAPI schemas with Swagger UI. 2 | package main 3 | 4 | import ( 5 | "errors" 6 | "flag" 7 | "fmt" 8 | "log" 9 | "net" 10 | "net/http" 11 | "os/exec" 12 | "path" 13 | "regexp" 14 | "runtime" 15 | "strings" 16 | "time" 17 | 18 | "github.com/bool64/dev/version" 19 | "github.com/swaggest/swgui" 20 | "github.com/swaggest/swgui/v5emb" 21 | ) 22 | 23 | func main() { 24 | var ( 25 | listen string 26 | skipBrowser bool 27 | ver bool 28 | proxy bool 29 | ) 30 | 31 | flag.StringVar(&listen, "listen", "127.0.0.1:0", "listen address, port 0 picks a free random port") 32 | flag.BoolVar(&skipBrowser, "s", false, "skip browser opening") 33 | flag.BoolVar(&ver, "version", false, "Show version and exit.") 34 | flag.BoolVar(&proxy, "proxy", false, "Proxy requests.") 35 | 36 | flag.Parse() 37 | 38 | if ver { 39 | fmt.Printf("%s, Swagger UI %s\n", version.Info().Version, "v5.29.1") 40 | 41 | return 42 | } 43 | 44 | if flag.NArg() < 1 { 45 | fmt.Println("Usage: swgui ") 46 | flag.PrintDefaults() 47 | 48 | return 49 | } 50 | 51 | filePathToSchema := flag.Arg(0) 52 | urlToSchema := "/" + path.Base(filePathToSchema) 53 | 54 | cfg := swgui.Config{ 55 | Title: filePathToSchema, 56 | SwaggerJSON: urlToSchema, 57 | BasePath: "/", 58 | Proxy: proxy, 59 | } 60 | 61 | swh := v5emb.NewHandlerWithConfig(cfg) 62 | hh := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { 63 | if r.URL.Path == urlToSchema { 64 | http.ServeFile(rw, r, filePathToSchema) 65 | 66 | return 67 | } 68 | 69 | swh.ServeHTTP(rw, r) 70 | }) 71 | 72 | listener, err := net.Listen("tcp", listen) 73 | if err != nil { 74 | log.Fatalf("failed to start server: %s", err) 75 | 76 | return 77 | } 78 | 79 | addr := listener.Addr().String() 80 | 81 | srv := &http.Server{Handler: hh, ReadHeaderTimeout: time.Second} 82 | 83 | go func() { 84 | if err := srv.Serve(listener); err != nil && !errors.Is(err, http.ErrServerClosed) { 85 | log.Println("failed to listen ans serve: ", err.Error()) 86 | } 87 | }() 88 | 89 | if strings.HasPrefix(listen, ":") { 90 | m, err := interfaces(false) 91 | if err != nil { 92 | log.Println("find network interfaces:", err) 93 | } else { 94 | for _, v := range m { 95 | addr = v + listen 96 | } 97 | } 98 | } 99 | 100 | log.Println("Starting Swagger UI server at http://" + addr) 101 | log.Println("Press Ctrl+C to stop") 102 | 103 | if !skipBrowser { 104 | if err := openBrowser("http://" + addr); err != nil && !strings.Contains(err.Error(), "executable file not found") { 105 | log.Println("failed to open browser", err.Error()) 106 | } 107 | } 108 | 109 | <-make(chan struct{}) 110 | } 111 | 112 | // openBrowser opens the specified URL in the default browser of the user. 113 | func openBrowser(url string) error { 114 | var ( 115 | cmd string 116 | args []string 117 | ) 118 | 119 | switch runtime.GOOS { 120 | case "windows": 121 | cmd = "cmd" 122 | args = []string{"/c", "start"} 123 | case "darwin": 124 | cmd = "open" 125 | default: // "linux", "freebsd", "openbsd", "netbsd" 126 | cmd = "xdg-open" 127 | } 128 | 129 | args = append(args, url) 130 | 131 | return exec.Command(cmd, args...).Start() //nolint:gosec 132 | } 133 | 134 | // interfaces returns a `name:ip` map of the suitable interfaces found. 135 | func interfaces(listAll bool) ([]string, error) { 136 | names := make([]string, 0) 137 | 138 | ifaces, err := net.Interfaces() 139 | if err != nil { 140 | return names, err 141 | } 142 | 143 | re := regexp.MustCompile(`^(veth|br\-|docker|lo|EHC|XHC|bridge|gif|stf|p2p|awdl|utun|tun|tap)`) 144 | 145 | for _, iface := range ifaces { 146 | if !listAll && re.MatchString(iface.Name) { 147 | continue 148 | } 149 | 150 | if iface.Flags&net.FlagUp == 0 { 151 | continue 152 | } 153 | 154 | ip, err := findIP(iface) 155 | if err != nil { 156 | continue 157 | } 158 | 159 | names = append(names, ip) 160 | } 161 | 162 | return names, nil 163 | } 164 | 165 | // FindIP returns the IP address of the passed interface, and an error. 166 | func findIP(iface net.Interface) (string, error) { 167 | var ip string 168 | 169 | addrs, err := iface.Addrs() 170 | if err != nil { 171 | return "", err 172 | } 173 | 174 | for _, addr := range addrs { 175 | if ipnet, ok := addr.(*net.IPNet); ok { 176 | if ipnet.IP.IsLinkLocalUnicast() { 177 | continue 178 | } 179 | 180 | if ipnet.IP.To4() != nil { 181 | ip = ipnet.IP.String() 182 | 183 | continue 184 | } 185 | // Use IPv6 only if an IPv4 hasn't been found yet. 186 | // This is eventually overwritten with an IPv4, if found (see above) 187 | if ip == "" { 188 | ip = "[" + ipnet.IP.String() + "]" 189 | } 190 | } 191 | } 192 | 193 | if ip == "" { 194 | return "", errors.New("unable to find an IP for this interface") 195 | } 196 | 197 | return ip, nil 198 | } 199 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #GOLANGCI_LINT_VERSION := "v2.5.0" # Optional configuration to pinpoint golangci-lint version. 2 | 3 | # The head of Makefile determines location of dev-go to include standard targets. 4 | GO ?= go 5 | export GO111MODULE = on 6 | 7 | ifneq "$(GOFLAGS)" "" 8 | $(info GOFLAGS: ${GOFLAGS}) 9 | endif 10 | 11 | ifneq "$(wildcard ./vendor )" "" 12 | $(info Using vendor) 13 | modVendor = -mod=vendor 14 | ifeq (,$(findstring -mod,$(GOFLAGS))) 15 | export GOFLAGS := ${GOFLAGS} ${modVendor} 16 | endif 17 | ifneq "$(wildcard ./vendor/github.com/bool64/dev)" "" 18 | DEVGO_PATH := ./vendor/github.com/bool64/dev 19 | endif 20 | endif 21 | 22 | ifeq ($(DEVGO_PATH),) 23 | DEVGO_PATH := $(shell GO111MODULE=on $(GO) list ${modVendor} -f '{{.Dir}}' -m github.com/bool64/dev) 24 | ifeq ($(DEVGO_PATH),) 25 | $(info Module github.com/bool64/dev not found, downloading.) 26 | DEVGO_PATH := $(shell export GO111MODULE=on && $(GO) get github.com/bool64/dev && $(GO) list -f '{{.Dir}}' -m github.com/bool64/dev) 27 | endif 28 | endif 29 | 30 | export CGO_ENABLED = 0 31 | BUILD_LDFLAGS=-s -w 32 | BUILD_PKG = ./cmd/swgui 33 | export RELEASE_TARGETS="darwin/amd64 darwin/arm64 linux/amd64 linux/arm64 windows/amd64" 34 | 35 | -include $(DEVGO_PATH)/makefiles/main.mk 36 | -include $(DEVGO_PATH)/makefiles/lint.mk 37 | -include $(DEVGO_PATH)/makefiles/reset-ci.mk 38 | -include $(DEVGO_PATH)/makefiles/release-assets.mk 39 | -include $(DEVGO_PATH)/makefiles/build.mk 40 | 41 | # Add your custom targets here. 42 | 43 | SWAGGER_UI_VERSION_V3 := v3.52.5 44 | SWAGGER_UI_VERSION_V4 := v4.19.1 45 | SWAGGER_UI_VERSION_V5 := v5.29.1 46 | 47 | ## Update assets for Swagger UI v3 48 | update-v3: 49 | curl https://raw.githubusercontent.com/swagger-api/swagger-ui/$(SWAGGER_UI_VERSION_V3)/dist/swagger-ui-bundle.js -o ./v3/static/swagger-ui-bundle.js 50 | curl https://raw.githubusercontent.com/swagger-api/swagger-ui/$(SWAGGER_UI_VERSION_V3)/dist/swagger-ui-standalone-preset.js -o ./v3/static/swagger-ui-standalone-preset.js 51 | curl https://raw.githubusercontent.com/swagger-api/swagger-ui/$(SWAGGER_UI_VERSION_V3)/dist/swagger-ui.js -o ./v3/static/swagger-ui.js 52 | curl https://raw.githubusercontent.com/swagger-api/swagger-ui/$(SWAGGER_UI_VERSION_V3)/dist/swagger-ui.css -o ./v3/static/swagger-ui.css 53 | curl https://raw.githubusercontent.com/swagger-api/swagger-ui/$(SWAGGER_UI_VERSION_V3)/dist/oauth2-redirect.html -o ./v3/static/oauth2-redirect.html 54 | curl https://raw.githubusercontent.com/swagger-api/swagger-ui/$(SWAGGER_UI_VERSION_V3)/dist/favicon-32x32.png -o ./v3/static/favicon-32x32.png 55 | curl https://raw.githubusercontent.com/swagger-api/swagger-ui/$(SWAGGER_UI_VERSION_V3)/dist/favicon-16x16.png -o ./v3/static/favicon-16x16.png 56 | rm -rf ./v3/static/*.gz 57 | go run ./v3/gen/gen.go 58 | zopfli --i50 ./v3/static/*.js && rm -f ./v3/static/*.js 59 | zopfli --i50 ./v3/static/*.css && rm -f ./v3/static/*.css 60 | zopfli --i50 ./v3/static/*.html && rm -f ./v3/static/*.html 61 | 62 | ## Update assets for Swagger UI v4 63 | update-v4: 64 | curl https://raw.githubusercontent.com/swagger-api/swagger-ui/$(SWAGGER_UI_VERSION_V4)/dist/swagger-ui-bundle.js -o ./v4/static/swagger-ui-bundle.js 65 | curl https://raw.githubusercontent.com/swagger-api/swagger-ui/$(SWAGGER_UI_VERSION_V4)/dist/swagger-ui-standalone-preset.js -o ./v4/static/swagger-ui-standalone-preset.js 66 | curl https://raw.githubusercontent.com/swagger-api/swagger-ui/$(SWAGGER_UI_VERSION_V4)/dist/swagger-ui.js -o ./v4/static/swagger-ui.js 67 | curl https://raw.githubusercontent.com/swagger-api/swagger-ui/$(SWAGGER_UI_VERSION_V4)/dist/swagger-ui.css -o ./v4/static/swagger-ui.css 68 | curl https://raw.githubusercontent.com/swagger-api/swagger-ui/$(SWAGGER_UI_VERSION_V4)/dist/oauth2-redirect.html -o ./v4/static/oauth2-redirect.html 69 | curl https://raw.githubusercontent.com/swagger-api/swagger-ui/$(SWAGGER_UI_VERSION_V4)/dist/favicon-32x32.png -o ./v4/static/favicon-32x32.png 70 | curl https://raw.githubusercontent.com/swagger-api/swagger-ui/$(SWAGGER_UI_VERSION_V4)/dist/favicon-16x16.png -o ./v4/static/favicon-16x16.png 71 | rm -rf ./v4/static/*.gz 72 | go run ./v4/gen/gen.go 73 | zopfli --i50 ./v4/static/*.js && rm -f ./v4/static/*.js 74 | zopfli --i50 ./v4/static/*.css && rm -f ./v4/static/*.css 75 | zopfli --i50 ./v4/static/*.html && rm -f ./v4/static/*.html 76 | 77 | ## Update assets for Swagger UI v5 78 | update-v5: 79 | curl https://raw.githubusercontent.com/swagger-api/swagger-ui/$(SWAGGER_UI_VERSION_V5)/dist/swagger-ui-bundle.js -o ./v5/static/swagger-ui-bundle.js 80 | curl https://raw.githubusercontent.com/swagger-api/swagger-ui/$(SWAGGER_UI_VERSION_V5)/dist/swagger-ui-standalone-preset.js -o ./v5/static/swagger-ui-standalone-preset.js 81 | curl https://raw.githubusercontent.com/swagger-api/swagger-ui/$(SWAGGER_UI_VERSION_V5)/dist/swagger-ui.js -o ./v5/static/swagger-ui.js 82 | curl https://raw.githubusercontent.com/swagger-api/swagger-ui/$(SWAGGER_UI_VERSION_V5)/dist/swagger-ui.css -o ./v5/static/swagger-ui.css 83 | curl https://raw.githubusercontent.com/swagger-api/swagger-ui/$(SWAGGER_UI_VERSION_V5)/dist/oauth2-redirect.html -o ./v5/static/oauth2-redirect.html 84 | curl https://raw.githubusercontent.com/swagger-api/swagger-ui/$(SWAGGER_UI_VERSION_V5)/dist/favicon-32x32.png -o ./v5/static/favicon-32x32.png 85 | curl https://raw.githubusercontent.com/swagger-api/swagger-ui/$(SWAGGER_UI_VERSION_V5)/dist/favicon-16x16.png -o ./v5/static/favicon-16x16.png 86 | rm -rf ./v5/static/*.gz 87 | go run ./v5/gen/gen.go 88 | zopfli --i50 ./v5/static/*.js && rm -f ./v5/static/*.js 89 | zopfli --i50 ./v5/static/*.css && rm -f ./v5/static/*.css 90 | zopfli --i50 ./v5/static/*.html && rm -f ./v5/static/*.html 91 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= 2 | github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= 3 | github.com/bool64/dev v0.2.28/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= 4 | github.com/bool64/dev v0.2.43 h1:yQ7qiZVef6WtCl2vDYU0Y+qSq+0aBrQzY8KXkklk9cQ= 5 | github.com/bool64/dev v0.2.43/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= 6 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 7 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 8 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 9 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 10 | github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 h1:bUGsEnyNbVPw06Bs80sCeARAlK8lhwqGyi6UT8ymuGk= 11 | github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= 12 | github.com/shurcooL/httpgzip v0.0.0-20190720172056-320755c1c1b0 h1:mj/nMDAwTBiaCqMEs4cYCqF7pO6Np7vhy1D1wcQGz+E= 13 | github.com/shurcooL/httpgzip v0.0.0-20190720172056-320755c1c1b0/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q= 14 | github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 h1:pXY9qYc/MP5zdvqWEUH6SjNiu7VhSjuVFTFiTcphaLU= 15 | github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= 16 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 17 | github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= 18 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 19 | github.com/vearutop/statigz v1.4.0 h1:RQL0KG3j/uyA/PFpHeZ/L6l2ta920/MxlOAIGEOuwmU= 20 | github.com/vearutop/statigz v1.4.0/go.mod h1:LYTolBLiz9oJISwiVKnOQoIwhO1LWX1A7OECawGS8XE= 21 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 22 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 23 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 24 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 25 | golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 26 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 27 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 28 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 29 | golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= 30 | golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= 31 | golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= 32 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 33 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 34 | golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 35 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 36 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 37 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 38 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 39 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 40 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 41 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 42 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 43 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 44 | golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= 45 | golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= 46 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 47 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 48 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 49 | golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 50 | golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= 51 | golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 52 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 53 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 54 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 55 | golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= 56 | golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= 57 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 58 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 59 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 60 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 61 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 62 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2018 Lazada Tech Hub 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /swagger.json: -------------------------------------------------------------------------------- 1 | { 2 | "swagger": "2.0", 3 | "info": { 4 | "description": "This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters.", 5 | "version": "1.0.0", 6 | "title": "Swagger Petstore", 7 | "termsOfService": "http://swagger.io/terms/", 8 | "contact": { 9 | "email": "apiteam@swagger.io" 10 | }, 11 | "license": { 12 | "name": "Apache 2.0", 13 | "url": "http://www.apache.org/licenses/LICENSE-2.0.html" 14 | } 15 | }, 16 | "host": "petstore.swagger.io", 17 | "basePath": "/v2", 18 | "tags": [ 19 | { 20 | "name": "pet", 21 | "description": "Everything about your Pets", 22 | "externalDocs": { 23 | "description": "Find out more", 24 | "url": "http://swagger.io" 25 | } 26 | }, 27 | { 28 | "name": "store", 29 | "description": "Access to Petstore orders" 30 | }, 31 | { 32 | "name": "user", 33 | "description": "Operations about user", 34 | "externalDocs": { 35 | "description": "Find out more about our store", 36 | "url": "http://swagger.io" 37 | } 38 | } 39 | ], 40 | "schemes": [ 41 | "https", 42 | "http" 43 | ], 44 | "paths": { 45 | "/pet": { 46 | "post": { 47 | "tags": [ 48 | "pet" 49 | ], 50 | "summary": "Add a new pet to the store", 51 | "description": "", 52 | "operationId": "addPet", 53 | "consumes": [ 54 | "application/json", 55 | "application/xml" 56 | ], 57 | "produces": [ 58 | "application/xml", 59 | "application/json" 60 | ], 61 | "parameters": [ 62 | { 63 | "in": "body", 64 | "name": "body", 65 | "description": "Pet object that needs to be added to the store", 66 | "required": true, 67 | "schema": { 68 | "$ref": "#/definitions/Pet" 69 | } 70 | } 71 | ], 72 | "responses": { 73 | "405": { 74 | "description": "Invalid input" 75 | } 76 | }, 77 | "security": [ 78 | { 79 | "petstore_auth": [ 80 | "write:pets", 81 | "read:pets" 82 | ] 83 | } 84 | ] 85 | }, 86 | "put": { 87 | "tags": [ 88 | "pet" 89 | ], 90 | "summary": "Update an existing pet", 91 | "description": "", 92 | "operationId": "updatePet", 93 | "consumes": [ 94 | "application/json", 95 | "application/xml" 96 | ], 97 | "produces": [ 98 | "application/xml", 99 | "application/json" 100 | ], 101 | "parameters": [ 102 | { 103 | "in": "body", 104 | "name": "body", 105 | "description": "Pet object that needs to be added to the store", 106 | "required": true, 107 | "schema": { 108 | "$ref": "#/definitions/Pet" 109 | } 110 | } 111 | ], 112 | "responses": { 113 | "400": { 114 | "description": "Invalid ID supplied" 115 | }, 116 | "404": { 117 | "description": "Pet not found" 118 | }, 119 | "405": { 120 | "description": "Validation exception" 121 | } 122 | }, 123 | "security": [ 124 | { 125 | "petstore_auth": [ 126 | "write:pets", 127 | "read:pets" 128 | ] 129 | } 130 | ] 131 | } 132 | }, 133 | "/pet/findByStatus": { 134 | "get": { 135 | "tags": [ 136 | "pet" 137 | ], 138 | "summary": "Finds Pets by status", 139 | "description": "Multiple status values can be provided with comma separated strings", 140 | "operationId": "findPetsByStatus", 141 | "produces": [ 142 | "application/xml", 143 | "application/json" 144 | ], 145 | "parameters": [ 146 | { 147 | "name": "status", 148 | "in": "query", 149 | "description": "Status values that need to be considered for filter", 150 | "required": true, 151 | "type": "array", 152 | "items": { 153 | "type": "string", 154 | "enum": [ 155 | "available", 156 | "pending", 157 | "sold" 158 | ], 159 | "default": "available" 160 | }, 161 | "collectionFormat": "multi" 162 | } 163 | ], 164 | "responses": { 165 | "200": { 166 | "description": "successful operation", 167 | "schema": { 168 | "type": "array", 169 | "items": { 170 | "$ref": "#/definitions/Pet" 171 | } 172 | } 173 | }, 174 | "400": { 175 | "description": "Invalid status value" 176 | } 177 | }, 178 | "security": [ 179 | { 180 | "petstore_auth": [ 181 | "write:pets", 182 | "read:pets" 183 | ] 184 | } 185 | ] 186 | } 187 | }, 188 | "/pet/findByTags": { 189 | "get": { 190 | "tags": [ 191 | "pet" 192 | ], 193 | "summary": "Finds Pets by tags", 194 | "description": "Muliple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.", 195 | "operationId": "findPetsByTags", 196 | "produces": [ 197 | "application/xml", 198 | "application/json" 199 | ], 200 | "parameters": [ 201 | { 202 | "name": "tags", 203 | "in": "query", 204 | "description": "Tags to filter by", 205 | "required": true, 206 | "type": "array", 207 | "items": { 208 | "type": "string" 209 | }, 210 | "collectionFormat": "multi" 211 | } 212 | ], 213 | "responses": { 214 | "200": { 215 | "description": "successful operation", 216 | "schema": { 217 | "type": "array", 218 | "items": { 219 | "$ref": "#/definitions/Pet" 220 | } 221 | } 222 | }, 223 | "400": { 224 | "description": "Invalid tag value" 225 | } 226 | }, 227 | "security": [ 228 | { 229 | "petstore_auth": [ 230 | "write:pets", 231 | "read:pets" 232 | ] 233 | } 234 | ], 235 | "deprecated": true 236 | } 237 | }, 238 | "/pet/{petId}": { 239 | "get": { 240 | "tags": [ 241 | "pet" 242 | ], 243 | "summary": "Find pet by ID", 244 | "description": "Returns a single pet", 245 | "operationId": "getPetById", 246 | "produces": [ 247 | "application/xml", 248 | "application/json" 249 | ], 250 | "parameters": [ 251 | { 252 | "name": "petId", 253 | "in": "path", 254 | "description": "ID of pet to return", 255 | "required": true, 256 | "type": "integer", 257 | "format": "int64" 258 | } 259 | ], 260 | "responses": { 261 | "200": { 262 | "description": "successful operation", 263 | "schema": { 264 | "$ref": "#/definitions/Pet" 265 | } 266 | }, 267 | "400": { 268 | "description": "Invalid ID supplied" 269 | }, 270 | "404": { 271 | "description": "Pet not found" 272 | } 273 | }, 274 | "security": [ 275 | { 276 | "api_key": [] 277 | } 278 | ] 279 | }, 280 | "post": { 281 | "tags": [ 282 | "pet" 283 | ], 284 | "summary": "Updates a pet in the store with form data", 285 | "description": "", 286 | "operationId": "updatePetWithForm", 287 | "consumes": [ 288 | "application/x-www-form-urlencoded" 289 | ], 290 | "produces": [ 291 | "application/xml", 292 | "application/json" 293 | ], 294 | "parameters": [ 295 | { 296 | "name": "petId", 297 | "in": "path", 298 | "description": "ID of pet that needs to be updated", 299 | "required": true, 300 | "type": "integer", 301 | "format": "int64" 302 | }, 303 | { 304 | "name": "name", 305 | "in": "formData", 306 | "description": "Updated name of the pet", 307 | "required": false, 308 | "type": "string" 309 | }, 310 | { 311 | "name": "status", 312 | "in": "formData", 313 | "description": "Updated status of the pet", 314 | "required": false, 315 | "type": "string" 316 | } 317 | ], 318 | "responses": { 319 | "405": { 320 | "description": "Invalid input" 321 | } 322 | }, 323 | "security": [ 324 | { 325 | "petstore_auth": [ 326 | "write:pets", 327 | "read:pets" 328 | ] 329 | } 330 | ] 331 | }, 332 | "delete": { 333 | "tags": [ 334 | "pet" 335 | ], 336 | "summary": "Deletes a pet", 337 | "description": "", 338 | "operationId": "deletePet", 339 | "produces": [ 340 | "application/xml", 341 | "application/json" 342 | ], 343 | "parameters": [ 344 | { 345 | "name": "api_key", 346 | "in": "header", 347 | "required": false, 348 | "type": "string" 349 | }, 350 | { 351 | "name": "petId", 352 | "in": "path", 353 | "description": "Pet id to delete", 354 | "required": true, 355 | "type": "integer", 356 | "format": "int64" 357 | } 358 | ], 359 | "responses": { 360 | "400": { 361 | "description": "Invalid ID supplied" 362 | }, 363 | "404": { 364 | "description": "Pet not found" 365 | } 366 | }, 367 | "security": [ 368 | { 369 | "petstore_auth": [ 370 | "write:pets", 371 | "read:pets" 372 | ] 373 | } 374 | ] 375 | } 376 | }, 377 | "/pet/{petId}/uploadImage": { 378 | "post": { 379 | "tags": [ 380 | "pet" 381 | ], 382 | "summary": "uploads an image", 383 | "description": "", 384 | "operationId": "uploadFile", 385 | "consumes": [ 386 | "multipart/form-data" 387 | ], 388 | "produces": [ 389 | "application/json" 390 | ], 391 | "parameters": [ 392 | { 393 | "name": "petId", 394 | "in": "path", 395 | "description": "ID of pet to update", 396 | "required": true, 397 | "type": "integer", 398 | "format": "int64" 399 | }, 400 | { 401 | "name": "additionalMetadata", 402 | "in": "formData", 403 | "description": "Additional data to pass to server", 404 | "required": false, 405 | "type": "string" 406 | }, 407 | { 408 | "name": "file", 409 | "in": "formData", 410 | "description": "file to upload", 411 | "required": false, 412 | "type": "file" 413 | } 414 | ], 415 | "responses": { 416 | "200": { 417 | "description": "successful operation", 418 | "schema": { 419 | "$ref": "#/definitions/ApiResponse" 420 | } 421 | } 422 | }, 423 | "security": [ 424 | { 425 | "petstore_auth": [ 426 | "write:pets", 427 | "read:pets" 428 | ] 429 | } 430 | ] 431 | } 432 | }, 433 | "/store/inventory": { 434 | "get": { 435 | "tags": [ 436 | "store" 437 | ], 438 | "summary": "Returns pet inventories by status", 439 | "description": "Returns a map of status codes to quantities", 440 | "operationId": "getInventory", 441 | "produces": [ 442 | "application/json" 443 | ], 444 | "parameters": [], 445 | "responses": { 446 | "200": { 447 | "description": "successful operation", 448 | "schema": { 449 | "type": "object", 450 | "additionalProperties": { 451 | "type": "integer", 452 | "format": "int32" 453 | } 454 | } 455 | } 456 | }, 457 | "security": [ 458 | { 459 | "api_key": [] 460 | } 461 | ] 462 | } 463 | }, 464 | "/store/order": { 465 | "post": { 466 | "tags": [ 467 | "store" 468 | ], 469 | "summary": "Place an order for a pet", 470 | "description": "", 471 | "operationId": "placeOrder", 472 | "produces": [ 473 | "application/xml", 474 | "application/json" 475 | ], 476 | "parameters": [ 477 | { 478 | "in": "body", 479 | "name": "body", 480 | "description": "order placed for purchasing the pet", 481 | "required": true, 482 | "schema": { 483 | "$ref": "#/definitions/Order" 484 | } 485 | } 486 | ], 487 | "responses": { 488 | "200": { 489 | "description": "successful operation", 490 | "schema": { 491 | "$ref": "#/definitions/Order" 492 | } 493 | }, 494 | "400": { 495 | "description": "Invalid Order" 496 | } 497 | } 498 | } 499 | }, 500 | "/store/order/{orderId}": { 501 | "get": { 502 | "tags": [ 503 | "store" 504 | ], 505 | "summary": "Find purchase order by ID", 506 | "description": "For valid response try integer IDs with value >= 1 and <= 10. Other values will generated exceptions", 507 | "operationId": "getOrderById", 508 | "produces": [ 509 | "application/xml", 510 | "application/json" 511 | ], 512 | "parameters": [ 513 | { 514 | "name": "orderId", 515 | "in": "path", 516 | "description": "ID of pet that needs to be fetched", 517 | "required": true, 518 | "type": "integer", 519 | "maximum": 10.0, 520 | "minimum": 1.0, 521 | "format": "int64" 522 | } 523 | ], 524 | "responses": { 525 | "200": { 526 | "description": "successful operation", 527 | "schema": { 528 | "$ref": "#/definitions/Order" 529 | } 530 | }, 531 | "400": { 532 | "description": "Invalid ID supplied" 533 | }, 534 | "404": { 535 | "description": "Order not found" 536 | } 537 | } 538 | }, 539 | "delete": { 540 | "tags": [ 541 | "store" 542 | ], 543 | "summary": "Delete purchase order by ID", 544 | "description": "For valid response try integer IDs with positive integer value. Negative or non-integer values will generate API errors", 545 | "operationId": "deleteOrder", 546 | "produces": [ 547 | "application/xml", 548 | "application/json" 549 | ], 550 | "parameters": [ 551 | { 552 | "name": "orderId", 553 | "in": "path", 554 | "description": "ID of the order that needs to be deleted", 555 | "required": true, 556 | "type": "integer", 557 | "minimum": 1.0, 558 | "format": "int64" 559 | } 560 | ], 561 | "responses": { 562 | "400": { 563 | "description": "Invalid ID supplied" 564 | }, 565 | "404": { 566 | "description": "Order not found" 567 | } 568 | } 569 | } 570 | }, 571 | "/user": { 572 | "post": { 573 | "tags": [ 574 | "user" 575 | ], 576 | "summary": "Create user", 577 | "description": "This can only be done by the logged in user.", 578 | "operationId": "createUser", 579 | "produces": [ 580 | "application/xml", 581 | "application/json" 582 | ], 583 | "parameters": [ 584 | { 585 | "in": "body", 586 | "name": "body", 587 | "description": "Created user object", 588 | "required": true, 589 | "schema": { 590 | "$ref": "#/definitions/User" 591 | } 592 | } 593 | ], 594 | "responses": { 595 | "default": { 596 | "description": "successful operation" 597 | } 598 | } 599 | } 600 | }, 601 | "/user/createWithArray": { 602 | "post": { 603 | "tags": [ 604 | "user" 605 | ], 606 | "summary": "Creates list of users with given input array", 607 | "description": "", 608 | "operationId": "createUsersWithArrayInput", 609 | "produces": [ 610 | "application/xml", 611 | "application/json" 612 | ], 613 | "parameters": [ 614 | { 615 | "in": "body", 616 | "name": "body", 617 | "description": "List of user object", 618 | "required": true, 619 | "schema": { 620 | "type": "array", 621 | "items": { 622 | "$ref": "#/definitions/User" 623 | } 624 | } 625 | } 626 | ], 627 | "responses": { 628 | "default": { 629 | "description": "successful operation" 630 | } 631 | } 632 | } 633 | }, 634 | "/user/createWithList": { 635 | "post": { 636 | "tags": [ 637 | "user" 638 | ], 639 | "summary": "Creates list of users with given input array", 640 | "description": "", 641 | "operationId": "createUsersWithListInput", 642 | "produces": [ 643 | "application/xml", 644 | "application/json" 645 | ], 646 | "parameters": [ 647 | { 648 | "in": "body", 649 | "name": "body", 650 | "description": "List of user object", 651 | "required": true, 652 | "schema": { 653 | "type": "array", 654 | "items": { 655 | "$ref": "#/definitions/User" 656 | } 657 | } 658 | } 659 | ], 660 | "responses": { 661 | "default": { 662 | "description": "successful operation" 663 | } 664 | } 665 | } 666 | }, 667 | "/user/login": { 668 | "get": { 669 | "tags": [ 670 | "user" 671 | ], 672 | "summary": "Logs user into the system", 673 | "description": "", 674 | "operationId": "loginUser", 675 | "produces": [ 676 | "application/xml", 677 | "application/json" 678 | ], 679 | "parameters": [ 680 | { 681 | "name": "username", 682 | "in": "query", 683 | "description": "The user name for login", 684 | "required": true, 685 | "type": "string" 686 | }, 687 | { 688 | "name": "password", 689 | "in": "query", 690 | "description": "The password for login in clear text", 691 | "required": true, 692 | "type": "string" 693 | } 694 | ], 695 | "responses": { 696 | "200": { 697 | "description": "successful operation", 698 | "schema": { 699 | "type": "string" 700 | }, 701 | "headers": { 702 | "X-Rate-Limit": { 703 | "type": "integer", 704 | "format": "int32", 705 | "description": "calls per hour allowed by the user" 706 | }, 707 | "X-Expires-After": { 708 | "type": "string", 709 | "format": "date-time", 710 | "description": "date in UTC when token expires" 711 | } 712 | } 713 | }, 714 | "400": { 715 | "description": "Invalid username/password supplied" 716 | } 717 | } 718 | } 719 | }, 720 | "/user/logout": { 721 | "get": { 722 | "tags": [ 723 | "user" 724 | ], 725 | "summary": "Logs out current logged in user session", 726 | "description": "", 727 | "operationId": "logoutUser", 728 | "produces": [ 729 | "application/xml", 730 | "application/json" 731 | ], 732 | "parameters": [], 733 | "responses": { 734 | "default": { 735 | "description": "successful operation" 736 | } 737 | } 738 | } 739 | }, 740 | "/user/{username}": { 741 | "get": { 742 | "tags": [ 743 | "user" 744 | ], 745 | "summary": "Get user by user name", 746 | "description": "", 747 | "operationId": "getUserByName", 748 | "produces": [ 749 | "application/xml", 750 | "application/json" 751 | ], 752 | "parameters": [ 753 | { 754 | "name": "username", 755 | "in": "path", 756 | "description": "The name that needs to be fetched. Use user1 for testing. ", 757 | "required": true, 758 | "type": "string" 759 | } 760 | ], 761 | "responses": { 762 | "200": { 763 | "description": "successful operation", 764 | "schema": { 765 | "$ref": "#/definitions/User" 766 | } 767 | }, 768 | "400": { 769 | "description": "Invalid username supplied" 770 | }, 771 | "404": { 772 | "description": "User not found" 773 | } 774 | } 775 | }, 776 | "put": { 777 | "tags": [ 778 | "user" 779 | ], 780 | "summary": "Updated user", 781 | "description": "This can only be done by the logged in user.", 782 | "operationId": "updateUser", 783 | "produces": [ 784 | "application/xml", 785 | "application/json" 786 | ], 787 | "parameters": [ 788 | { 789 | "name": "username", 790 | "in": "path", 791 | "description": "name that need to be updated", 792 | "required": true, 793 | "type": "string" 794 | }, 795 | { 796 | "in": "body", 797 | "name": "body", 798 | "description": "Updated user object", 799 | "required": true, 800 | "schema": { 801 | "$ref": "#/definitions/User" 802 | } 803 | } 804 | ], 805 | "responses": { 806 | "400": { 807 | "description": "Invalid user supplied" 808 | }, 809 | "404": { 810 | "description": "User not found" 811 | } 812 | } 813 | }, 814 | "delete": { 815 | "tags": [ 816 | "user" 817 | ], 818 | "summary": "Delete user", 819 | "description": "This can only be done by the logged in user.", 820 | "operationId": "deleteUser", 821 | "produces": [ 822 | "application/xml", 823 | "application/json" 824 | ], 825 | "parameters": [ 826 | { 827 | "name": "username", 828 | "in": "path", 829 | "description": "The name that needs to be deleted", 830 | "required": true, 831 | "type": "string" 832 | } 833 | ], 834 | "responses": { 835 | "400": { 836 | "description": "Invalid username supplied" 837 | }, 838 | "404": { 839 | "description": "User not found" 840 | } 841 | } 842 | } 843 | } 844 | }, 845 | "securityDefinitions": { 846 | "petstore_auth": { 847 | "type": "oauth2", 848 | "authorizationUrl": "https://petstore.swagger.io/oauth/dialog", 849 | "flow": "implicit", 850 | "scopes": { 851 | "write:pets": "modify pets in your account", 852 | "read:pets": "read your pets" 853 | } 854 | }, 855 | "api_key": { 856 | "type": "apiKey", 857 | "name": "api_key", 858 | "in": "header" 859 | } 860 | }, 861 | "definitions": { 862 | "Order": { 863 | "type": "object", 864 | "properties": { 865 | "id": { 866 | "type": "integer", 867 | "format": "int64" 868 | }, 869 | "petId": { 870 | "type": "integer", 871 | "format": "int64" 872 | }, 873 | "quantity": { 874 | "type": "integer", 875 | "format": "int32" 876 | }, 877 | "shipDate": { 878 | "type": "string", 879 | "format": "date-time" 880 | }, 881 | "status": { 882 | "type": "string", 883 | "description": "Order Status", 884 | "enum": [ 885 | "placed", 886 | "approved", 887 | "delivered" 888 | ] 889 | }, 890 | "complete": { 891 | "type": "boolean", 892 | "default": false 893 | } 894 | }, 895 | "xml": { 896 | "name": "Order" 897 | } 898 | }, 899 | "User": { 900 | "type": "object", 901 | "properties": { 902 | "id": { 903 | "type": "integer", 904 | "format": "int64" 905 | }, 906 | "username": { 907 | "type": "string" 908 | }, 909 | "firstName": { 910 | "type": "string" 911 | }, 912 | "lastName": { 913 | "type": "string" 914 | }, 915 | "email": { 916 | "type": "string" 917 | }, 918 | "password": { 919 | "type": "string" 920 | }, 921 | "phone": { 922 | "type": "string" 923 | }, 924 | "userStatus": { 925 | "type": "integer", 926 | "format": "int32", 927 | "description": "User Status" 928 | } 929 | }, 930 | "xml": { 931 | "name": "User" 932 | } 933 | }, 934 | "Category": { 935 | "type": "object", 936 | "properties": { 937 | "id": { 938 | "type": "integer", 939 | "format": "int64" 940 | }, 941 | "name": { 942 | "type": "string" 943 | } 944 | }, 945 | "xml": { 946 | "name": "Category" 947 | } 948 | }, 949 | "Tag": { 950 | "type": "object", 951 | "properties": { 952 | "id": { 953 | "type": "integer", 954 | "format": "int64" 955 | }, 956 | "name": { 957 | "type": "string" 958 | } 959 | }, 960 | "xml": { 961 | "name": "Tag" 962 | } 963 | }, 964 | "Pet": { 965 | "type": "object", 966 | "required": [ 967 | "name", 968 | "photoUrls" 969 | ], 970 | "properties": { 971 | "id": { 972 | "type": "integer", 973 | "format": "int64" 974 | }, 975 | "category": { 976 | "$ref": "#/definitions/Category" 977 | }, 978 | "name": { 979 | "type": "string", 980 | "example": "doggie" 981 | }, 982 | "photoUrls": { 983 | "type": "array", 984 | "xml": { 985 | "name": "photoUrl", 986 | "wrapped": true 987 | }, 988 | "items": { 989 | "type": "string" 990 | } 991 | }, 992 | "tags": { 993 | "type": "array", 994 | "xml": { 995 | "name": "tag", 996 | "wrapped": true 997 | }, 998 | "items": { 999 | "$ref": "#/definitions/Tag" 1000 | } 1001 | }, 1002 | "status": { 1003 | "type": "string", 1004 | "description": "pet status in the store", 1005 | "enum": [ 1006 | "available", 1007 | "pending", 1008 | "sold" 1009 | ] 1010 | } 1011 | }, 1012 | "xml": { 1013 | "name": "Pet" 1014 | } 1015 | }, 1016 | "ApiResponse": { 1017 | "type": "object", 1018 | "properties": { 1019 | "code": { 1020 | "type": "integer", 1021 | "format": "int32" 1022 | }, 1023 | "type": { 1024 | "type": "string" 1025 | }, 1026 | "message": { 1027 | "type": "string" 1028 | } 1029 | } 1030 | } 1031 | }, 1032 | "externalDocs": { 1033 | "description": "Find out more about Swagger", 1034 | "url": "http://swagger.io" 1035 | } 1036 | } --------------------------------------------------------------------------------