Skip to content

Commit

Permalink
feat: implement parsing extension on root level openapi (#416)
Browse files Browse the repository at this point in the history
  • Loading branch information
ymohl-cl authored and easonlin404 committed Jun 28, 2019
1 parent 016b87b commit e3192f3
Show file tree
Hide file tree
Showing 11 changed files with 130 additions and 6 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ import "github.com/swaggo/gin-swagger/swaggerFiles" // swagger embed files
// @authorizationurl https://example.com/oauth/authorize
// @scope.admin Grants read and write access to administrative information
// @x-extension-openapi {"example": "value on a json format"}
func main() {
r := gin.Default()
Expand Down Expand Up @@ -322,6 +324,7 @@ $ swag init
| host | The host (name or ip) serving the API. | // @host localhost:8080 |
| BasePath | The base path on which the API is served. | // @BasePath /api/v1 |
| schemes | The transfer protocol for the operation that separated by spaces. | // @schemes http https |
| x-name | The extension key, must be start by x- and take only json value | // @x-example-key {"key": "value"} |
### Using markdown descriptions
When a short string in your documentation is insufficient, or you need images, code examples and things like that you may want to use markdown descriptions. In order to use markdown descriptions use the following annotations.
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/swaggo/swag
require (
github.com/KyleBanks/depth v1.2.1
github.com/ghodss/yaml v1.0.0
github.com/gin-gonic/gin v1.4.0
github.com/go-openapi/jsonreference v0.19.0
github.com/go-openapi/spec v0.19.0
github.com/pkg/errors v0.8.1
Expand Down
20 changes: 20 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -9,42 +9,60 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 h1:t8FVkw33L+wilf2QiWkw0UV77qRpcH/JHPKGpKa2E8g=
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y=
github.com/gin-gonic/gin v1.4.0 h1:3tMoCCfM7ppqsR0ptz/wi1impNpT7/9wQtMZ8lr1mCQ=
github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
github.com/go-openapi/jsonpointer v0.17.0 h1:nH6xp8XdXHx8dqveo0ZuJBluCO2qGrPbDNZ0dwoRHP0=
github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.19.0 h1:BqWKpV1dFd+AuiKlgtddwVIFQsuMpxfBDBHGfM2yNpk=
github.com/go-openapi/jsonreference v0.19.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/spec v0.19.0 h1:A4SZ6IWh3lnjH0rG0Z5lkxazMGBECtrZcbyYQi+64k4=
github.com/go-openapi/spec v0.19.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/swag v0.17.0 h1:iqrgMg7Q7SvtbWLlltPrkMs0UBJI6oTSs79JFRUi880=
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 h1:2gxZ0XQIU/5z3Z3bUBu+FXuk2pFbkN6tcwi/pjyaDic=
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/swaggo/gin-swagger v1.1.0 h1:ZI6/82S07DkkrMfGKbJhKj1R+QNTICkeAJP06pU36pU=
github.com/swaggo/gin-swagger v1.1.0/go.mod h1:FQlm07YuT1glfN3hQiO11UQ2m39vOCZ/aa3WWr5E+XU=
github.com/swaggo/swag v1.4.0/go.mod h1:hog2WgeMOrQ/LvQ+o1YGTeT+vWVrbi0SiIslBtxKTyM=
github.com/ugorji/go v1.1.4 h1:j4s+tAvLfL3bZyefP2SEWmhBzmuIlH/eqNuPdFPgngw=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/ugorji/go/codec v0.0.0-20181209151446-772ced7fd4c2 h1:EICbibRW4JNKMcY+LsWmuwob+CRS1BmdRdjphAm9mH4=
github.com/ugorji/go/codec v0.0.0-20181209151446-772ced7fd4c2/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c h1:uOCk1iQW6Vc18bnC13MfzScl+wdKBmM9Y9kU7Z83/lw=
Expand All @@ -54,9 +72,11 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190110015856-aa033095749b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468 h1:fTfk6GjmihJbK0mSUFgPPgYpsdmApQ86Mcd4GuKax9U=
golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ=
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
Expand Down
28 changes: 26 additions & 2 deletions parser.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package swag

import (
"encoding/json"
"fmt"
"go/ast"
"go/build"
Expand Down Expand Up @@ -137,6 +138,7 @@ func (parser *Parser) ParseAPI(searchDir string, mainAPIFile string) error {
}

if err := parser.ParseGeneralAPIInfo(path.Join(searchDir, mainAPIFile)); err != nil {
fmt.Println("error: ", err)
return err
}

Expand Down Expand Up @@ -175,6 +177,7 @@ func (parser *Parser) ParseGeneralAPIInfo(mainAPIFile string) error {
for _, comment := range fileTree.Comments {
comments := strings.Split(comment.Text(), "\n")
previousAttribute := ""
// parsing classic meta data model
for _, commentLine := range comments {
attribute := strings.ToLower(strings.Split(commentLine, " ")[0])
multilineBlock := false
Expand Down Expand Up @@ -255,7 +258,6 @@ func (parser *Parser) ParseGeneralAPIInfo(mainAPIFile string) error {
URL: commentInfo,
}
replaceLastTag(parser.swagger.Tags, tag)

case "@tag.docs.description":
commentInfo := strings.TrimSpace(commentLine[len(attribute):])
tag := parser.swagger.Tags[len(parser.swagger.Tags)-1]
Expand All @@ -267,7 +269,29 @@ func (parser *Parser) ParseGeneralAPIInfo(mainAPIFile string) error {
}
previousAttribute = attribute
}

// parsing specific meta data extensions
for _, commentLine := range comments {
prefixExtension := "@x-"
split := strings.Split(commentLine, " ")
if len(split[0]) < len(prefixExtension) {
continue
}
attribute := strings.ToLower(split[0])
switch attribute[:len(prefixExtension)] {
case prefixExtension:
var valueJSON interface{}
split = strings.SplitAfter(commentLine, attribute+" ")
if len(split) < 2 {
return errors.New(attribute + " need a value")
}
extensionName := "x-" + strings.SplitAfter(attribute, prefixExtension)[1]
if err := json.Unmarshal([]byte(split[1]), &valueJSON); err != nil {
return errors.New(attribute + " need a valid json value")
}
parser.swagger.AddExtension(extensionName, valueJSON)
}
}
// parsing specific meta data securities
for i := 0; i < len(comments); i++ {
attribute := strings.ToLower(strings.Split(comments[i], " ")[0])
switch attribute {
Expand Down
44 changes: 42 additions & 2 deletions parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,14 @@ func TestParser_ParseGeneralApiInfo(t *testing.T) {
"write": " Grants write access"
}
}
}
},
"x-google-endpoints": [
{
"allowCors": true,
"name": "name.endpoints.environment.cloud.goog"
}
],
"x-google-marks": "marks values"
}`
gopath := os.Getenv("GOPATH")
assert.NotNil(t, gopath)
Expand Down Expand Up @@ -168,7 +175,14 @@ func TestParser_ParseGeneralApiInfoTemplated(t *testing.T) {
"write": " Grants write access"
}
}
}
},
"x-google-endpoints": [
{
"allowCors": true,
"name": "name.endpoints.environment.cloud.goog"
}
],
"x-google-marks": "marks values"
}`
gopath := os.Getenv("GOPATH")
assert.NotNil(t, gopath)
Expand All @@ -180,6 +194,32 @@ func TestParser_ParseGeneralApiInfoTemplated(t *testing.T) {
assert.Equal(t, expected, string(b))
}

func TestParser_ParseGeneralApiInfoExtensions(t *testing.T) {
// should be return an error because extension value is not a valid json
func() {
expected := "@x-google-endpoints need a valid json value"
gopath := os.Getenv("GOPATH")
assert.NotNil(t, gopath)
p := New()
err := p.ParseGeneralAPIInfo("testdata/extensionsFail1.go")
if assert.Error(t, err) {
assert.Equal(t, expected, err.Error())
}
}()

// should be return an error because extension don't have a value
func() {
expected := "@x-google-endpoints need a value"
gopath := os.Getenv("GOPATH")
assert.NotNil(t, gopath)
p := New()
err := p.ParseGeneralAPIInfo("testdata/extensionsFail2.go")
if assert.Error(t, err) {
assert.Equal(t, expected, err.Error())
}
}()
}

func TestParser_ParseGeneralApiInfoWithOpsInSameFile(t *testing.T) {
expected := `{
"swagger": "2.0",
Expand Down
14 changes: 14 additions & 0 deletions testdata/extensionsFail1.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package main

// @title Swagger Example API
// @version 1.0
// @description This is a sample server Petstore server.
// @description It has a lot of beautiful features.
// @termsOfService http://swagger.io/terms/

// @securitydefinitions.oauth2.accessCode OAuth2AccessCode
// @tokenUrl https://example.com/oauth/token
// @authorizationurl https://example.com/oauth/authorize
// @scope.admin Grants read and write access to administrative information

// @x-google-endpoints ["name":"name.endpoints.environment.cloud.goog","allowCors":true}]
14 changes: 14 additions & 0 deletions testdata/extensionsFail2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package main

// @title Swagger Example API
// @version 1.0
// @description This is a sample server Petstore server.
// @description It has a lot of beautiful features.
// @termsOfService http://swagger.io/terms/

// @securitydefinitions.oauth2.accessCode OAuth2AccessCode
// @tokenUrl https://example.com/oauth/token
// @authorizationurl https://example.com/oauth/authorize
// @scope.admin Grants read and write access to administrative information

// @x-google-endpoints
4 changes: 4 additions & 0 deletions testdata/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,8 @@ package main
// @tokenUrl https://example.com/oauth/token
// @authorizationurl https://example.com/oauth/authorize
// @scope.admin Grants read and write access to administrative information

// @x-google-endpoints [{"name":"name.endpoints.environment.cloud.goog","allowCors":true}]
// @x-google-marks "marks values"

func main() {}
2 changes: 1 addition & 1 deletion testdata/simple2/docs/docs.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
// This file was generated by swaggo/swag at
// 2019-06-12 14:11:08.278195965 +0200 CEST m=+0.065173340
// 2019-06-25 15:43:55.76642234 +0200 CEST m=+2.220403193

package docs

Expand Down
2 changes: 1 addition & 1 deletion testdata/simple3/docs/docs.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
// This file was generated by swaggo/swag at
// 2019-06-12 14:11:08.291157752 +0200 CEST m=+0.078135144
// 2019-06-25 15:43:56.877451901 +0200 CEST m=+3.331432757

package docs

Expand Down
4 changes: 4 additions & 0 deletions testdata/templated.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,8 @@ package main
// @tokenUrl https://example.com/oauth/token
// @authorizationurl https://example.com/oauth/authorize
// @scope.admin Grants read and write access to administrative information

// @x-google-endpoints [{"name":"name.endpoints.environment.cloud.goog","allowCors":true}]
// @x-google-marks "marks values"

func main() {}

0 comments on commit e3192f3

Please sign in to comment.