Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
64d8dea07f | ||
|
|
88c9ed2643 | ||
|
|
bd7f2153bf |
@@ -143,6 +143,9 @@ Demo project tree, `swag init` is run at relative `.`
|
||||
└── main.go
|
||||
```
|
||||
|
||||
## Multiple APIs
|
||||
This feature where introduced in swag v1.7.9
|
||||
|
||||
## Configuration
|
||||
|
||||
You can configure Swagger using different configuration options
|
||||
|
||||
23
example/multiple/README.md
Normal file
23
example/multiple/README.md
Normal file
@@ -0,0 +1,23 @@
|
||||
|
||||
# Multiple API feature
|
||||
Since swag 1.7.9 we are allowing registration of multiple endpoints into the same server.
|
||||
|
||||
Generate documentation for v1 endpoints
|
||||
```shell
|
||||
swag i -g main.go -dir api/v1 --instanceName v1
|
||||
```
|
||||
|
||||
|
||||
Generate documentation for v2 endpoints
|
||||
```shell
|
||||
swag i -g main.go -dir api/v2 --instanceName v2
|
||||
```
|
||||
|
||||
Run example
|
||||
```shell
|
||||
go run main.go
|
||||
```
|
||||
|
||||
Now you can access the v1 swagger here [http://localhost:8080/swagger/v1/index.html](http://localhost:8080/swagger/v1/index.html) ,
|
||||
and v2 swagger here [http://localhost:8080/swagger/v2/index.html](http://localhost:8080/swagger/v2/index.html)
|
||||
|
||||
26
example/multiple/api/v1/example.go
Normal file
26
example/multiple/api/v1/example.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type Book struct {
|
||||
ID int `json:"id,omitempty"`
|
||||
Title string `json:"title"`
|
||||
Author string `json:"author"`
|
||||
Year *uint16 `json:"year"`
|
||||
}
|
||||
|
||||
//
|
||||
// @Summary Get a list of books in the the store
|
||||
// @Description get string by ID
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {array} Book "ok"
|
||||
// @Router /books [get]
|
||||
func GetBooks(ctx *gin.Context) {
|
||||
ctx.JSON(200, []Book{
|
||||
{ID: 1, Title: "Book 1", Author: "Author 1", Year: nil},
|
||||
{ID: 2, Title: "Book 2", Author: "Author 2", Year: nil},
|
||||
})
|
||||
}
|
||||
25
example/multiple/api/v1/main.go
Normal file
25
example/multiple/api/v1/main.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// @title Swagger Example API
|
||||
// @version 1.0
|
||||
// @description This is a sample server.
|
||||
// @termsOfService http://swagger.io/terms/
|
||||
|
||||
// @contact.name API Support
|
||||
// @contact.url http://www.swagger.io/support
|
||||
// @contact.email support@swagger.io
|
||||
|
||||
// @license.name Apache 2.0
|
||||
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
// @BasePath /v1
|
||||
|
||||
func Register(router *gin.Engine) {
|
||||
v1 := router.Group("v1")
|
||||
|
||||
v1.GET("/books", GetBooks)
|
||||
}
|
||||
26
example/multiple/api/v2/example.go
Normal file
26
example/multiple/api/v2/example.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package v2
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type Book struct {
|
||||
ID int `json:"id,omitempty"`
|
||||
Title string `json:"title"`
|
||||
Author string `json:"author"`
|
||||
Year *uint16 `json:"year"`
|
||||
}
|
||||
|
||||
//
|
||||
// @Summary Get a list of books in the the store
|
||||
// @Description get string by ID
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {array} Book "ok"
|
||||
// @Router /books [get]
|
||||
func GetBooks(ctx *gin.Context) {
|
||||
ctx.JSON(200, []Book{
|
||||
{ID: 1, Title: "Book 3", Author: "Author 3", Year: nil},
|
||||
{ID: 2, Title: "Book 4", Author: "Author 4", Year: nil},
|
||||
})
|
||||
}
|
||||
25
example/multiple/api/v2/main.go
Normal file
25
example/multiple/api/v2/main.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package v2
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// @title Swagger Example API
|
||||
// @version 2.0
|
||||
// @description This is a sample server.
|
||||
// @termsOfService http://swagger.io/terms/
|
||||
|
||||
// @contact.name API Support
|
||||
// @contact.url http://www.swagger.io/support
|
||||
// @contact.email support@swagger.io
|
||||
|
||||
// @license.name Apache 2.0
|
||||
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
// @BasePath /v2
|
||||
|
||||
func Register(router *gin.Engine) {
|
||||
v2 := router.Group("v2")
|
||||
|
||||
v2.GET("/books", GetBooks)
|
||||
}
|
||||
87
example/multiple/docs/v1_docs.go
Normal file
87
example/multiple/docs/v1_docs.go
Normal file
@@ -0,0 +1,87 @@
|
||||
// Package docs GENERATED BY SWAG; DO NOT EDIT
|
||||
// This file was generated by swaggo/swag
|
||||
package docs
|
||||
|
||||
import "github.com/swaggo/swag"
|
||||
|
||||
const docTemplatev1 = `{
|
||||
"schemes": {{ marshal .Schemes }},
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"description": "{{escape .Description}}",
|
||||
"title": "{{.Title}}",
|
||||
"termsOfService": "http://swagger.io/terms/",
|
||||
"contact": {
|
||||
"name": "API Support",
|
||||
"url": "http://www.swagger.io/support",
|
||||
"email": "support@swagger.io"
|
||||
},
|
||||
"license": {
|
||||
"name": "Apache 2.0",
|
||||
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
|
||||
},
|
||||
"version": "{{.Version}}"
|
||||
},
|
||||
"host": "{{.Host}}",
|
||||
"basePath": "{{.BasePath}}",
|
||||
"paths": {
|
||||
"/books": {
|
||||
"get": {
|
||||
"description": "get string by ID",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"summary": "Get a list of books in the the store",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "ok",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/v1.Book"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"v1.Book": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"author": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"year": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
// SwaggerInfov1 holds exported Swagger Info so clients can modify it
|
||||
var SwaggerInfov1 = &swag.Spec{
|
||||
Version: "1.0",
|
||||
Host: "",
|
||||
BasePath: "/v1",
|
||||
Schemes: []string{},
|
||||
Title: "Swagger Example API",
|
||||
Description: "This is a sample server.",
|
||||
InfoInstanceName: "v1",
|
||||
SwaggerTemplate: docTemplatev1,
|
||||
}
|
||||
|
||||
func init() {
|
||||
swag.Register(SwaggerInfov1.InstanceName(), SwaggerInfov1)
|
||||
}
|
||||
63
example/multiple/docs/v1_swagger.json
Normal file
63
example/multiple/docs/v1_swagger.json
Normal file
@@ -0,0 +1,63 @@
|
||||
{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"description": "This is a sample server.",
|
||||
"title": "Swagger Example API",
|
||||
"termsOfService": "http://swagger.io/terms/",
|
||||
"contact": {
|
||||
"name": "API Support",
|
||||
"url": "http://www.swagger.io/support",
|
||||
"email": "support@swagger.io"
|
||||
},
|
||||
"license": {
|
||||
"name": "Apache 2.0",
|
||||
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
|
||||
},
|
||||
"version": "1.0"
|
||||
},
|
||||
"basePath": "/v1",
|
||||
"paths": {
|
||||
"/books": {
|
||||
"get": {
|
||||
"description": "get string by ID",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"summary": "Get a list of books in the the store",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "ok",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/v1.Book"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"v1.Book": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"author": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"year": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
42
example/multiple/docs/v1_swagger.yaml
Normal file
42
example/multiple/docs/v1_swagger.yaml
Normal file
@@ -0,0 +1,42 @@
|
||||
basePath: /v1
|
||||
definitions:
|
||||
v1.Book:
|
||||
properties:
|
||||
author:
|
||||
type: string
|
||||
id:
|
||||
type: integer
|
||||
title:
|
||||
type: string
|
||||
year:
|
||||
type: integer
|
||||
type: object
|
||||
info:
|
||||
contact:
|
||||
email: support@swagger.io
|
||||
name: API Support
|
||||
url: http://www.swagger.io/support
|
||||
description: This is a sample server.
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
termsOfService: http://swagger.io/terms/
|
||||
title: Swagger Example API
|
||||
version: "1.0"
|
||||
paths:
|
||||
/books:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: get string by ID
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: ok
|
||||
schema:
|
||||
items:
|
||||
$ref: '#/definitions/v1.Book'
|
||||
type: array
|
||||
summary: Get a list of books in the the store
|
||||
swagger: "2.0"
|
||||
87
example/multiple/docs/v2_docs.go
Normal file
87
example/multiple/docs/v2_docs.go
Normal file
@@ -0,0 +1,87 @@
|
||||
// Package docs GENERATED BY SWAG; DO NOT EDIT
|
||||
// This file was generated by swaggo/swag
|
||||
package docs
|
||||
|
||||
import "github.com/swaggo/swag"
|
||||
|
||||
const docTemplatev2 = `{
|
||||
"schemes": {{ marshal .Schemes }},
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"description": "{{escape .Description}}",
|
||||
"title": "{{.Title}}",
|
||||
"termsOfService": "http://swagger.io/terms/",
|
||||
"contact": {
|
||||
"name": "API Support",
|
||||
"url": "http://www.swagger.io/support",
|
||||
"email": "support@swagger.io"
|
||||
},
|
||||
"license": {
|
||||
"name": "Apache 2.0",
|
||||
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
|
||||
},
|
||||
"version": "{{.Version}}"
|
||||
},
|
||||
"host": "{{.Host}}",
|
||||
"basePath": "{{.BasePath}}",
|
||||
"paths": {
|
||||
"/books": {
|
||||
"get": {
|
||||
"description": "get string by ID",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"summary": "Get a list of books in the the store",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "ok",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/v2.Book"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"v2.Book": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"author": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"year": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
// SwaggerInfov2 holds exported Swagger Info so clients can modify it
|
||||
var SwaggerInfov2 = &swag.Spec{
|
||||
Version: "2.0",
|
||||
Host: "",
|
||||
BasePath: "/v2",
|
||||
Schemes: []string{},
|
||||
Title: "Swagger Example API",
|
||||
Description: "This is a sample server.",
|
||||
InfoInstanceName: "v2",
|
||||
SwaggerTemplate: docTemplatev2,
|
||||
}
|
||||
|
||||
func init() {
|
||||
swag.Register(SwaggerInfov2.InstanceName(), SwaggerInfov2)
|
||||
}
|
||||
63
example/multiple/docs/v2_swagger.json
Normal file
63
example/multiple/docs/v2_swagger.json
Normal file
@@ -0,0 +1,63 @@
|
||||
{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"description": "This is a sample server.",
|
||||
"title": "Swagger Example API",
|
||||
"termsOfService": "http://swagger.io/terms/",
|
||||
"contact": {
|
||||
"name": "API Support",
|
||||
"url": "http://www.swagger.io/support",
|
||||
"email": "support@swagger.io"
|
||||
},
|
||||
"license": {
|
||||
"name": "Apache 2.0",
|
||||
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
|
||||
},
|
||||
"version": "2.0"
|
||||
},
|
||||
"basePath": "/v2",
|
||||
"paths": {
|
||||
"/books": {
|
||||
"get": {
|
||||
"description": "get string by ID",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"summary": "Get a list of books in the the store",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "ok",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/v2.Book"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"v2.Book": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"author": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"year": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
42
example/multiple/docs/v2_swagger.yaml
Normal file
42
example/multiple/docs/v2_swagger.yaml
Normal file
@@ -0,0 +1,42 @@
|
||||
basePath: /v2
|
||||
definitions:
|
||||
v2.Book:
|
||||
properties:
|
||||
author:
|
||||
type: string
|
||||
id:
|
||||
type: integer
|
||||
title:
|
||||
type: string
|
||||
year:
|
||||
type: integer
|
||||
type: object
|
||||
info:
|
||||
contact:
|
||||
email: support@swagger.io
|
||||
name: API Support
|
||||
url: http://www.swagger.io/support
|
||||
description: This is a sample server.
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
termsOfService: http://swagger.io/terms/
|
||||
title: Swagger Example API
|
||||
version: "2.0"
|
||||
paths:
|
||||
/books:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: get string by ID
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: ok
|
||||
schema:
|
||||
items:
|
||||
$ref: '#/definitions/v2.Book'
|
||||
type: array
|
||||
summary: Get a list of books in the the store
|
||||
swagger: "2.0"
|
||||
26
example/multiple/main.go
Normal file
26
example/multiple/main.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
swaggerFiles "github.com/swaggo/files"
|
||||
ginSwagger "github.com/swaggo/gin-swagger"
|
||||
v1 "github.com/swaggo/gin-swagger/example/multiple/api/v1"
|
||||
v2 "github.com/swaggo/gin-swagger/example/multiple/api/v2"
|
||||
_ "github.com/swaggo/gin-swagger/example/multiple/docs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// New gin router
|
||||
router := gin.New()
|
||||
|
||||
// Register api/v1 endpoints
|
||||
v1.Register(router)
|
||||
router.GET("/swagger/v1/*any", ginSwagger.WrapHandler(swaggerFiles.Handler, ginSwagger.InstanceName("v1")))
|
||||
|
||||
// Register api/v2 endpoints
|
||||
v2.Register(router)
|
||||
router.GET("/swagger/v2/*any", ginSwagger.WrapHandler(swaggerFiles.Handler, ginSwagger.InstanceName("v2")))
|
||||
|
||||
// Listen and Server in
|
||||
_ = router.Run()
|
||||
}
|
||||
6
go.mod
6
go.mod
@@ -3,10 +3,10 @@ module github.com/swaggo/gin-swagger
|
||||
go 1.15
|
||||
|
||||
require (
|
||||
github.com/gin-contrib/gzip v0.0.3
|
||||
github.com/gin-contrib/gzip v0.0.5
|
||||
github.com/gin-gonic/gin v1.7.7
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/swaggo/files v0.0.0-20210815190702-a29dd2bc99b2
|
||||
github.com/swaggo/swag v1.7.9
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd
|
||||
github.com/swaggo/swag v1.8.1
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4
|
||||
)
|
||||
|
||||
14
go.sum
14
go.sum
@@ -15,9 +15,12 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gin-contrib/gzip v0.0.3 h1:etUaeesHhEORpZMp18zoOhepboiWnFtXrBZxszWUn4k=
|
||||
github.com/gin-contrib/gzip v0.0.3/go.mod h1:YxxswVZIqOvcHEQpsSn+QF5guQtO1dCfy0shBPy4jFc=
|
||||
github.com/gin-contrib/gzip v0.0.5 h1:mhnVU32YnnBh2LPH2iqRqsA/eR7SAqRaD388jL2s/j0=
|
||||
github.com/gin-contrib/gzip v0.0.5/go.mod h1:OPIK6HR0Um2vNmBUTlayD7qle4yVVRZT0PyhdUigrKk=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||
github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
|
||||
github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs=
|
||||
github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U=
|
||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
@@ -81,7 +84,6 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
@@ -90,8 +92,8 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/swaggo/files v0.0.0-20210815190702-a29dd2bc99b2 h1:+iNTcqQJy0OZ5jk6a5NLib47eqXK8uYcPX+O4+cBpEM=
|
||||
github.com/swaggo/files v0.0.0-20210815190702-a29dd2bc99b2/go.mod h1:lKJPbtWzJ9JhsTN1k1gZgleJWY/cqq0psdoMmaThG3w=
|
||||
github.com/swaggo/swag v1.7.9 h1:6vCG5mm43ebDzGlZPMGYrYI4zKFfOr5kicQX8qjeDwc=
|
||||
github.com/swaggo/swag v1.7.9/go.mod h1:gZ+TJ2w/Ve1RwQsA2IRoSOTidHz6DX+PIG8GWvbnoLU=
|
||||
github.com/swaggo/swag v1.8.1 h1:JuARzFX1Z1njbCGz+ZytBR15TFJwF2Q7fu8puJHhQYI=
|
||||
github.com/swaggo/swag v1.8.1/go.mod h1:ugemnJsPZm/kRwFUnzBlbHRd0JY9zE1M4F+uy2pAaPQ=
|
||||
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||
@@ -108,10 +110,9 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 h1:HVyaeDAYux4pnY+D/SiwmLOR36ewZ4iGQIIrtnuCjFA=
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -121,7 +122,6 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
||||
130
swagger.go
130
swagger.go
@@ -16,59 +16,56 @@ import (
|
||||
|
||||
type swaggerConfig struct {
|
||||
URL string
|
||||
DeepLinking bool
|
||||
DocExpansion string
|
||||
DefaultModelsExpandDepth int
|
||||
Oauth2RedirectURL template.JS
|
||||
Title string
|
||||
Oauth2RedirectURL template.JS
|
||||
DefaultModelsExpandDepth int
|
||||
DeepLinking bool
|
||||
PersistAuthorization bool
|
||||
}
|
||||
|
||||
// Config stores ginSwagger configuration variables.
|
||||
type Config struct {
|
||||
//The url pointing to API definition (normally swagger.json or swagger.yaml). Default is `doc.json`.
|
||||
// The url pointing to API definition (normally swagger.json or swagger.yaml). Default is `doc.json`.
|
||||
URL string
|
||||
DeepLinking bool
|
||||
DocExpansion string
|
||||
DefaultModelsExpandDepth int
|
||||
InstanceName string
|
||||
Title string
|
||||
DefaultModelsExpandDepth int
|
||||
DeepLinking bool
|
||||
PersistAuthorization bool
|
||||
}
|
||||
|
||||
// Convert the config to a swagger one in order to fill unexposed template values.
|
||||
func (c Config) ToSwaggerConfig() swaggerConfig {
|
||||
func (config Config) toSwaggerConfig() swaggerConfig {
|
||||
return swaggerConfig{
|
||||
URL: c.URL,
|
||||
DeepLinking: c.DeepLinking,
|
||||
DocExpansion: c.DocExpansion,
|
||||
DefaultModelsExpandDepth: c.DefaultModelsExpandDepth,
|
||||
Oauth2RedirectURL: template.JS(
|
||||
"`${window.location.protocol}//${window.location.host}$" +
|
||||
"{window.location.pathname.split('/').slice(0, window.location.pathname.split('/').length - 1).join('/')}" +
|
||||
"/oauth2-redirect.html`",
|
||||
),
|
||||
Title: c.Title,
|
||||
PersistAuthorization: c.PersistAuthorization,
|
||||
URL: config.URL,
|
||||
DeepLinking: config.DeepLinking,
|
||||
DocExpansion: config.DocExpansion,
|
||||
DefaultModelsExpandDepth: config.DefaultModelsExpandDepth,
|
||||
Oauth2RedirectURL: "`${window.location.protocol}//${window.location.host}$" +
|
||||
"{window.location.pathname.split('/').slice(0, window.location.pathname.split('/').length - 1).join('/')}" +
|
||||
"/oauth2-redirect.html`",
|
||||
Title: config.Title,
|
||||
PersistAuthorization: config.PersistAuthorization,
|
||||
}
|
||||
}
|
||||
|
||||
// URL presents the url pointing to API definition (normally swagger.json or swagger.yaml).
|
||||
func URL(url string) func(c *Config) {
|
||||
func URL(url string) func(*Config) {
|
||||
return func(c *Config) {
|
||||
c.URL = url
|
||||
}
|
||||
}
|
||||
|
||||
// DocExpansion list, full, none.
|
||||
func DocExpansion(docExpansion string) func(c *Config) {
|
||||
func DocExpansion(docExpansion string) func(*Config) {
|
||||
return func(c *Config) {
|
||||
c.DocExpansion = docExpansion
|
||||
}
|
||||
}
|
||||
|
||||
// DeepLinking set the swagger deeplinking configuration
|
||||
func DeepLinking(deepLinking bool) func(c *Config) {
|
||||
// DeepLinking set the swagger deep linking configuration.
|
||||
func DeepLinking(deepLinking bool) func(*Config) {
|
||||
return func(c *Config) {
|
||||
c.DeepLinking = deepLinking
|
||||
}
|
||||
@@ -76,74 +73,76 @@ func DeepLinking(deepLinking bool) func(c *Config) {
|
||||
|
||||
// DefaultModelsExpandDepth set the default expansion depth for models
|
||||
// (set to -1 completely hide the models).
|
||||
func DefaultModelsExpandDepth(depth int) func(c *Config) {
|
||||
func DefaultModelsExpandDepth(depth int) func(*Config) {
|
||||
return func(c *Config) {
|
||||
c.DefaultModelsExpandDepth = depth
|
||||
}
|
||||
}
|
||||
|
||||
// InstanceName set the instance name that was used to generate the swagger documents.
|
||||
// InstanceName set the instance name that was used to generate the swagger documents
|
||||
// Defaults to swag.Name ("swagger").
|
||||
func InstanceName(name string) func(c *Config) {
|
||||
func InstanceName(name string) func(*Config) {
|
||||
return func(c *Config) {
|
||||
c.InstanceName = name
|
||||
}
|
||||
}
|
||||
|
||||
// If set to true, it persists authorization data and it would not be lost on browser close/refresh
|
||||
// Defaults to false
|
||||
func PersistAuthorization(persistAuthorization bool) func(c *Config) {
|
||||
// PersistAuthorization Persist authorization information over browser close/refresh.
|
||||
// Defaults to false.
|
||||
func PersistAuthorization(persistAuthorization bool) func(*Config) {
|
||||
return func(c *Config) {
|
||||
c.PersistAuthorization = persistAuthorization
|
||||
}
|
||||
}
|
||||
|
||||
// WrapHandler wraps `http.Handler` into `gin.HandlerFunc`.
|
||||
func WrapHandler(h *webdav.Handler, confs ...func(c *Config)) gin.HandlerFunc {
|
||||
defaultConfig := &Config{
|
||||
func WrapHandler(handler *webdav.Handler, options ...func(*Config)) gin.HandlerFunc {
|
||||
var config = Config{
|
||||
URL: "doc.json",
|
||||
DeepLinking: true,
|
||||
DocExpansion: "list",
|
||||
DefaultModelsExpandDepth: 1,
|
||||
InstanceName: swag.Name,
|
||||
Title: "Swagger UI",
|
||||
DefaultModelsExpandDepth: 1,
|
||||
DeepLinking: true,
|
||||
PersistAuthorization: false,
|
||||
}
|
||||
|
||||
for _, c := range confs {
|
||||
c(defaultConfig)
|
||||
for _, c := range options {
|
||||
c(&config)
|
||||
}
|
||||
|
||||
return CustomWrapHandler(defaultConfig, h)
|
||||
return CustomWrapHandler(&config, handler)
|
||||
}
|
||||
|
||||
// CustomWrapHandler wraps `http.Handler` into `gin.HandlerFunc`
|
||||
// CustomWrapHandler wraps `http.Handler` into `gin.HandlerFunc`.
|
||||
func CustomWrapHandler(config *Config, handler *webdav.Handler) gin.HandlerFunc {
|
||||
var once sync.Once
|
||||
|
||||
if config.InstanceName == "" {
|
||||
config.InstanceName = swag.Name
|
||||
}
|
||||
|
||||
if config.Title == "" {
|
||||
config.Title = "Swagger UI"
|
||||
}
|
||||
|
||||
// create a template with name
|
||||
t := template.New("swagger_index.html")
|
||||
index, _ := t.Parse(swagger_index_templ)
|
||||
index, _ := template.New("swagger_index.html").Parse(swaggerIndexTpl)
|
||||
|
||||
var rexp = regexp.MustCompile(`(.*)(index\.html|doc\.json|favicon-16x16\.png|favicon-32x32\.png|/oauth2-redirect\.html|swagger-ui\.css|swagger-ui\.css\.map|swagger-ui\.js|swagger-ui\.js\.map|swagger-ui-bundle\.js|swagger-ui-bundle\.js\.map|swagger-ui-standalone-preset\.js|swagger-ui-standalone-preset\.js\.map)[\?|.]*`)
|
||||
var matcher = regexp.MustCompile(`(.*)(index\.html|doc\.json|favicon-16x16\.png|favicon-32x32\.png|/oauth2-redirect\.html|swagger-ui\.css|swagger-ui\.css\.map|swagger-ui\.js|swagger-ui\.js\.map|swagger-ui-bundle\.js|swagger-ui-bundle\.js\.map|swagger-ui-standalone-preset\.js|swagger-ui-standalone-preset\.js\.map)[?|.]*`)
|
||||
|
||||
return func(ctx *gin.Context) {
|
||||
if ctx.Request.Method != http.MethodGet {
|
||||
ctx.AbortWithStatus(http.StatusMethodNotAllowed)
|
||||
|
||||
return func(c *gin.Context) {
|
||||
if c.Request.Method != http.MethodGet {
|
||||
c.AbortWithStatus(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
matches := rexp.FindStringSubmatch(c.Request.RequestURI)
|
||||
matches := matcher.FindStringSubmatch(ctx.Request.RequestURI)
|
||||
|
||||
if len(matches) != 3 {
|
||||
c.Status(http.StatusNotFound)
|
||||
_, _ = c.Writer.Write([]byte("404 page not found"))
|
||||
ctx.String(http.StatusNotFound, http.StatusText(http.StatusNotFound))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -154,39 +153,39 @@ func CustomWrapHandler(config *Config, handler *webdav.Handler) gin.HandlerFunc
|
||||
|
||||
switch filepath.Ext(path) {
|
||||
case ".html":
|
||||
c.Header("Content-Type", "text/html; charset=utf-8")
|
||||
ctx.Header("Content-Type", "text/html; charset=utf-8")
|
||||
case ".css":
|
||||
c.Header("Content-Type", "text/css; charset=utf-8")
|
||||
ctx.Header("Content-Type", "text/css; charset=utf-8")
|
||||
case ".js":
|
||||
c.Header("Content-Type", "application/javascript")
|
||||
ctx.Header("Content-Type", "application/javascript")
|
||||
case ".png":
|
||||
c.Header("Content-Type", "image/png")
|
||||
ctx.Header("Content-Type", "image/png")
|
||||
case ".json":
|
||||
c.Header("Content-Type", "application/json; charset=utf-8")
|
||||
ctx.Header("Content-Type", "application/json; charset=utf-8")
|
||||
}
|
||||
|
||||
switch path {
|
||||
case "index.html":
|
||||
_ = index.Execute(c.Writer, config.ToSwaggerConfig())
|
||||
_ = index.Execute(ctx.Writer, config.toSwaggerConfig())
|
||||
case "doc.json":
|
||||
doc, err := swag.ReadDoc(config.InstanceName)
|
||||
if err != nil {
|
||||
c.AbortWithStatus(http.StatusInternalServerError)
|
||||
ctx.AbortWithStatus(http.StatusInternalServerError)
|
||||
|
||||
return
|
||||
}
|
||||
_, _ = c.Writer.Write([]byte(doc))
|
||||
|
||||
ctx.String(http.StatusOK, doc)
|
||||
default:
|
||||
handler.ServeHTTP(c.Writer, c.Request)
|
||||
handler.ServeHTTP(ctx.Writer, ctx.Request)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DisablingWrapHandler turn handler off
|
||||
// if specified environment variable passed
|
||||
func DisablingWrapHandler(h *webdav.Handler, envName string) gin.HandlerFunc {
|
||||
eFlag := os.Getenv(envName)
|
||||
if eFlag != "" {
|
||||
// if specified environment variable passed.
|
||||
func DisablingWrapHandler(handler *webdav.Handler, envName string) gin.HandlerFunc {
|
||||
if os.Getenv(envName) != "" {
|
||||
return func(c *gin.Context) {
|
||||
// Simulate behavior when route unspecified and
|
||||
// return 404 HTTP code
|
||||
@@ -194,14 +193,13 @@ func DisablingWrapHandler(h *webdav.Handler, envName string) gin.HandlerFunc {
|
||||
}
|
||||
}
|
||||
|
||||
return WrapHandler(h)
|
||||
return WrapHandler(handler)
|
||||
}
|
||||
|
||||
// DisablingCustomWrapHandler turn handler off
|
||||
// if specified environment variable passed
|
||||
func DisablingCustomWrapHandler(config *Config, h *webdav.Handler, envName string) gin.HandlerFunc {
|
||||
eFlag := os.Getenv(envName)
|
||||
if eFlag != "" {
|
||||
// if specified environment variable passed.
|
||||
func DisablingCustomWrapHandler(config *Config, handler *webdav.Handler, envName string) gin.HandlerFunc {
|
||||
if os.Getenv(envName) != "" {
|
||||
return func(c *gin.Context) {
|
||||
// Simulate behavior when route unspecified and
|
||||
// return 404 HTTP code
|
||||
@@ -209,10 +207,10 @@ func DisablingCustomWrapHandler(config *Config, h *webdav.Handler, envName strin
|
||||
}
|
||||
}
|
||||
|
||||
return CustomWrapHandler(config, h)
|
||||
return CustomWrapHandler(config, handler)
|
||||
}
|
||||
|
||||
const swagger_index_templ = `<!-- HTML for static distribution bundle build -->
|
||||
const swaggerIndexTpl = `<!-- HTML for static distribution bundle build -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package ginSwagger
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
@@ -42,12 +43,18 @@ func TestWrapCustomHandler(t *testing.T) {
|
||||
|
||||
assert.Equal(t, http.StatusInternalServerError, performRequest(http.MethodGet, "/doc.json", router).Code)
|
||||
|
||||
swag.Register(swag.Name, &mockedSwag{})
|
||||
doc := &mockedSwag{}
|
||||
swag.Register(swag.Name, doc)
|
||||
|
||||
w2 := performRequest(http.MethodGet, "/doc.json", router)
|
||||
assert.Equal(t, http.StatusOK, w2.Code)
|
||||
assert.Equal(t, w2.Header()["Content-Type"][0], "application/json; charset=utf-8")
|
||||
|
||||
// Perform body rendering validation
|
||||
w2Body, err := ioutil.ReadAll(w2.Body)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, doc.ReadDoc(), string(w2Body))
|
||||
|
||||
w3 := performRequest(http.MethodGet, "/favicon-16x16.png", router)
|
||||
assert.Equal(t, http.StatusOK, w3.Code)
|
||||
assert.Equal(t, w3.Header()["Content-Type"][0], "image/png")
|
||||
@@ -85,10 +92,10 @@ func TestDisablingWrapHandler(t *testing.T) {
|
||||
|
||||
router.GET("/disabling/*any", DisablingWrapHandler(swaggerFiles.Handler, disablingKey))
|
||||
|
||||
assert.Equal(t, 404, performRequest(http.MethodGet, "/disabling/index.html", router).Code)
|
||||
assert.Equal(t, 404, performRequest(http.MethodGet, "/disabling/doc.json", router).Code)
|
||||
assert.Equal(t, 404, performRequest(http.MethodGet, "/disabling/oauth2-redirect.html", router).Code)
|
||||
assert.Equal(t, 404, performRequest(http.MethodGet, "/disabling/notfound", router).Code)
|
||||
assert.Equal(t, http.StatusNotFound, performRequest(http.MethodGet, "/disabling/index.html", router).Code)
|
||||
assert.Equal(t, http.StatusNotFound, performRequest(http.MethodGet, "/disabling/doc.json", router).Code)
|
||||
assert.Equal(t, http.StatusNotFound, performRequest(http.MethodGet, "/disabling/oauth2-redirect.html", router).Code)
|
||||
assert.Equal(t, http.StatusNotFound, performRequest(http.MethodGet, "/disabling/notfound", router).Code)
|
||||
}
|
||||
|
||||
func TestDisablingCustomWrapHandler(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user