Nice to meet you!

We're delighted to have you here. Need assistance with our services or products? Feel free to reach out.

Hero Illustration
0 Comments
Mitrais, Software Development

Implementing Golang API Documentation Using Go Swagger

As developers, we are already aware of the importance of documenting and organizing all the API’s; but not every developer enjoys the documentation part of the job. The best way to assist us is to use a tool that can automatically prepare API documentation, and Swagger is the ideal tool for this purpose.

What is Swagger? 

Swagger is a set of open-source tools built around the OpenAPI Specification that helps us design, build, document, and consume REST APIs. 

Why use Swagger? 

As we need to follow proper steps in software development, documentation is a ‘must’. With Swagger, we can create API documentation automatically by adding comments to our code and generate REST clients for any technology like Golang, Node, PHP, etc. Swagger is great for maintaining consistent naming conventions, maintaining best practices, and providing a common structure for our applications. Also, it can save coding time on the client side. 

In this example, we will develop the API using Golang, and then we will use Swagger to generate the API documentation.

Installing Go-Swagger  

The requirement to start this tutorial is to install Go on your local machine. The installation is out of this article’s scope, but the instructions can be easily found on the Internet. Once Go is installed, we can install Go-Swagger as follows:

On the machine, clone the Go-Swagger repo:

git clone https://github.com/go-swagger/go-swagger 

Go to the Go-Swagger directory and install it using this command:   

go install ./cmd/swagger

To verify that Go-Swagger has been installed, go to cmd and type “swagger” and press ENTER. The output should be as below.

C:\Users\Muhammad_F820>swagger 
Please specify one command of: diff, expand, flatten, generate, init, mixin, serve, validate or version. 

Implementing Go-Swagger to Golang  

Let’s create a new directory named “imp-goswagger” and then open Visual Studio Code. After that, open the terminal and type: 

go mod init imp-goswagger 

Download dependencies for our project. For this demo we will use:  

  • Mux: handling http request and routing 
go get github.com/gorilla/mux 
  • Swagger: handling swagger documents 
go get github.com/go-openapi/runtime/middleware 
  • Gorm: handling database transaction 
go get gorm.io/gorm 
go get gorm.io/driver/postgres 

Create a config folder in the root directory. Then create file dbconn.go and write a database connection with the following code: 

package database 
 
import ( 
    "fmt" 
 
    "gorm.io/driver/postgres" 
    "gorm.io/gorm" 
    "gorm.io/gorm/schema" 
) 
 
func NewConnectionDB(database string, host string, user string, password string, port int) (*gorm.DB, error) { 
    var dialect gorm.Dialector 
 
    //default singular 
    gormConfig := &gorm.Config{ 
        NamingStrategy: schema.NamingStrategy{ 
            SingularTable: true, 
        }, 
    } 
 
    dsn := fmt.Sprintf( 
        "host=%s port=%d user=%s dbname=%s password=%s sslmode=%s", 
        host, 
        port, 
        user, 
        database, 
        password, 
        "disable", 
    ) 
 
    dialect = postgres.Open(dsn) 
 
    db, err := gorm.Open(dialect, gormConfig) 
    if err != nil { 
        return nil, err 
    } 
 
    return db, nil 
} 

Writing Documentation Using Go Swagger 

Now that we have created a database connection, the next step is to document using Swagger. It will consist of basic configurations, models, and API Routes. 

  • Basic Configuration 

Place the following code inside main.go. 

//   Product Api: 
//    version: 0.1 
//    title: Product Api 
//   Schemes: http, https 
//   Host: 
//   BasePath: /api/v1 
//      Consumes: 
//      - application/json 
//   Produces: 
//   - application/json 
//   SecurityDefinitions: 
//    Bearer: 
//     type: apiKey 
//     name: Authorization 
//     in: header 
//   swagger:meta 
package main 

For security definitions, we use an API key, which can be verified for every API. 

  • Models 

Create models to manage requests and responses of our API. Below are examples of a structure using swagger comments. We can add a name, type, schema, required field, and description for every field. 

package model 
 
