Golang uses swaggo to automatically generate Restful API documents

#About Swaggo

I believe many program apes, like me, don't like writing API documents. How comfortable it is to write code. Not only does it take a lot of time to write documents, but sometimes it can't be comprehensive. But API documents are essential. I don't need to say that I believe they are important. A vague document can even make front and rear personnel fight. swaggo introduced in today's blog is a tool that allows you to generate perfect API documents just by focusing on the code. There's a lot of nonsense. Let's read the article directly.

Maybe you used it Swagger swaggo replaces the part where you write yaml manually. Comments can be converted into documents with just one command, which allows us to focus more on the code.

At present, swaggo mainly implements the following functions of swagger 2.0:

  • 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

  • Enumeration (Enums)

  • Grouping Operations With Tags

  • Swagger Extensions

The following contents take gin swaggo as an example

Here is the demo address

Updated on May 16, 2020:

swag has been upgraded to v1.6.5, and the returned data format has been updated.

Please pay attention to the latest Official website document.

At the end of this article, you can learn about the optimization part.

#Use use

#Install swag cli - and download related packages Install swag cli and download related packages

To use swaggo, you first need to install swag cli.

    go get -u github.com/swaggo/swag/cmd/swag

Then we need two more bags.

    # Gin swagger Middleware
    go get github.com/swaggo/gin-swagger
    # swagger built-in file
    go get github.com/swaggo/gin-swagger/swaggerFiles

You can see the version you installed

    swag --version
    swag version v1.6.5

#Add comments in main go Add comments in main.go

    package main
    
    import (
    "github.com/gin-gonic/gin"
    	ginSwagger "github.com/swaggo/gin-swagger"
    "github.com/swaggo/gin-swagger/swaggerFiles"
    )
    
    // @title Swagger Example API
    // @version 1.0
    // @description This is a sample server celler server.
    // @termsOfService https://razeen.me
    
    // @contact.name Razeen
    // @contact.url https://razeen.me
    // @contact.email me@razeen.me
    
    // @license.name Apache 2.0
    // @license.url http://www.apache.org/licenses/LICENSE-2.0.html
    
    // @host 127.0.0.1:8080
    // @BasePath /api/v1
    
    func main() {
    
    	r := gin.Default()
        store := sessions.NewCookieStore([]byte("secret"))
    	r.Use(sessions.Sessions("mysession", store))
    
    	r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
    
    	v1 := r.Group("/api/v1")
    	{
    		v1.GET("/hello", HandleHello)
    		v1.POST("/login", HandleLogin)
    		v1Auth := r.Use(HandleAuth)
    		{
    			v1Auth.POST("/upload", HandleUpload)
    			v1Auth.GET("/list", HandleList)
    		}
    	}
    
    	r.Run(":8080")
    }

As shown above, we need to import

    ginSwagger "github.com/swaggo/gin-swagger"
    "github.com/swaggo/gin-swagger/swaggerFiles"

At the same time, add comments. Of which:

  • Title: document title
  • Version: version
  • description,termsOfService,contact... These are some statements, which can not be written.
  • license.name yes, this is required.
  • host,BasePath: if you want to directly swagger debug the API, these two items need to be filled in correctly. The former is the port of the service document, ip. The latter is the basic path. For example, here is "/ api/v1".
  • In the original file, there are securityDefinitions.basic,securityDefinitions.apikey, etc. These are used for authentication. I won't expand them here for the time being.

Here, we can automatically generate documents by executing swag init in the same directory of mian.go, as follows:

    ➜  swaggo-gin git:(master) ✗ swag init
    2019/01/12 21:29:14 Generate swagger docs....
    2019/01/12 21:29:14 Generate general API Info
    2019/01/12 21:29:14 create docs.go at  docs/docs.go

