Skip to content

Generate Swagger 2.0 documentation for Go with "no" annotations, "no" files, "no" command

License

Notifications You must be signed in to change notification settings

AndresSabiniPeYa/swagno

 
 

Repository files navigation

swagno: no annotations, no files, no command

Swagno

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.

About the Project

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.

Contents

Getting started

  1. Get swagno package in your project
go get github.com/go-swagno/swagno
  1. 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.)

  1. 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),
}
  1. Create Swagger(swagno) instance
sw := CreateNewSwagger("Swagger API", "1.0")
  1. Use AddEndpoints (or swagno.AddEndpoints) function to add endpoints arrays to Swagno
AddEndpoints(endpoints)
// you can add more arrays
// AddEndpoints(productEndpoints)
// AddEndpoints(merchantEndpoints)
  1. 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"})

Supported Web Frameworks

How to use with Fiber

You can read detailed document and find better examples in swagno-fiber

Example:

  1. Get swagno-fiber
go get github.com/go-swagno/swagno-fiber
  1. 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

How to use with Gin

You can read detailed document and find better examples in swagno-gin

Example:

  1. Get swagno-gin
go get github.com/go-swagno/swagno-gin
  1. 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

Implementation Status

As purpose of this section, you can compare swagno status with swaggo

Swagger 2.0 document

  • 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

Create Your Swagger

General Swagger Info

sw := CreateNewSwagger("Swagger API", "1.0") -> (title, version)
sw := CreateNewSwagger("Swagger API", "1.0", "/v2", "localhost") -> (title, version, basePath, host)

Adding Contact and License info (optional)

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/"

Adding Tags (optional)

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"})

Security

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")))

Basic Auth

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")

Api Key Auth

If you have an api key auth, you can use SetApiKeyAuth function.

Parameters:

  • name -> name of the api key
  • in -> location of the api key. It can be header or query
  • description (optional) -> you can also add description as argument
sw.SetApiKeyAuth("api_key", "header")
// with description
sw.SetApiKeyAuth("api_key", "header", "Description")

OAuth2 Auth

If you have an oauth2 auth, you can use SetOAuth2Auth function. You can also add description as argument:

Parameters:

  • name -> name of the oauth2
  • flow -> flow type of the oauth2. It can be implicit, password, application, accessCode
  • authorizationUrl -> authorization url of the oauth2 (set this if flow is impilicit or accessCode, else you can set empty string)
  • tokenUrl -> token url of the oauth2 (set this if flow is password, application or accessCode, else you can set empty string)
  • scopes -> scopes of the oauth2
  • description (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 scope
  • description -> description of the scope

Endpoints (API)

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)

Arguments:

Method

Options: GET, POST, PUT, DELETE, OPTION, PATCH, HEAD

Path

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

Tags as string seperated by comma -> "tag1,tag2"

Params

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}}

Parameter Functions

  • 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 Options

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". 

Body

use a struct model instance like models.ProductPost{} or nil

Response/Return

use a struct model instance like models.Product{} or nil

Error Response

use a struct model instance like models.ErrorResponse or nil

Description

Endpoint description as string

Security

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()))

BasicAuth

If you want to use basic auth to an endpoint, you can use BasicAuth() function.

BasicAuth("Basic Auth Description")

ApiKeyAuth

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")

OAuth2Auth

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")

Consumes (optional)

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.

Produces (optional)

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"),

Contribution

We are welcome to any contribution. Swagno still has some missing features. Also we want to enrich handler implementations for other web frameworks.

About

Generate Swagger 2.0 documentation for Go with "no" annotations, "no" files, "no" command

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Go 100.0%