Skip to content

Commit

Permalink
feat: support @x- attributes for operations (#452)
Browse files Browse the repository at this point in the history
  • Loading branch information
yutopp authored and easonlin404 committed Jul 16, 2019
1 parent 6de832a commit 4642ffd
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 21 deletions.
29 changes: 15 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -348,20 +348,21 @@ When a short string in your documentation is insufficient, or you need images, c
[celler/controller](https://github.com/swaggo/swag/tree/master/example/celler/controller)


| annotation | description |
|--------------------|----------------------------------------------------------------------------------------------------------------------------|
| description | A verbose explanation of the operation behavior. |
| id | A unique string used to identify the operation. Must be unique among all API operations. |
| tags | A list of tags to each API operation that separated by commas. |
| summary | A short summary of what the operation does. |
| accept | A list of MIME types the APIs can consume. Value MUST be as described under [Mime Types](#mime-types). |
| produce | A list of MIME types the APIs can produce. Value MUST be as described under [Mime Types](#mime-types). |
| param | Parameters that separated by spaces. `param name`,`param type`,`data type`,`is mandatory?`,`comment` `attribute(optional)` |
| security | [Security](#security) to each API operation. |
| success | Success response that separated by spaces. `return code`,`{param type}`,`data type`,`comment` |
| failure | Failure response that separated by spaces. `return code`,`{param type}`,`data type`,`comment` |
| header | Header in response that separated by spaces. `return code`,`{param type}`,`data type`,`comment` |
| router | Path definition that separated by spaces. `path`,`[httpMethod]` |
| annotation | description |
|-------------|----------------------------------------------------------------------------------------------------------------------------|
| description | A verbose explanation of the operation behavior. |
| id | A unique string used to identify the operation. Must be unique among all API operations. |
| tags | A list of tags to each API operation that separated by commas. |
| summary | A short summary of what the operation does. |
| accept | A list of MIME types the APIs can consume. Value MUST be as described under [Mime Types](#mime-types). |
| produce | A list of MIME types the APIs can produce. Value MUST be as described under [Mime Types](#mime-types). |
| param | Parameters that separated by spaces. `param name`,`param type`,`data type`,`is mandatory?`,`comment` `attribute(optional)` |
| security | [Security](#security) to each API operation. |
| success | Success response that separated by spaces. `return code`,`{param type}`,`data type`,`comment` |
| failure | Failure response that separated by spaces. `return code`,`{param type}`,`data type`,`comment` |
| header | Header in response that separated by spaces. `return code`,`{param type}`,`data type`,`comment` |
| router | Path definition that separated by spaces. `path`,`[httpMethod]` |
| x-name | The extension key, must be start by x- and take only json value. |

## Mime Types

Expand Down
18 changes: 17 additions & 1 deletion operation.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package swag

import (
"encoding/json"
"fmt"
"go/ast"
goparser "go/parser"
Expand Down Expand Up @@ -64,7 +65,8 @@ func (operation *Operation) ParseComment(comment string, astFile *ast.File) erro

attribute := strings.Fields(commentLine)[0]
lineRemainder := strings.TrimSpace(commentLine[len(attribute):])
switch strings.ToLower(attribute) {
lowerAttribute := strings.ToLower(attribute)
switch lowerAttribute {
case "@description":
if operation.Description == "" {
operation.Description = lineRemainder
Expand Down Expand Up @@ -112,6 +114,20 @@ func (operation *Operation) ParseComment(comment string, astFile *ast.File) erro
case "@deprecated":
operation.Deprecate()
}

// parsing specific meta data extensions
if strings.HasPrefix(lowerAttribute, "@x-") {
if len(lineRemainder) == 0 {
return errors.New(attribute + " need a value")
}

var valueJSON interface{}
if err := json.Unmarshal([]byte(lineRemainder), &valueJSON); err != nil {
return errors.New(attribute + " need a valid json value")
}
operation.Operation.AddExtension(attribute[1:], valueJSON) // Trim "@" at head
}

return nil
}

Expand Down
43 changes: 43 additions & 0 deletions operation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -746,3 +746,46 @@ func TestParseDeprecationDescription(t *testing.T) {
t.Error("Failed to parse @deprecated comment")
}
}

func TestParseExtentions(t *testing.T) {
// Fail if there are no args for attributes.
{
comment := `@x-amazon-apigateway-integration`
operation := NewOperation()
operation.parser = New()

err := operation.ParseComment(comment, nil)
assert.EqualError(t, err, "@x-amazon-apigateway-integration need a value")
}

// Fail if args of attributes are broken.
{
comment := `@x-amazon-apigateway-integration ["broken"}]`
operation := NewOperation()
operation.parser = New()

err := operation.ParseComment(comment, nil)
assert.EqualError(t, err, "@x-amazon-apigateway-integration need a valid json value")
}

// OK
{
comment := `@x-amazon-apigateway-integration {"uri": "${some_arn}", "passthroughBehavior": "when_no_match", "httpMethod": "POST", "type": "aws_proxy"}`
operation := NewOperation()
operation.parser = New()

err := operation.ParseComment(comment, nil)
assert.NoError(t, err)

expected := `{
"x-amazon-apigateway-integration": {
"httpMethod": "POST",
"passthroughBehavior": "when_no_match",
"type": "aws_proxy",
"uri": "${some_arn}"
}
}`
b, _ := json.MarshalIndent(operation, "", " ")
assert.Equal(t, expected, string(b))
}
}
14 changes: 11 additions & 3 deletions testdata/simple2/docs/docs.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
// This file was generated by swaggo/swag at
// 2019-06-25 15:43:55.76642234 +0200 CEST m=+2.220403193
// 2019-07-15 21:17:57.384551624 +0900 JST m=+0.027691337

package docs

import (
"bytes"
"encoding/json"

"github.com/alecthomas/template"
"github.com/swaggo/swag"
)

var doc = `{
"schemes": {{ marshal .Schemes }},
"swagger": "2.0",
"info": {
"description": "This is a sample server Petstore server.",
Expand Down Expand Up @@ -494,17 +496,23 @@ type swaggerInfo struct {
Version string
Host string
BasePath string
Schemes []string
Title string
Description string
}

// SwaggerInfo holds exported Swagger Info so clients can modify it
var SwaggerInfo swaggerInfo
var SwaggerInfo = swaggerInfo{Schemes: []string{}}

type s struct{}

func (s *s) ReadDoc() string {
t, err := template.New("swagger_info").Parse(doc)
t, err := template.New("swagger_info").Funcs(template.FuncMap{
"marshal": func(v interface{}) string {
a, _ := json.Marshal(v)
return string(a)
},
}).Parse(doc)
if err != nil {
return doc
}
Expand Down
14 changes: 11 additions & 3 deletions testdata/simple3/docs/docs.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
// This file was generated by swaggo/swag at
// 2019-06-25 15:43:56.877451901 +0200 CEST m=+3.331432757
// 2019-07-15 21:17:57.389489669 +0900 JST m=+0.032629371

package docs

import (
"bytes"
"encoding/json"

"github.com/alecthomas/template"
"github.com/swaggo/swag"
)

var doc = `{
"schemes": {{ marshal .Schemes }},
"swagger": "2.0",
"info": {
"description": "This is a sample server Petstore server.",
Expand Down Expand Up @@ -467,17 +469,23 @@ type swaggerInfo struct {
Version string
Host string
BasePath string
Schemes []string
Title string
Description string
}

// SwaggerInfo holds exported Swagger Info so clients can modify it
var SwaggerInfo swaggerInfo
var SwaggerInfo = swaggerInfo{Schemes: []string{}}

type s struct{}

func (s *s) ReadDoc() string {
t, err := template.New("swagger_info").Parse(doc)
t, err := template.New("swagger_info").Funcs(template.FuncMap{
"marshal": func(v interface{}) string {
a, _ := json.Marshal(v)
return string(a)
},
}).Parse(doc)
if err != nil {
return doc
}
Expand Down

0 comments on commit 4642ffd

Please sign in to comment.