Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

added security definition description #1174

Merged
merged 11 commits into from Apr 19, 2022
30 changes: 15 additions & 15 deletions README.md
Expand Up @@ -9,7 +9,7 @@
[![Go Report Card](https://goreportcard.com/badge/github.com/swaggo/swag)](https://goreportcard.com/report/github.com/swaggo/swag)
[![codebeat badge](https://codebeat.co/badges/71e2f5e5-9e6b-405d-baf9-7cc8b5037330)](https://codebeat.co/projects/github-com-swaggo-swag-master)
[![Go Doc](https://godoc.org/github.com/swaggo/swagg?status.svg)](https://godoc.org/github.com/swaggo/swag)
[![Backers on Open Collective](https://opencollective.com/swag/backers/badge.svg)](#backers)
[![Backers on Open Collective](https://opencollective.com/swag/backers/badge.svg)](#backers)
[![Sponsors on Open Collective](https://opencollective.com/swag/sponsors/badge.svg)](#sponsors) [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fswaggo%2Fswag.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fswaggo%2Fswag?ref=badge_shield)
[![Release](https://img.shields.io/github/release/swaggo/swag.svg?style=flat-square)](https://github.com/swaggo/swag/releases)

Expand All @@ -30,7 +30,7 @@ Swag converts Go annotations to Swagger Documentation 2.0. We've created a varie
- [Descriptions over multiple lines](#descriptions-over-multiple-lines)
- [User defined structure with an array type](#user-defined-structure-with-an-array-type)
- [Model composition in response](#model-composition-in-response)
- [Add a headers in response](#add-a-headers-in-response)
- [Add a headers in response](#add-a-headers-in-response)
- [Use multiple path params](#use-multiple-path-params)
- [Example value of struct](#example-value-of-struct)
- [SchemaExample of body](#schemaexample-of-body)
Expand Down Expand Up @@ -193,7 +193,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/swaggo/files"
"github.com/swaggo/gin-swagger"

"./docs" // docs is generated by Swag CLI, you have to import it.
)

Expand All @@ -212,7 +212,7 @@ func main() {
docs.SwaggerInfo.Host = "petstore.swagger.io"
docs.SwaggerInfo.BasePath = "/v2"
docs.SwaggerInfo.Schemes = []string{"http", "https"}

r := gin.New()

// use ginSwagger middleware to serve the API docs
Expand Down Expand Up @@ -298,10 +298,10 @@ $ swag init

## The swag formatter

The Swag Comments can be automatically formatted, just like 'go fmt'.
The Swag Comments can be automatically formatted, just like 'go fmt'.
Find the result of formatting [here](https://github.com/swaggo/swag/tree/master/example/celler).

Usage:
Usage:
```shell
swag fmt
```
Expand Down Expand Up @@ -444,11 +444,11 @@ Besides that, `swag` also accepts aliases for some MIME Types as follows:
| annotation | description | parameters | example |
|------------|-------------|------------|---------|
| securitydefinitions.basic | [Basic](https://swagger.io/docs/specification/2-0/authentication/basic-authentication/) auth. | | // @securityDefinitions.basic BasicAuth |
| securitydefinitions.apikey | [API key](https://swagger.io/docs/specification/2-0/authentication/api-keys/) auth. | in, name | // @securityDefinitions.apikey ApiKeyAuth |
| securitydefinitions.oauth2.application | [OAuth2 application](https://swagger.io/docs/specification/authentication/oauth2/) auth. | tokenUrl, scope | // @securitydefinitions.oauth2.application OAuth2Application |
| securitydefinitions.oauth2.implicit | [OAuth2 implicit](https://swagger.io/docs/specification/authentication/oauth2/) auth. | authorizationUrl, scope | // @securitydefinitions.oauth2.implicit OAuth2Implicit |
| securitydefinitions.oauth2.password | [OAuth2 password](https://swagger.io/docs/specification/authentication/oauth2/) auth. | tokenUrl, scope | // @securitydefinitions.oauth2.password OAuth2Password |
| securitydefinitions.oauth2.accessCode | [OAuth2 access code](https://swagger.io/docs/specification/authentication/oauth2/) auth. | tokenUrl, authorizationUrl, scope | // @securitydefinitions.oauth2.accessCode OAuth2AccessCode |
| securitydefinitions.apikey | [API key](https://swagger.io/docs/specification/2-0/authentication/api-keys/) auth. | in, name, sec.def.description | // @securityDefinitions.apikey ApiKeyAuth |
| securitydefinitions.oauth2.application | [OAuth2 application](https://swagger.io/docs/specification/authentication/oauth2/) auth. | tokenUrl, scope, sec.def.description | // @securitydefinitions.oauth2.application OAuth2Application |
| securitydefinitions.oauth2.implicit | [OAuth2 implicit](https://swagger.io/docs/specification/authentication/oauth2/) auth. | authorizationUrl, scope, sec.def.description | // @securitydefinitions.oauth2.implicit OAuth2Implicit |
| securitydefinitions.oauth2.password | [OAuth2 password](https://swagger.io/docs/specification/authentication/oauth2/) auth. | tokenUrl, scope, sec.def.description | // @securitydefinitions.oauth2.password OAuth2Password |
| securitydefinitions.oauth2.accessCode | [OAuth2 access code](https://swagger.io/docs/specification/authentication/oauth2/) auth. | tokenUrl, authorizationUrl, scope, sec.def.description | // @securitydefinitions.oauth2.accessCode OAuth2AccessCode |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update sec.def.description with "description" for the parameter column and add also the "description" feature in the example column.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added the example on the table below where the parameter annotation | example lives as I cannot do line breaks on the example cell of the mentioned table. Hope that is ok.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ubogdan , as sec.def.description is a "line" parameter such as header, in, scopes etc; I had to name it in the mentioned way because if I named it description it will override (or take) the description at the general API info level.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can of course change it to x-description as well as an alternative :)

Copy link
Contributor

@ubogdan ubogdan Apr 19, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the following definition

// @securityDefinitions.basic BasicAuth
// @securityDefinitions.apikey ApiKeyAuth
// @in header
// @name Authorization
// @securitydefinitions.oauth2.application OAuth2Application
// @tokenUrl https://example.com/oauth/token
// @scope.write Grants write access
// @scope.admin Grants read and write access to administrative information
// @securitydefinitions.oauth2.implicit OAuth2Implicit
// @authorizationUrl https://example.com/oauth/authorize
// @scope.write Grants write access
// @scope.admin Grants read and write access to administrative information
// @securitydefinitions.oauth2.password OAuth2Password
// @tokenUrl https://example.com/oauth/token
// @scope.read Grants read access
// @scope.write Grants write access
// @scope.admin Grants read and write access to administrative information
// @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

I expect to see something like

// @securitydefinitions.oauth2.application  OAuth2Application
// @tokenUrl                                https://example.com/oauth/token
// @scope.write                             Grants write access
// @scope.admin                             Grants read and write access to administrative information
// @description                             Perform OAUTH2 at application level

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can do that :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You made it @security.definition.description instead of @description ...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, did not see your edited comment 馃槄
I will try to make it work with just description but as I said before, when I tried it overlapped with the @description that you put to the general API info. I will debug and see if I can solve that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current way it works is the following, given these lines:

// @description this API is a demo
// @securitydefinitions.oauth2.application  OAuth2Application
// @description                             Perform OAUTH2 at application level

The code will:

  • Range every comment
  • For the first line it will set the API description to this API is a demo
  • For the second line it will range all comments starting from comments[i+1:] in other words skipping the current. This will effectively go through the @description and set it correctly.
  • For the third line it will set the API description (and override) to Perform OAUTH2 at application level

The issue is that the parseSecAttr function is iterating all the lines below until it finds another @securitydefinitions.. But then, the lines that parseSecAttr iterated, will be iterated back again by the main for buckle.

This is why I changed the name to something different. I can potentially see how to make the main buckle not go through the lines that the security definition already did, but that might introduce lots of changes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ubogdan check it now, with the changes I have done it is working correctly and the main buckle does not re-iterate the lines that the security definitions already iterated :)



| parameters annotation | example |
Expand Down Expand Up @@ -487,7 +487,7 @@ type Foo struct {

Field Name | Type | Description
---|:---:|---
<a name="validate"></a>validate | `string` | Determines the validation for the parameter. Possible values are: `required`.
<a name="validate"></a>validate | `string` | Determines the validation for the parameter. Possible values are: `required`.
<a name="parameterDefault"></a>default | * | Declares the value of the parameter that the server will use if none is provided, for example a "count" to control the number of results per page might default to 100 if not supplied by the client in the request. (Note: "default" has no meaning for required parameters.) See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-6.2. Unlike JSON Schema this value MUST conform to the defined [`type`](#parameterType) for this parameter.
<a name="parameterMaximum"></a>maximum | `number` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.1.2.
<a name="parameterMinimum"></a>minimum | `number` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.1.3.
Expand All @@ -512,7 +512,7 @@ Field Name | Type | Description

### Descriptions over multiple lines

You can add descriptions spanning multiple lines in either the general api description or routes definitions like so:
You can add descriptions spanning multiple lines in either the general api description or routes definitions like so:

```go
// @description This is the first line
Expand Down Expand Up @@ -561,7 +561,7 @@ type Order struct { //in `proto` package
@success 200 {object} jsonresult.JSONResult{data=[]string} "desc"
```

- overriding multiple fields. field will be added if not exists
- overriding multiple fields. field will be added if not exists
```go
@success 200 {object} jsonresult.JSONResult{data1=string,data2=[]string,data3=proto.Order,data4=[]proto.Order} "desc"
```
Expand Down Expand Up @@ -751,7 +751,7 @@ Rendered:
"id": "integer"
}
```


### Use swaggerignore tag to exclude a field

Expand Down
35 changes: 28 additions & 7 deletions parser.go
Expand Up @@ -472,35 +472,45 @@ func parseGeneralAPIInfo(parser *Parser, comments []string) error {
case "@securitydefinitions.basic":
parser.swagger.SecurityDefinitions[value] = spec.BasicAuth()
case "@securitydefinitions.apikey":
attrMap, _, _, err := parseSecAttr(attribute, []string{"@in", "@name"}, comments[i+1:])
attrMap, _, extensions, err := parseSecAttr(attribute, []string{"@in", "@name"}, comments[i+1:])
if err != nil {
return err
}
parser.swagger.SecurityDefinitions[value] = spec.APIKeyAuth(attrMap["@name"], attrMap["@in"])
secDef := spec.APIKeyAuth(attrMap["@name"], attrMap["@in"])
tryAddDescription(secDef, extensions)
parser.swagger.SecurityDefinitions[value] = secDef
case "@securitydefinitions.oauth2.application":
pmorelli92 marked this conversation as resolved.
Show resolved Hide resolved
attrMap, scopes, extensions, err := parseSecAttr(attribute, []string{"@tokenurl"}, comments[i+1:])
if err != nil {
return err
}
parser.swagger.SecurityDefinitions[value] = secOAuth2Application(attrMap["@tokenurl"], scopes, extensions)
secDef := secOAuth2Application(attrMap["@tokenurl"], scopes, extensions)
tryAddDescription(secDef, extensions)
parser.swagger.SecurityDefinitions[value] = secDef
case "@securitydefinitions.oauth2.implicit":
attrs, scopes, ext, err := parseSecAttr(attribute, []string{"@authorizationurl"}, comments[i+1:])
if err != nil {
return err
}
parser.swagger.SecurityDefinitions[value] = secOAuth2Implicit(attrs["@authorizationurl"], scopes, ext)
secDef := secOAuth2Implicit(attrs["@authorizationurl"], scopes, ext)
tryAddDescription(secDef, ext)
parser.swagger.SecurityDefinitions[value] = secDef
case "@securitydefinitions.oauth2.password":
attrs, scopes, ext, err := parseSecAttr(attribute, []string{"@tokenurl"}, comments[i+1:])
if err != nil {
return err
}
parser.swagger.SecurityDefinitions[value] = secOAuth2Password(attrs["@tokenurl"], scopes, ext)
secDef := secOAuth2Password(attrs["@tokenurl"], scopes, ext)
tryAddDescription(secDef, ext)
parser.swagger.SecurityDefinitions[value] = secDef
case "@securitydefinitions.oauth2.accesscode":
attrs, scopes, ext, err := parseSecAttr(attribute, []string{"@tokenurl", "@authorizationurl"}, comments[i+1:])
if err != nil {
return err
}
parser.swagger.SecurityDefinitions[value] = secOAuth2AccessToken(attrs["@authorizationurl"], attrs["@tokenurl"], scopes, ext)
secDef := secOAuth2AccessToken(attrs["@authorizationurl"], attrs["@tokenurl"], scopes, ext)
tryAddDescription(secDef, ext)
parser.swagger.SecurityDefinitions[value] = secDef
case "@query.collection.format":
parser.collectionFormatInQuery = value
default:
Expand Down Expand Up @@ -549,6 +559,14 @@ func parseGeneralAPIInfo(parser *Parser, comments []string) error {
return nil
}

func tryAddDescription(spec *spec.SecurityScheme, extensions map[string]interface{}) {
if val, ok := extensions["@sec.def.description"]; ok {
if str, ok := val.(string); ok {
spec.Description = str
}
}
}

// ParseAcceptComment parses comment for given `accept` comment string.
func (parser *Parser) ParseAcceptComment(commentLine string) error {
return parseMimeTypeList(commentLine, &parser.swagger.Consumes, "%v accept type can't be accepted")
Expand Down Expand Up @@ -581,7 +599,6 @@ func parseSecAttr(context string, search []string, lines []string) (map[string]s
for _, findterm := range search {
if securityAttr == findterm {
attrMap[securityAttr] = strings.TrimSpace(v[len(securityAttr):])

continue
}
}
Expand All @@ -596,6 +613,10 @@ func parseSecAttr(context string, search []string, lines []string) (map[string]s
// Add the custom attribute without the @
extensions[securityAttr[1:]] = strings.TrimSpace(v[len(securityAttr):])
}
// Not mandatory field
if securityAttr == "@sec.def.description" {
extensions[securityAttr] = strings.TrimSpace(v[len(securityAttr):])
}
// next securityDefinitions
if strings.Index(securityAttr, "@securitydefinitions.") == 0 {
break
Expand Down
4 changes: 3 additions & 1 deletion parser_test.go
Expand Up @@ -538,12 +538,14 @@ func TestParser_ParseGeneralAPISecurity(t *testing.T) {
err := parseGeneralAPIInfo(parser, []string{
"@securitydefinitions.apikey ApiKey",
"@in header",
"@name X-API-KEY"})
"@name X-API-KEY",
"@sec.def.description some"})
assert.NoError(t, err)

b, _ := json.MarshalIndent(parser.GetSwagger().SecurityDefinitions, "", " ")
expected := `{
"ApiKey": {
"description": "some",
"type": "apiKey",
"name": "X-API-KEY",
"in": "header"
Expand Down
8 changes: 8 additions & 0 deletions swagger_test.go
Expand Up @@ -146,6 +146,14 @@ var doc = `{
}
}
}
},
"securityDefinitions": {
"ApiKey": {
"description: "some",
"type": "apiKey",
"name": "X-API-KEY",
"in": "header"
}
}
}`

Expand Down