swag
Swag converts Go annotations to Swagger Documentation 2.0. We've created a variety of plugins for popular Go web frameworks. This allows you to quickly integrate with an existing Go project (using Swagger UI).
Contents
Getting started
-
Add comments to your API source code, See Declarative Comments Format.
-
Download swag by using:
$ go get -u github.com/geeks-accelerator/swag/cmd/swag
To build from source you need Go (1.9 or newer).
Or download a pre-compiled binary from the release page.
- Run
swag init
in the project's root folder which contains the main.go
file. This will parse your comments and generate the required files (docs
folder and docs/docs.go
).
$ swag init
Make sure to import the generated docs/docs.go
so that your specific configuration gets init
'ed. If your General API annotations do not live in main.go
, you can let swag know with -g
flag.
swag init -g http/api.go
swag cli
$ swag init -h
NAME:
swag init - Create docs.go
USAGE:
swag init [command options] [arguments...]
OPTIONS:
--generalInfo value, -g value Go file path in which 'swagger general API Info' is written (default: "main.go")
--dir value, -d value Directory you want to parse (default: "./")
--exclude value Exclude directoies and files, comma separated
--propertyStrategy value, -p value Property Naming Strategy like snakecase,camelcase,pascalcase (default: "camelcase")
--output value, -o value Output directory for all the generated files(swagger.json, swagger.yaml and doc.go) (default: "./docs")
--parseVendor Parse go files in 'vendor' folder, disabled by default
--parseDependency Parse go files in outside dependency folder, disabled by default
How to use it with SaaS Starter Kit
Find the example source code here.
- After using
swag init
to generate Swagger 2.0 docs, import the following packages:
import "./internal/mid/saas-swagger" // Saas Starter Kit middleware
import "github.com/geeks-accelerator/files" // swagger embed files
- Add General API annotations in
main.go
code:
// @title Swagger Example API
// @version 1.0
// @description This is a sample server celler 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
// @host localhost:8080
// @BasePath /api/v1
// @query.collection.format multi
// @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
// @x-extension-openapi {"example": "value on a json format"}
//...
Additionally some general API info can be set dynamically. The generated code package docs
exports SwaggerInfo
variable which we can use to set the title, description, version, host and base path programatically. Example using Gin:
package main
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.
)
// @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
// @termsOfService http://swagger.io/terms/
func main() {
// programatically set swagger info
docs.SwaggerInfo.Title = "Swagger Example API"
docs.SwaggerInfo.Description = "This is a sample server Petstore server."
docs.SwaggerInfo.Version = "1.0"
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
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
r.Run()
}
- Add API Operation annotations in
controller
code
package controller
import (
"fmt"
"net/http"
"strconv"
"github.com/gin-gonic/gin"
"github.com/geeks-accelerator/swag/example/celler/httputil"
"github.com/geeks-accelerator/swag/example/celler/model"
)
// ShowAccount godoc
// @Summary Show a account
// @Description get string by ID
// @ID get-string-by-int
// @Accept json
// @Produce json
// @Param id path int true "Account ID"
// @Success 200 {object} model.Account
// @Header 200 {string} Token "qwerty"
// @Failure 400 {object} httputil.HTTPError
// @Failure 404 {object} httputil.HTTPError
// @Failure 500 {object} httputil.HTTPError
// @Router /accounts/{id} [get]
func (c *Controller) ShowAccount(ctx *gin.Context) {
id := ctx.Param("id")
aid, err := strconv.Atoi(id)
if err != nil {
httputil.NewError(ctx, http.StatusBadRequest, err)
return
}
account, err := model.AccountOne(aid)
if err != nil {
httputil.NewError(ctx, http.StatusNotFound, err)
return
}
ctx.JSON(http.StatusOK, account)
}
// ListAccounts godoc
// @Summary List accounts
// @Description get accounts
// @Accept json
// @Produce json
// @Param q query string false "name search by q"
// @Success 200 {array} model.Account
// @Header 200 {string} Token "qwerty"
// @Failure 400 {object} httputil.HTTPError
// @Failure 404 {object} httputil.HTTPError
// @Failure 500 {object} httputil.HTTPError
// @Router /accounts [get]
func (c *Controller) ListAccounts(ctx *gin.Context) {
q := ctx.Request.URL.Query().Get("q")
accounts, err := model.AccountsAll(q)
if err != nil {
httputil.NewError(ctx, http.StatusNotFound, err)
return
}
ctx.JSON(http.StatusOK, accounts)
}
//...
$ swag init
- Run your app, and browse to http://localhost:8080/swagger/index.html. You will see Swagger 2.0 Api documents as shown below:
Implementation Status
Swagger 2.0 document
- Basic Structure
- API Host and Base Path
- Paths and Operations
- Describing Parameters
- Describing Request Body
- Describing Responses
- MIME Types
- Authentication
- Basic Authentication
- API Keys
- Adding Examples
- File Upload
- Enums
- Grouping Operations With Tags
- Swagger Extensions
General API Info
Example
celler/main.go
annotation |
description |
example |
title |
Required. The title of the application. |
// @title Swagger Example API |
version |
Required. Provides the version of the application API. |
// @version 1.0 |
description |
A short description of the application. |
// @description This is a sample server celler server. |
tag.name |
Name of a tag. |
// @tag.name This is the name of the tag |
tag.description |
Description of the tag |
// @tag.description Cool Description |
tag.docs.url |
Url of the external Documentation of the tag |
// @tag.docs.url https://example.com |
tag.docs.description |
Description of the external Documentation of the tag |
// @tag.docs.description Best example documentation |
termsOfService |
The Terms of Service for the API. |
// @termsOfService http://swagger.io/terms/ |
contact.name |
The contact information for the exposed API. |
// @contact.name API Support |
contact.url |
The URL pointing to the contact information. MUST be in the format of a URL. |
// @contact.url http://www.swagger.io/support |
contact.email |
The email address of the contact person/organization. MUST be in the format of an email address. |
// @contact.email support@swagger.io |
license.name |
Required. The license name used for the API. |
// @license.name Apache 2.0 |
license.url |
A URL to the license used for the API. MUST be in the format of a URL. |
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html |
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 |
query.collection.format |
The default collection(array) param format in query,enums:csv,multi,pipes,tsv,ssv. If not set, csv is the default. |
// @query.collection.format multi |
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.
annotation |
description |
example |
title |
Required. The title of the application. |
// @title Swagger Example API |
version |
Required. Provides the version of the application API. |
// @version 1.0 |
description.markdown |
A short description of the application. Parsed from the api.md file. This is an alternative to @description |
// @description.markdown No value needed, this parses the description from api.md |
tag.name |
Name of a tag. |
// @tag.name This is the name of the tag |
tag.description.markdown |
Description of the tag this is an alternative to tag.description. The description will be read from a file named like tagname.md |
// @tag.description.markdown |
API Operation
Example
celler/controller
annotation |
description |
description |
A verbose explanation of the operation behavior. |
description.markdown |
A short description of the application. The description will be read from a file named like endpointname.md |
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. |
produce |
A list of MIME types the APIs can produce. Value MUST be as described under Mime Types. |
param |
Parameters that separated by spaces. param name ,param type ,data type ,is mandatory? ,comment attribute(optional) |
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
swag
accepts all MIME Types which are in the correct format, that is, match */*
.
Besides that, swag
also accepts aliases for some MIME Types as follows:
Alias |
MIME Type |
json |
application/json |
xml |
text/xml |
plain |
text/plain |
html |
text/html |
mpfd |
multipart/form-data |
x-www-form-urlencoded |
application/x-www-form-urlencoded |
json-api |
application/vnd.api+json |
json-stream |
application/x-json-stream |
octet-stream |
application/octet-stream |
png |
image/png |
jpeg |
image/jpeg |
gif |
image/gif |
Param Type
- query
- path
- header
- body
- formData
Data Type
- string (string)
- integer (int, uint, uint32, uint64)
- number (float32)
- boolean (bool)
- user defined struct
Security
annotation |
description |
parameters |
example |
securitydefinitions.basic |
Basic auth. |
|
// @securityDefinitions.basic BasicAuth |
securitydefinitions.apikey |
API key auth. |
in, name |
// @securityDefinitions.apikey ApiKeyAuth |
securitydefinitions.oauth2.application |
OAuth2 application auth. |
tokenUrl, scope |
// @securitydefinitions.oauth2.application OAuth2Application |
securitydefinitions.oauth2.implicit |
OAuth2 implicit auth. |
authorizationUrl, scope |
// @securitydefinitions.oauth2.implicit OAuth2Implicit |
securitydefinitions.oauth2.password |
OAuth2 password auth. |
tokenUrl, scope |
// @securitydefinitions.oauth2.password OAuth2Password |
securitydefinitions.oauth2.accessCode |
OAuth2 access code auth. |
tokenUrl, authorizationUrl, scope |
// @securitydefinitions.oauth2.accessCode OAuth2AccessCode |
Attribute
// @Param enumstring query string false "string enums" Enums(A, B, C)
// @Param enumint query int false "int enums" Enums(1, 2, 3)
// @Param enumnumber query number false "int enums" Enums(1.1, 1.2, 1.3)
// @Param string query string false "string valid" minlength(5) maxlength(10)
// @Param int query int false "int valid" mininum(1) maxinum(10)
// @Param default query string false "string default" default(A)
// @Param collection query []string false "string collection" collectionFormat(multi)
It also works for the struct fields:
type Foo struct {
Bar string `minLength:"4" maxLength:"16"`
Baz int `minimum:"10" maximum:"20" default:"15"`
Qux []string `enums:"foo,bar,baz"`
}
Available
Future
Examples
Descriptions over multiple lines
You can add descriptions spanning multiple lines in either the general api description or routes definitions like so:
// @description This is the first line
// @description This is the second line
// @description And so forth.
User defined structure with an array type
// @Success 200 {array} model.Account <-- This is a user defined struct.
package model
type Account struct {
ID int `json:"id" example:"1"`
Name string `json:"name" example:"account name"`
}
Model composition in response
// JSONResult's data field will be overridden by the specific type proto.Order
@success 200 {object} jsonresult.JSONResult{data=proto.Order} "desc"
type JSONResult struct {
Code int `json:"code" `
Message string `json:"message"`
Data interface{} `json:"data"`
}
type Order struct { //in `proto` package
Id uint `json:"id"`
Data interface{} `json:"data"`
}
- also support array of objects and primitive types as nested response
@success 200 {object} jsonresult.JSONResult{data=[]proto.Order} "desc"
@success 200 {object} jsonresult.JSONResult{data=string} "desc"
@success 200 {object} jsonresult.JSONResult{data=[]string} "desc"
- overriding multiple fields. field will be added if not exists
@success 200 {object} jsonresult.JSONResult{data1=string,data2=[]string,data3=proto.Order,data4=[]proto.Order} "desc"
- overriding deep-level fields
type DeepObject struct { //in `proto` package
...
}
@success 200 {object} jsonresult.JSONResult{data1=proto.Order{data=proto.DeepObject},data2=[]proto.Order{data=[]proto.DeepObject}} "desc"
// @Success 200 {string} string "ok"
// @Header 200 {string} Location "/entity/1"
// @Header 200 {string} Token "qwerty"
Use multiple path params
/// ...
// @Param group_id path int true "Group ID"
// @Param account_id path int true "Account ID"
// ...
// @Router /examples/groups/{group_id}/accounts/{account_id} [get]
Example value of struct
type Account struct {
ID int `json:"id" example:"1"`
Name string `json:"name" example:"account name"`
PhotoUrls []string `json:"photo_urls" example:"http://test/image/1.jpg,http://test/image/2.jpg"`
}
Description of struct
type Account struct {
// ID this is userid
ID int `json:"id"`
Name string `json:"name"` // This is Name
}
Use swaggertype tag to supported custom type
#201
type TimestampTime struct {
time.Time
}
///implement encoding.JSON.Marshaler interface
func (t *TimestampTime) MarshalJSON() ([]byte, error) {
bin := make([]byte, 16)
bin = strconv.AppendInt(bin[:0], t.Time.Unix(), 10)
return bin, nil
}
func (t *TimestampTime) UnmarshalJSON(bin []byte) error {
v, err := strconv.ParseInt(string(bin), 10, 64)
if err != nil {
return err
}
t.Time = time.Unix(v, 0)
return nil
}
///
type Account struct {
// Override primitive type by simply specifying it via `swaggertype` tag
ID sql.NullInt64 `json:"id" swaggertype:"integer"`
// Override struct type to a primitive type 'integer' by specifying it via `swaggertype` tag
RegisterTime TimestampTime `json:"register_time" swaggertype:"primitive,integer"`
// Array types can be overridden using "array,<prim_type>" format
Coeffs []big.Float `json:"coeffs" swaggertype:"array,number"`
}
#379
type CerticateKeyPair struct {
Crt []byte `json:"crt" swaggertype:"string" format:"base64" example:"U3dhZ2dlciByb2Nrcw=="`
Key []byte `json:"key" swaggertype:"string" format:"base64" example:"U3dhZ2dlciByb2Nrcw=="`
}
generated swagger doc as follows:
"api.MyBinding": {
"type":"object",
"properties":{
"crt":{
"type":"string",
"format":"base64",
"example":"U3dhZ2dlciByb2Nrcw=="
},
"key":{
"type":"string",
"format":"base64",
"example":"U3dhZ2dlciByb2Nrcw=="
}
}
}
Use swaggerignore tag to exclude a field
type Account struct {
ID string `json:"id"`
Name string `json:"name"`
Ignored int `swaggerignore:"true"`
}
Add extension info to struct field
type Account struct {
ID string `json:"id" extensions:"x-nullable,x-abc=def"` // extensions fields must start with "x-"
}
generate swagger doc as follows:
"Account": {
"type": "object",
"properties": {
"id": {
"type": "string",
"x-nullable": true,
"x-abc": "def"
}
}
}
Rename model to display
type Resp struct {
Code int
}//@name Response
How to using security annotations
General API info.
// @securityDefinitions.basic BasicAuth
// @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
Each API operation.
// @Security ApiKeyAuth
Make it AND condition
// @Security ApiKeyAuth
// @Security OAuth2Application[write, admin]
About the Project
This project was inspired by yvasiyarov/swagger but we simplified the usage and added support a variety of web frameworks. Gopher image source is tenntenn/gopher-stickers. It has licenses creative commons licensing.
Contributors
This project exists thanks to all the people who contribute. [Contribute].
Backers
Thank you to all our backers! 🙏 [Become a backer]
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor]
License