Then we import the automatically generated docs package and run:

    package main
    
    import (
    "github.com/gin-gonic/gin"
    	ginSwagger "github.com/swaggo/gin-swagger"
    "github.com/swaggo/gin-swagger/swaggerFiles"
    
    	_ "github.com/razeencheng/demo-go/swaggo-gin/docs"
    )
    
    // @title Swagger Example API
    // @version 1.0
    // ...
    ➜  swaggo-gin git:(master) ✗ go build
    ➜  swaggo-gin git:(master) ✗ ./swaggo-gin
    [GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
    
    [GIN-debug] [WARNING] Running in"debug" mode. Switch to "release" mode in production.
     - using env:   export GIN_MODE=release
     - using code:  gin.SetMode(gin.ReleaseMode)
    
    [GIN-debug] GET    /api/v1/hello             --> main.HandleHello (3 handlers)
    [GIN-debug] POST   /api/v1/login             --> main.HandleLogin (3 handlers)
    [GIN-debug] POST   /upload                   --> main.HandleUpload (4 handlers)
    [GIN-debug] GET    /list                     --> main.HandleList (4 handlers)
    [GIN-debug] GET    /swagger/*any             --> github.com/swaggo/gin-swagger.WrapHandler.func1 (4 handlers)
    [GIN-debug] Listening and serving HTTP on :8080

Browser open http://127.0.0.1:8080/swagger/index.html , we can see that the following document title has been generated.

#Add comments on the Handle function Add comments on the Handle function

Next, we need to add comments on each routing processing function, such as:

    // @Summary test SayHello
    // @Description say Hello to you
    // @Tags test
    // @Accept mpfd
    // @Produce json
    // @Param who query string true "person name"
    // @Success 200 {string} string "{"msg": "hello Razeen"}"
    // @Failure 400 {string} string "{"msg": "who are you"}"
    // @Router /hello [get]
    funcHandleHello(c *gin.Context) {
    	who := c.Query("who")
    
    if who == "" {
    		c.JSON(http.StatusBadRequest, gin.H{"msg": "who are u?"})
    return
    	}
    
    	c.JSON(http.StatusOK, gin.H{"msg": "hello " + who})
    }

Let's run swag init again.

At this time, the relevant description of the API has been generated. We can also directly test the API by clicking Try it out.

It's not easy to use. Of course, it's not over. We'll explain these comment fields one by one.

These comments correspond to the location in the API document, which I have marked in the figure above. Here we mainly talk about the following parameters in detail:

#TagsTags

Tags is used to group API s.

#AcceptAccept

The received parameter types, including support form (mpfd), JSON (JSON), etc., are shown in the following table.

#ProduceProduce

The returned data structure is usually json

#ParamParam

Parameters, from front to back:

@Param who query string true "person name"

@Param 1. Parameter name ` ` 2. Parameter type ` ` 3. Parameter data type ` ` 4. Required ` ` 5. Parameter description ` ` 6. Other attributes

1. Parameter name

The parameter name is the name of the parameter we interpret.

2. Parameter type

There are four main parameter types:

path this type parameter is directly spliced in the URL, such as Demo HandleGetFile in:

    // @Param id path integer true "file ID"

query this type of parameter is usually combined in the URL, such as Demo HandleHello in

    // @Param who query string true "person name"

formData this type parameter is generally used by post and put methods, such as Demo HandleLogin in

    // @Param user formData string true "user name" default(admin)

body when Accept is in JSON format, we use this field to specify the received JSON type

    // @Param param body main.JSONParams true "JSON to upload"

3. Parameter data type

Data types mainly support the following:

  • string (string)
  • integer (int, uint, uint32, uint64)
  • number (float32)
  • boolean (bool)

Note that if you upload a file, you can use file, but the parameter type must be formData, as follows:

    // @Param file formData file true "file"

4. Is it necessary

Indicates whether the parameter is required. If necessary, it will be marked in bold in the document and must be filled in during the test.

5. Parameter description

These are some descriptions of parameters

6. Other attributes

In addition to the above attributes, we can also fill in some additional attributes for the parameter, such as enumeration, default value, value range, etc. As follows:

    enumeration
    // @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)
    
    Value addition range
    // @Param string query string false "string valid" minlength(5) maxlength(10)
    // @Param int query int false "int valid" mininum(1) maxinum(10)
    
    Set defaults
    // @Param default query string false "string default" default(A)
    

Moreover, these parameters can be used in combination, such as:

    // @Param enumstring query string false "string enums" Enums(A, B, C) default(A)
#SuccessSuccess

Specify the data for the successful response. The format is:

//@ Success 1.HTTP response code ` {2. Response parameter type} ` ` 3. Response data type ` ` 4. Other descriptions

1.HTTP response code

That's 200400500.

2. Response parameter type / 3. Response data type

The returned data type can be user-defined or json.

  • Custom type

In normal use, I will return some JSON data serialized by the specified model. At this time, this can be done

    // @Success 200 {object} main.File

Where, the package name is directly used for the model. You would say, what if I return the model array? Then you can write:

    // @Success 200 {anrry} main.File

If you just return other data formats, you can write as follows:

    // @Success 200 {string} string ""

4. Other descriptions

You can add some descriptions.

#FailureFailure

Same as Success.

#RouterRouter

Specify the route and HTTP method. The format is:

//@ Router /path/to/handle [HTTP method]

No basic path.

#Document generation and testing Document generation and testing

In fact, the introduction has been interspersed above.

Run swag init under main.go to generate and update documents.

Click Try it out in the document to test. If some API s need to log in, Try to log in to the interface.

#Optimize optimization

See here, you can basically use it. However, documents are generally only needed when we test. When my product is launched, interface documents should not be given to users, and the package with interface documents will be much larger (swaggo is built directly into binary).

To deal with this situation, we can optimize it during compilation, such as using build tag to control whether to compile documents.

Declare swagHandler in main.go and join the route only when the parameter is not empty:

    package main
    
    //...
    
    var swagHandler gin.HandlerFunc
    
    funcmain(){
    // ...
    
    if swagHandler != nil {
    			r.GET("/swagger/*any", swagHandler)
            }
    
    //...
    }
    

At the same time, we initialize this parameter in the package added with build tag.

  
    // +build doc
    
    package main
    
    import (
    	_ "github.com/razeencheng/demo-go/swaggo-gin/docs"
    
    	ginSwagger "github.com/swaggo/gin-swagger"
    "github.com/swaggo/gin-swagger/swaggerFiles"
    )
    
    funcinit() {
    	swagHandler = ginSwagger.WrapHandler(swaggerFiles.Handler)
    }

Then we can use go build -tags "doc" to package packages with documents, and directly go build to package packages without documents.

You will find that even if I have such a small Demo, the compiled size will differ by 19M!

    ➜  swaggo-gin git:(master) ✗ go build
    ➜  swaggo-gin git:(master) ✗ ll swaggo-gin
    -rwxr-xr-x  1 xxx  staff    15M Jan 13 00:23 swaggo-gin
    ➜  swaggo-gin git:(master) ✗ go build -tags "doc"
    ➜  swaggo-gin git:(master) ✗ ll swaggo-gin
    -rwxr-xr-x  1 xxx  staff    34M Jan 13 00:24 swaggo-gin
    

The article ends here, complete Demo address here.

This article is taken from https://razeencheng.com/post/go-swagger.html

Tags: Go

Posted on Sun, 10 Oct 2021 09:13:24 -0400 by zc1