// swagger:model Product 
type Product struct { 
    // ID of product 
    // in: int64 
    ID uint64 `gorm:"primary_key:auto_increment" json:"-"` 
    // Name of product 
    // in: string 
    Name string `json:"name" gorm:"not null;type:varchar"` 
    // SKU of product 
    // in: string 
    SKU string `json:"sku" gorm:"type:varchar" 
    // UOM of product 
    // in: string 
    UOM string `json:"uom" gorm:"type:varchar"` 
    // Weight of product 
    // in: int32 
    Weight int32 `json:"weight"` 
} 
 
// swagger:parameters SaveProductRequest 
type ReqProductBody struct { 
    //  in: body 
    Body SaveProductRequest `json:"body"`
}
  • API Routes 

In this part, we can add swagger comments for every route. We can specify request and response models, route names, request methods, descriptions and API keys if required. 

// swagger:operation POST /product Product SaveProductRequest 
// Create Product 
// 
// --- 
// responses: 
// 
//  401: CommonError 
//  200: CommonSuccess 
func (s *productServiceImpl) CreateProduct(input model.SaveProductRequest) (*model.Product, message.Message) { 
    s.baseRepo.BeginTx() 
    product := model.Product{ 
        Name:   input.Name, 
        SKU:    input.SKU, 
        UOM:    input.UOM, 
        Weight: input.Weight, 
    } 
    result, err := s.productRepo.Create(&product) 
    if err != nil { 
        return nil, message.ErrSaveData 
    } 
    return result, message.SuccessMsg 
} 
 
// swagger:operation PUT /product/{id} Product SaveProductRequest 
// Update Product 
// 
// --- 
// responses: 
// 
//  401: CommonError 
//  200: CommonSuccess 
func (s *productServiceImpl) UpdateProduct(id int, input model.SaveProductRequest) (*model.Product, message.Message) { 
    s.baseRepo.BeginTx() 
    product, err := s.productRepo.FindById(id) 
    if err != nil { 
        return nil, message.ErrNotFound 
    } 
    if product != nil { 
        return nil, message.ErrNotFound 
    } 
 
    product.Name = input.Name 
    product.SKU = input.SKU 
    product.UOM = input.UOM 
    product.Weight = input.Weight 
 
    result, err := s.productRepo.Update(id, product) 
    if err != nil { 
        return nil, message.ErrSaveData 
    } 
    return result, message.SuccessMsg 
} 
 
// swagger:operation GET /product/{id} Product byParamGet 
// Get Product by Id 
// 
// --- 
// responses: 
// 
//  401: CommonError 
//  200: CommonSuccess 
func (s *productServiceImpl) GetProduct(id int) (*model.Product, message.Message) { 
    s.baseRepo.BeginTx() 
    result, err := s.productRepo.FindById(id) 
    if err != nil { 
        return nil, message.ErrNotFound 
    } 
    return result, message.SuccessMsg 
} 
 
// swagger:operation GET /product Product getList 
// Get Product List 
// 
// --- 
// responses: 
// 
//  401: CommonError 
//  200: CommonSuccess 
func (s *productServiceImpl) GetList() ([]model.Product, message.Message) { 
    s.baseRepo.BeginTx() 
    results, err := s.productRepo.FindAll() 
    if err != nil { 
        return nil, message.ErrNotFound 
    } 
    return results, message.SuccessMsg 
} 
 
// swagger:operation DELETE /product/{id} Product byParamDelete 
// Delete Product by Id 
// 
// --- 
// responses: 
// 
//  401: CommonError 
//  200: CommonSuccess 
func (s *productServiceImpl) DeleteProduct(id int) message.Message { 
    s.baseRepo.BeginTx() 
    err := s.productRepo.Delete(id) 
    if err != nil { 
        return message.ErrDeleteData 
    } 
    return message.SuccessMsg 
} 

After implementing all of the steps above, we can generate swagger yaml or JSON files for swagger comments using this command in the root directory. 

swagger generate spec -o ./swagger.yaml –scan-models

It will generate the file swagger.yaml in the root directory. We can add routes to this file for documentation by implementing this code: 

  pr := mux.NewRouter() 
 
    pr.Handle("/swagger.yaml", http.FileServer(http.Dir("./"))) 
    opts := middleware.SwaggerUIOpts{SpecURL: "swagger.yaml"} 
    sh := middleware.SwaggerUI(opts, nil) 
    pr.Handle("/docs", sh) 
 
    //// documentation for share 
    opts1 := middleware.RedocOpts{SpecURL: "swagger.yaml", Path: "doc"} 
    sh1 := middleware.Redoc(opts1, nil) 
    pr.Handle("/doc", sh1)

Finally, we can run our apps and open this URL to see the documentation. 

So, those are the steps to create Golang API Documentation using Go Swagger. For the complete code, visit the GitHub repository: imp-goswagger 

Final Thoughts

Effective documentation has been proven to enhance productivity, as shown by GitHub’s 2021 State of the Octoverse report, which revealed a 50% productivity boost for developers when easy-to-source documentation was available. This increase in productivity alone makes a compelling case for the value of documentation, but just in case, we’ll add a few more. 

Well-written documentation contributes to building strong team cultures. 

GitHub’s report highlights the importance of good information flow in building trust and promoting developer satisfaction, particularly in remote work environments where teams work from different locations. Documentation plays a crucial role in ensuring that knowledge is shared amongst team members – both current and future.  

Code documentation is essential for onboarding new developers.  

For developers, an important part of the onboarding process includes a tour of the existing codebase. It also involves an overview of the system architecture and an introduction to team coding practices and conventions. Using Swagger makes this process transparent and sustainable even if there is high turnover on a team.

Hopefully, this article has been informative and will help implement documentation on our Golang API, since documentation is critical for developers.

References:

https://swagger.io/

https://www.infoq.com/articles/design-first-api-development/

https://www.postman.com/state-of-api/api-first-strategies/

https://www.bacancytechnology.com/blog/create-golang-api-documentation-using-go-swagger 

https://octoverse.github.com/

Author: Muhammad Farisul Khilmi, Software Engineer Programmer

Contact us to learn more!

Please complete the brief information below and we will follow up shortly.

    ** All fields are required
    Leave a comment