YApi结合swag管理和生成go项目restful API文档

YApi结合swag管理go项目API文档

准备

  • 什么是OpenAPI?Swagger是什么?
  • 安装和了解swag
  • YApi教程
  • docker部署YApi

项目demo

├── controller
│   ├── accounts.go
│   └── controller.go
├── docs               
│   ├── docs.go
│   ├── swagger.json
│   └── swagger.yaml
├── go.mod
├── httputil
│   └── error.go
├── main.go
└── model
    └── account.go

main.go

package main

import (
	"demo/controller"
	_ "demo/docs"

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

// @title Swagger Example API
// @version 1.0
// @description This is a sample server demo server.
// @termsOfService http://swagger.io/terms/

// @contact.name API Support
// @contact.url http://www.swagger.io/support
// @contact.email [email protected]

// @license.name Apache 2.0
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html

// @host localhost:8080
// @BasePath /api/v1

func main() {
	r := gin.Default()

	c := controller.NewController()

	v1 := r.Group("/api/v1")
	{
		accounts := v1.Group("/accounts")
		{
			accounts.GET(":id", c.ShowAccount)
			accounts.POST("", c.AddAccount)
		}
    }
    // 先用swag init 生成docs目录
    // http://localhost:8080/swagger/index.html 可以看swagger ui的文档
	r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
	r.Run(":8080")
}

controller/controller.go

package controller

// Controller example
type Controller struct {
}

// NewController example
func NewController() *Controller {
	return &Controller{}
}

// Message example
type Message struct {
	Message string `json:"message" example:"message"`
}

controller/accounts.go

package controller

import (
	"demo/httputil"
	"demo/model"
	"net/http"
	"strconv"

	"github.com/gin-gonic/gin"
)

// ShowAccount godoc
// @Summary Show a account
// @Description get string by ID
// @Tags accounts
// @Accept  json
// @Produce  json
// @Param id path int true "Account ID"
// @Success 200 {object} model.Account
// @Failure 400 {object} httputil.HTTPError
// @Failure 404 {object} httputil.HTTPError
// @Failure 500 {object} httputil.HTTPError
// @Router /accounts/{id} [get]
func (c *Controller) ShowAccount(ctx *gin.Context) {
	id := ctx.Param("id")
	aid, err := strconv.Atoi(id)
	if err != nil {
		httputil.NewError(ctx, http.StatusBadRequest, err)
		return
	}
	account, err := model.AccountOne(aid)
	if err != nil {
		httputil.NewError(ctx, http.StatusNotFound, err)
		return
	}
	ctx.JSON(http.StatusOK, account)
}

// AddAccount godoc
// @Summary Add a account
// @Description add by json account
// @Tags accounts
// @Accept  json
// @Produce  json
// @Param account body model.AddAccount true "Add account"
// @Success 200 {object} model.Account
// @Failure 400 {object} httputil.HTTPError
// @Failure 404 {object} httputil.HTTPError
// @Failure 500 {object} httputil.HTTPError
// @Router /accounts [post]
func (c *Controller) AddAccount(ctx *gin.Context) {
	var addAccount model.AddAccount
	if err := ctx.ShouldBindJSON(&addAccount); err != nil {
		httputil.NewError(ctx, http.StatusBadRequest, err)
		return
	}
	if err := addAccount.Validation(); err != nil {
		httputil.NewError(ctx, http.StatusBadRequest, err)
		return
	}
	// Name以外的字段仅用来演示
	account := model.Account{
		Name: addAccount.Name,
	}
	lastID, err := account.Insert()
	if err != nil {
		httputil.NewError(ctx, http.StatusBadRequest, err)
		return
	}
	account.ID = lastID
	ctx.JSON(http.StatusOK, account)
}

httputil/error.go


package httputil

import "github.com/gin-gonic/gin"

// NewError example
func NewError(ctx *gin.Context, status int, err error) {
	er := HTTPError{
		Code:    status,
		Message: err.Error(),
	}
	ctx.JSON(status, er)
}

// HTTPError example
type HTTPError struct {
	Code    int    `json:"code" example:"400"`
	Message string `json:"message" example:"status bad request"`
}

model/account.go

package model

import (
	"errors"
	"fmt"

	uuid "github.com/satori/go.uuid"
)

// Account example
type Account struct {
	ID   int       `json:"id" example:"1" format:"int64"`
	Name string    `json:"name" example:"account name"`
	UUID uuid.UUID `json:"uuid" example:"550e8400-e29b-41d4-a716-446655440000" format:"uuid"`
}

//  example
var (
	ErrNameInvalid = errors.New("name is empty")
	ErrNoRow       = errors.New("no rows in result set")
)

// AddAccount example
// Name以外的字段仅用来测试 struct tag 的作用
type AddAccount struct {
	Name   string  `json:"name" example:"Tom" format:"string" binding:"required" minLength:"1" maxLength:"16"` // 用户名
	Age    int     `json:"age" example:"10" binding:"required" minimum:"1" maximum:"150" default:"10"`         // 年龄
	Height float64 `json:"height" example:"1.80" binding:"required" minimum:"0.0" maximum:"9.99"`            // 身高,单位米
	Status string  `json:"status" enums:"healthy,ill"`     // 状态
}

// Validation example
func (a AddAccount) Validation() error {
	switch {
	case len(a.Name) == 0:
		return ErrNameInvalid
	default:
		return nil
	}
}

// AccountOne example
func AccountOne(id int) (Account, error) {
	for _, v := range accounts {
		if id == v.ID {
			return v, nil
		}
	}
	return Account{}, ErrNoRow
}

// Insert example
func (a Account) Insert() (int, error) {
	accountMaxID++
	a.ID = accountMaxID
	a.Name = fmt.Sprintf("account_%d", accountMaxID)
	accounts = append(accounts, a)
	return accountMaxID, nil
}

var accountMaxID = 3
var accounts = []Account{
	{ID: 1, Name: "account_1"},
	{ID: 2, Name: "account_2"},
	{ID: 3, Name: "account_3"},
}

swag生成API文档

在项目根目录下执行以下命令生成docs目录

swag init

YApi管理项目的API的文档

打开localhost:40001登录YApi

  1. 在个人空间下创建一个test分组,组长填自己的用户名好了

  2. test分组下创建一个项目demo

  3. 导入上面生成的docs/swagger.json文件,如图
    YApi结合swag管理和生成go项目restful API文档_第1张图片

  4. 查看导入的接口
    YApi结合swag管理和生成go项目restful API文档_第2张图片
    YApi结合swag管理和生成go项目restful API文档_第3张图片
    YApi结合swag管理和生成go项目restful API文档_第4张图片

在上图可以看到,model.AddAccount结构体附属的struct tag 和字段的注释已经变成文档的一部分了

同时还可以像postman一样测试接口,其他功能就不说了,留待你们自己挖掘
YApi结合swag管理和生成go项目restful API文档_第5张图片

总结

在go项目中,开发人员只要把代码的注解写好,然后用swag生成相关文件,YApi导入json文件,整个项目的接口管理变的清晰简单。不过文档没有swagger ui展示的那么详细,可以看情况搭配使用。

你可能感兴趣的:(golang)