Skip to content

OpenApi

The auto generated CRUD operations are documented via Swag which converts Go annotations to Swagger Documentation 2.0.

Getting started

Install swag by using:

go install github.com/swaggo/swag/cmd/swag@latest

Generates swagger documentation

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 --parseDependency --parseInternal

Make sure to import into the main.go file, the generated docs/docs.go so that your specific configuration gets init'ed.

import _ "example-module-name/docs"

Also adds the main annotations like:

package main

import (
    "github.com/darksubmarine/torpedo-lib-go/app"
    "github.com/darksubmarine/torpedo-lib-go/conf"
    "log/slog"
    "os"

    _ "./docs"
)


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

// @securityDefinitions.basic  BasicAuth

// @externalDocs.description  OpenAPI
// @externalDocs.url          https://swagger.io/resources/open-api/
func main() {

    // 1. App configuration
    config := conf.Map{}
    config.Add(3000, "port")

    // 2. Depdencies
    opts := app.ContainerOpts{Log: app.ContainerLogsOpts{W: os.Stdout, L: slog.LevelInfo}}

    application := app.NewApplicationContainer(opts)
    application.WithProvider(dependency.NewHttpServerProvider(config))
    application.WithProvider(dependency.NewHelloProvider())

    // 3. Run your application!
    application.Run()
}

Now we can run again swag init to refresh the generated documentation.

swag init --parseDependency --parseInternal

Parse internal files and dependencies

The swag command can be executed with parseDependency and parseInternal options:

1
2
3
4
swag init --parseDependency --parseInternal

--parseInternal                        Parse go files in internal packages, disabled by default
--parseDependency, --pd                Parse go files inside dependency folder, disabled by default

After using swag init to generate Swagger 2.0 docs, lets go to add the documentation endpoint to the HTTP Server. Import the following packages within the HTTP server provider:

import "github.com/swaggo/gin-swagger" // gin-swagger middleware
import "github.com/swaggo/files" // swagger embed files

And register the endpoint:

ginRouter.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))

For instance:

package dependency

import (
    "github.com/darksubmarine/torpedo-lib-go/app"
    "github.com/darksubmarine/torpedo-lib-go/conf"
    "github.com/darksubmarine/torpedo-lib-go/log"
    "github.com/gin-gonic/gin"

    "fmt"
    "net/http"

    ginSwagger "github.com/swaggo/gin-swagger" // gin-swagger middleware
    swaggerFiles "github.com/swaggo/files" // swagger embed files
)

// HttpServerProvider provides a gin http server
type HttpServerProvider struct {
    app.BaseProvider
    cfg conf.Map

    // server gin instance to be provided
    server *gin.Engine `torpedo.di:"provide"`

    // api router group to add endpoints under /api prefix
    apiV1 *gin.RouterGroup `torpedo.di:"provide,name=APIv1"`

    // binds
    logger log.ILogger `torpedo.di:"bind"`
}

func NewHttpServerProvider(config conf.Map) *HttpServerProvider {
    return &HttpServerProvider{cfg: config}
}

// Provide set the provide instances
func (p *HttpServerProvider) Provide(c app.IContainer) error {
    // gin server default instance
    p.server = gin.Default()

    // Adding a /ping endpoint
    p.server.GET("/ping", func(c *gin.Context) {
        p.logger.Info("/ping has been called")
        c.JSON(http.StatusOK, gin.H{"message": "pong"})
    })


    p.server.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))

    // api v1 group
    p.apiV1 = p.server.Group("/api/v1")

    return nil
}

// OnStart launches the gin http server calling the gin.Run method
func (p *HttpServerProvider) OnStart() func() error {
    return func() error {
        go func() {
            port := p.cfg.FetchIntP("port")
            if err := p.server.Run(fmt.Sprintf(":%d", port)); err != nil {
                panic(fmt.Sprintf("error starting HTTP server at %d with error %s", port, err))
            }
        }()

        return nil
    }
}

Finally, run your app, and browse to http://localhost:8080/swagger/index.html