Swagno is an approach to create Swagger Documentation 2.0 without any annotation, exported file or any command to run. You can declare your documentation details in code and get a json string to serve with a handler.
This project inspired by Swaggo. Swaggo, uses annotations, exports files and needs to run by command. If you don't like this way, Swagno appears as a good alternative.
- Getting started
- Supported Web Frameworks
- How to use with Fiber
- How to use with Gin
- Implementation Status
- Create Your Swagger
- Contribution
- Get swagno package in your project
go get github.com/go-swagno/swagno
- Import swagno (We suggest "." import)
import (
. "github.com/go-swagno/swagno"
)
You can import without explicit period (.) like this: import "github.com/go-swagno/swagno"
but then you have to add swagno.
to functions, structs etc. ( []swagno.Endpoint
, swagno.EndPoint
, swagno.Params()
etc.)
- Create your endpoints (check Endpoints). Example:
endpoints := []Endpoint{
EndPoint(GET, "/product", "product", Params(), nil, []models.Product{}, models.ErrorResponse{}, "Get all products", nil),
EndPoint(GET, "/product/{id}", "product", Params(IntParam("id", true, "")), nil, models.Product{}, models.ErrorResponse{}, "", nil),
EndPoint(GET, "/product/{id}/detail", "product", Params(IntParam("id", true, "")), nil, models.Product{}, models.ErrorResponse{}, "", nil),
EndPoint(POST, "/product", "product", Params(), models.ProductPost{}, models.Product{}, models.ErrorResponse{}, "", nil),
}
- Create Swagger(swagno) instance
sw := CreateNewSwagger("Swagger API", "1.0")
- Use AddEndpoints (or swagno.AddEndpoints) function to add endpoints arrays to Swagno
AddEndpoints(endpoints)
// you can add more arrays
// AddEndpoints(productEndpoints)
// AddEndpoints(merchantEndpoints)
- Generate json as string and give it to your handler to serve. You can create your own handler or use our Supported Web Frameworks
sw.GenerateDocs()
-> to generate swagger json from endpoints
For Gin: swagno-gin
// gin example -> https://github.com/go-swagno/swagno-gin
a.GET("/swagger/*any", swagger.SwaggerHandler(sw.GenerateDocs()))
For Fiber: swagno-fiber
// fiber example -> https://github.com/go-swagno/swagno-fiber
swagger.SwaggerHandler(a, sw.GenerateDocs(), swagger.Config{Prefix: "/swagger"})
You can read detailed document and find better examples in swagno-fiber
Example:
- Get swagno-fiber
go get github.com/go-swagno/swagno-fiber
- Import swagno-fiber
import "github.com/go-swagno/swagno-fiber/swagger"
...
// assume you declare your endpoints and "sw"(swagno) instance
swagger.SwaggerHandler(a, sw.GenerateDocs(), swagger.Config{Prefix: "/swagger"})
...
You can find a detailed example in https://github.com/go-swagno/swagno/example/fiber
You can read detailed document and find better examples in swagno-gin
Example:
- Get swagno-gin
go get github.com/go-swagno/swagno-gin
- Import swagno-gin
import "github.com/go-swagno/swagno-gin/swagger"
...
// assume you declare your endpoints and "sw"(swagno) instance
a.GET("/swagger/*any", swagger.SwaggerHandler(sw.GenerateDocs()))
...
You can find a detailed example in https://github.com/go-swagno/swagno/example/gin
As purpose of this section, you can compare swagno status with swaggo
- Basic Structure
- API Host and Base Path
- Paths and Operations
- Describing Parameters
- Describing Request Body
- Describing Responses
- MIME Types -> need to improve
- Authentication
- Basic Authentication
- API Keys
- OAuth2
- Adding Examples
- File Upload -> need to improve
- Enums
- Grouping Operations With Tags
- Swagger Extensions
sw := CreateNewSwagger("Swagger API", "1.0") -> (title, version)
sw := CreateNewSwagger("Swagger API", "1.0", "/v2", "localhost") -> (title, version, basePath, host)
sw.Info.Contact.Email = "anilsenay3@gmail.com"
sw.Info.Contact.Name = "anilsenay"
sw.Info.Contact.Url = "https://anilsenay.com"
sw.Info.License.Name = "Apache 2.0"
sw.Info.License.Url = "http://www.apache.org/licenses/LICENSE-2.0.html"
sw.Info.TermsOfService = "http://swagger.io/terms/"
Allows adding meta data to a single tag. If you don't need meta data for your tags, you can skip this.
There is 3 alternative way for describing tags with descriptions.
sw.AddTags(Tag("product", "Product operations"), Tag("merchant", "Merchant operations"))
sw.AddTags(SwaggerTag{Name: "WithStruct", Description: "WithStruct operations"})
sw.Tags = append(sw.Tags, SwaggerTag{Name: "headerparams", Description: "headerparams operations"})
If you want to add security to your swagger, you can use SetBasicAuth
, SetApiKeyAuth
, SetOAuth2Auth
functions.
sw.SetBasicAuth()
sw.SetApiKeyAuth("api_key", "header")
sw.SetOAuth2Auth("oauth2_name", "password", "http://localhost:8080/oauth2/token", "http://localhost:8080/oauth2/authorize", Scopes(Scope("read:pets", "read your pets"), Scope("write:pets", "modify pets in your account")))
If you have a basic auth with username and password, you can use SetBasicAuth
function. It has default name as "basicAuth". You can add description as argument:
sw.SetBasicAuth()
// with description
sw.SetBasicAuth("Description")
If you have an api key auth, you can use SetApiKeyAuth
function.
Parameters:
name
-> name of the api keyin
-> location of the api key. It can beheader
orquery
description
(optional) -> you can also add description as argument
sw.SetApiKeyAuth("api_key", "header")
// with description
sw.SetApiKeyAuth("api_key", "header", "Description")
If you have an oauth2 auth, you can use SetOAuth2Auth
function. You can also add description as argument:
Parameters:
name
-> name of the oauth2flow
-> flow type of the oauth2. It can beimplicit
,password
,application
,accessCode
authorizationUrl
-> authorization url of the oauth2 (set this if flow isimpilicit
oraccessCode
, else you can set empty string)tokenUrl
-> token url of the oauth2 (set this if flow ispassword
,application
oraccessCode
, else you can set empty string)scopes
-> scopes of the oauth2description
(optional) -> you can also add description as argument
sw.SetOAuth2Auth("oauth2_name", "password", "", "http://localhost:8080/oauth2/token", Scopes(Scope("read:pets", "read your pets"), Scope("write:pets", "modify pets in your account")))
For scopes, you can use Scopes
function. It takes Scope
as variadic parameter.
Parameters of Scope
:
name
-> name of the scopedescription
-> description of the scope
Defination:
EndPoint(method MethodType, path string, tags string, params []Parameter, body interface{}, ret interface{}, err interface{}, des string, secuirty []map[string][]string, args ...string)
You need to create an Endpoint array []Endpoint and add your endpoints in this array. Example:
endpoints := []Endpoint{
EndPoint(GET, "/product", "product", Params(), nil, []models.Product{}, models.ErrorResponse{}, "Get all products", nil),
EndPoint(GET, "/product/{id}", "product", Params(IntParam("id", true, "")), nil, models.Product{}, models.ErrorResponse{}, "", nil),
EndPoint(POST, "/product", "product", Params(), models.ProductPost{}, models.Product{}, models.ErrorResponse{}, "", nil),
}
// add endpoints array to Swagno
AddEndpoints(endpoints)
Note: You can simply add only one endpoint by using AddEndpoint(endpoint)
- Arguments: (Method, Path, Tag, Params, Body, Response, Error Response, Description, Security)
NOTE: If you not imported with explicit period (.), you need to get from swagno package:
endpoints := []swagno.Endpoint{
swagno.EndPoint(swagno.GET, "/product", "product", swagno.Params(), nil, []models.Product{}, models.ErrorResponse{}, "Get all products", nil),
swagno.EndPoint(swagno.GET, "/product/{id}", "product", swagno.Params(swagno.IntParam("id", true, "")), nil, models.Product{}, models.ErrorResponse{}, "", nil),
swagno.EndPoint(swagno.POST, "/product", "product", swagno.Params(), models.ProductPost{}, models.Product{}, models.ErrorResponse{}, "", nil),
}
// add endpoints array to Swagno
swagno.AddEndpoints(endpoints)
If you don't like this functional approach, you can use directly struct:
endpoints := []Endpoint{
{Method: "GET", Path: "/product/{id}", Description: "product", Params: Params(IntParam("id", true, "")), Return: models.Product{}, Error: models.ErrorResponse{}, Tags: []string{"WithStruct"}},
}
❗ Don't forget to add your endpoints array to Swagno ❗
AddEndpoints(endpoints)
- Method
- Path
- Tags
- Params
- Body
- Return
- Error
- Description
- Security
- Consumes (optional / extra argument)
- Produces (optional / extra argument)
Options: GET, POST, PUT, DELETE, OPTION, PATCH, HEAD
Path of your endpoint without adding query
parameter options
For example, you have endpoint as /product/{id}?someParam=true
you need to add path as /product/{id}
only, without query params.
Tags as string seperated by comma -> "tag1,tag2"
You can use Params() function to generate params array:
// path should be -> /product/{merchant}/{id}
Params(StrParam("merchant", true, ""), IntParam("id", true, ""))
Or you can use []Parameter array:
[]Parameter{{Name: "id", Type: "integer", In: "path", Required: true}}
- IntParam (name string, required bool, description string, args ...Fields)
- StrParam (name string, required bool, description string, args ...Fields)
- BoolParam (name string, required bool, description string, args ...Fields)
- FileParam (name string, required bool, description string, args ...Fields)
- IntQuery (name string, required bool, description string, args ...Fields)
- StrQuery (name string, required bool, description string, args ...Fields)
- BoolQuery (name string, required bool, description string, args ...Fields)
- IntHeader (name string, required bool, description string, args ...Fields)
- StrHeader (name string, required bool, description string, args ...Fields)
- BoolHeader (name string, required bool, description string, args ...Fields)
- IntEnumParam (name string, arr []int64, required bool, description string, args ...Fields)
- StrEnumParam (name string, arr []string, required bool, description string, args ...Fields)
- IntEnumQuery (name string, arr []int64, required bool, description string, args ...Fields)
- StrEnumQuery (name string, arr []string, required bool, description string, args ...Fields)
- IntEnumHeader (name string, arr []int64, required bool, description string, args ...Fields)
- StrEnumHeader (name string, arr []string, required bool, description string, args ...Fields)
- IntArrParam (name string, arr []int64, required bool, description string, args ...Fields)
- StrArrParam (name string, arr []string, required bool, description string, args ...Fields)
- IntArrQuery (name string, arr []int64, required bool, description string, args ...Fields)
- StrArrQuery (name string, arr []string, required bool, description string, args ...Fields)
- IntArrHeader (name string, arr []int64, required bool, description string, args ...Fields)
- StrArrHeader (name string, arr []string, required bool, description string, args ...Fields)
Parameter Option | Description |
---|---|
Name | name of parameter |
Type | type of parameter: integer, number(for float/double), string, array, boolean, file |
In | options: path, query, formData, header, array |
Required | true or false |
Description | parameter description as string |
Enum | int64 array or string array |
Items | |
Default | default value of parameter |
Format | format of parameter: https://swagger.io/specification/v2/#dataTypeFormat |
Min | min value of parameter value |
Max | max value of parameter value |
MinLen | min length of parameter value |
MaxLen | max length of parameter value |
Pattern | see: https://datatracker.ietf.org/doc/html/draft-fge-json-schema-validation-00#section-5.2.3 |
MaxItems | max items if type is array |
MinItems | min items if type is array |
UniqueItems | true or false |
MultipleOf | see: https://datatracker.ietf.org/doc/html/draft-fge-json-schema-validation-00#section-5.1.1 |
CollenctionFormat | if type is "array", checkout the table above: |
CollenctionFormat | Description |
---|---|
csv | comma separated values foo,bar. |
ssv | space separated values foo bar. |
tsv | tab separated values foo\tbar. |
pipes | pipe separated values foo | bar. |
multi | corresponds to multiple parameter instances instead of multiple values for a single instance foo=bar&foo=baz. This is valid only for parameters in "query" or "formData". |
use a struct model instance like models.ProductPost{}
or nil
use a struct model instance like models.Product{}
or nil
use a struct model instance like models.ErrorResponse
or nil
Endpoint description as string
Before using this function, you need to define your security definitions in Swagno struct. For example:
sw.SetBasicAuth()
sw.SetApiKeyAuth("api_key", "query")
sw.SetOAuth2Auth("oauth2_name", "password", "http://localhost:8080/oauth2/token", "http://localhost:8080/oauth2/authorize", Scopes(Scope("read:pets", "read your pets"), Scope("write:pets", "modify pets in your account")))
If you want to add security to your endpoint, you can use one of BasicAuth()
, ApiKeyAuth()
, OAuth()
functions:
BasicAuth()
ApiKeyAuth("api_key")
OAuth("oauth2_name", "read:pets")
// you can add more scope name as argument
OAuth("oauth2_name", "read:pets", "write:pets", "...")
And use in EndPoint
function:
EndPoint(GET, "/product", "product", Params(), nil, []models.Product{}, models.Error{}, "description", ApiKeyAuth("api_key", "header"))
You can add more than one security to your endpoint with Security()
function:
EndPoint(GET, "/product", "product", Params(), nil, []models.Product{}, models.ErrorResponse{}, "Get all products", Security(ApiKeyAuth("api_key", "header"), BasicAuth()))
If you want to use basic auth to an endpoint, you can use BasicAuth()
function.
BasicAuth("Basic Auth Description")
If you want to use api key auth to an endpoint, you can use ApiKeyAuth()
function. It needs name as argument. This name must match with one of your Swagno security definations.
ApiKeyAuth("api_key")
If you want to use oauth2 auth to an endpoint, you can use OAuth2Auth()
function. It needs name as argument. This name must match with one of your Swagno security definations. Then you can add scopes as arguments:
OAuth2Auth("oauth2_name", "read:pets", "write:pets")
For default there is only one consumes type: "application/json", you don't need to add it. If you want to add more consumes types, you can add them as string as seperated by commas to EndPoint function's extra option:
EndPoint(GET, "/product", "product", Params(), nil, []models.Product{}, models.ErrorResponse{}, "Get all products", nil, "application/xml,text/plain"),
NOTE: If you used FileParam() in your endpoint, you don't need to add "multipart/form-data" to consumes. It will add automatically.
For default there are two produces types: "application/json" and "application/xml", you don't need to add them. If you want to add more produces types, you can add them as string as seperated by commas to EndPoint function's extra option:
// without extra consumes -> nil as consumes
EndPoint(GET, "/product", "product", Params(), nil, []models.Product{}, models.ErrorResponse{}, "Get all products", nil, nil, "application/xml,text/plain"),
// with extra consumes
EndPoint(GET, "/product", "product", Params(), nil, []models.Product{}, models.ErrorResponse{}, "Get all products", nil, "application/xml,text/plain", "text/plain,text/html"),
We are welcome to any contribution. Swagno still has some missing features. Also we want to enrich handler implementations for other web frameworks.