使用 go-swagger 爲 golang API 自動生成 swagger 文檔
【導讀】swagger 定義接口、自動生成 go 接口代碼的操作如何落地?本文做了詳細介紹。
什麼是 swagger?
Swagger 是一個簡單但功能強大的 API 表達工具。它具有地球上最大的 API 工具生態系統,數以千計的開發人員,使用幾乎所有的現代編程語言,都在支持和使用 Swagger。使用 Swagger 生成 API,我們可以得到交互式文檔,自動生成代碼的 SDK 以及 API 的發現特性等。
swagger 文檔長啥樣?
一個最簡單的 swagger 文檔示例:
swagger: "2.0"
info:
version: 1.0.0
title: Simple API
description: A simple API to learn how to write OpenAPI Specification
schemes:
- https
host: simple.api
basePath: /openapi101
paths: {}
本文背景介紹
寫作本文的原因是因爲公司要求 api 文檔都使用 swagger 格式,項目是用 golang 編寫的,作爲一個懶癌程序員,怎麼能夠忍受去編寫這麼複雜的 swagger 文檔呢?有沒有一鍵生成的工具呢?google 一下,還真有, 那就是 go-swagger 項目。go-swagger 衆多特色功能之一就是 Generate a spec from source, 即通過源碼生成文檔,很符合我的需求。
下面就簡單介紹下如何爲項目加上 swagger 註釋,然後一鍵生成 API 文檔
開始之前需要安裝兩個工具:
-
swagger-editor: 用於編寫 swagger 文檔,UI 展示,生成代碼等...
-
go-swagger: 用於一鍵生成 API 文檔
安裝 swagger-editor, 我這裏使用 docker 運行,其他安裝方式,請查看官方文檔:
docker pull swaggerapi/swagger-editor
docker run --rm -p 80:8080 swaggerapi/swagger-editor
安裝 go-swagger, 我這邊使用 brew 安裝,其他安裝方式,請查看官方文檔
brew tap go-swagger/go-swagger
brew install go-swagger
好了,現在終於開始正題:start coding!!!
開始編寫註釋
- 假設有一個 user.server,提供一些 REST API,用於對用戶數據的增刪改查。
比如這裏有一個getOneUser
接口,是查詢用戶信息的:
package service
import (
"encoding/json"
"fmt"
"net/http"
"strconv"
"user.server/models"
"github.com/Sirupsen/logrus"
)
type GetUserParam struct {
Id int `json:"id"`
}
func GetOneUser(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
decoder := json.NewDecoder(r.Body)
var param GetUserParam
err := decoder.Decode(¶m)
if err != nil {
WriteResponse(w, ErrorResponseCode, "request param is invalid, please check!", nil)
return
}
// get user from db
user, err := models.GetOne(strconv.Itoa(param.Id))
if err != nil {
logrus.Warn(err)
WriteResponse(w, ErrorResponseCode, "failed", nil)
return
}
WriteResponse(w, SuccessResponseCode, "success", user)
}
根據 swagger 文檔規範,一個 swagger 文檔首先要有 swagger 的版本和 info 信息。利用 go-swagger 只需要在聲明 package 之前加上如下注釋即可:
// Package classification User API.
//
// The purpose of this service is to provide an application
// that is using plain go code to define an API
//
// Host: localhost
// Version: 0.0.1
//
// swagger:meta
package service
然後在項目根目錄下使用swagger generate spec \-o ./swagger.json
命令生成swagger.json
文件:
此命令會找到 main.go 入口文件,然後遍歷所有源碼文件,解析然後生成 swagger.json 文件
{
"swagger": "2.0",
"info": {
"description": "The purpose of this service is to provide an application\nthat is using plain go code to define an API",
"title": "User API.",
"version": "0.0.1"
},
"host": "localhost",
"paths": {}
}
- 基本信息有了,然後就要有路由,請求,響應等,下面針對 getOneUser 接口編寫 swagger 註釋:
// swagger:parameters getSingleUser
type GetUserParam struct {
// an id of user info
//
// Required: true
// in: path
Id int `json:"id"`
}
func GetOneUser(w http.ResponseWriter, r *http.Request) {
// swagger:route GET /users/{id} users getSingleUser
//
// get a user by userID
//
// This will show a user info
//
// Responses:
// 200: UserResponse
decoder := json.NewDecoder(r.Body)
var param GetUserParam
err := decoder.Decode(¶m)
if err != nil {
WriteResponse(w, ErrorResponseCode, "request param is invalid, please check!", nil)
return
}
// get user from db
user, err := models.GetOne(strconv.Itoa(param.Id))
if err != nil {
logrus.Warn(err)
WriteResponse(w, ErrorResponseCode, "failed", nil)
return
}
WriteResponse(w, SuccessResponseCode, "success", user)
}
可以看到在GetUserParam
結構體上面加了一行swagger:parameters getSingleUser
的註釋信息,這是聲明接口的入參註釋,結構體內部的幾行註釋指明瞭 id 這個參數必填,並且查詢參數 id 是在 url path 中。詳細用法,參考: swagger:params
在GetOneUser
函數中:
-
swagger:route
指明使用的 http method,路由,以及標籤和 operation id, 詳細用法,參考:swagger:route -
Responses
指明瞭返回值的 code 以及類型
然後再聲明響應:
// User Info
//
// swagger:response UserResponse
type UserWapper struct {
// in: body
Body ResponseMessage
}
type ResponseMessage struct {
Code int `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data"`
}
使用swagger:response
語法聲明返回值,其上兩行是返回值的描述(我也不清楚,爲啥描述信息要寫在上面,歡迎解惑), 詳細用法,參考;swagger:response
然後瀏覽器訪問localhost
, 查看 swagger-editor 界面, 點擊工具欄中的File->Impoprt File
上傳剛纔生成的 swagger.json
文件,就可以看到界面:
這樣一個簡單的 api 文檔就生成了
- 怎麼樣?是不是很簡單?可是又感覺那裏不對,嗯,註釋都寫在代碼裏了,很不美觀,而且不易維護。想一下 go-swagger 的原理是掃描目錄下的所有 go 文件,解析註釋信息。那麼是不是可以把 api 註釋都集中寫在單個文件內,統一管理,免得分散在各個源碼文件內。
新建一個doc.go
文件,這裏還有一個接口是UpdateUser
, 那麼我們在 doc.go 文件中聲明此接口的 api 註釋。先看一下UpdateUser
接口的代碼:
func UpdateUser(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
// decode body data into user struct
decoder := json.NewDecoder(r.Body)
user := models.User{}
err := decoder.Decode(&user)
if err != nil {
WriteResponse(w, ErrorResponseCode, "user data is invalid, please check!", nil)
return
}
// check if user exists
data, err := models.GetUserById(user.Id)
if err != nil {
logrus.Warn(err)
WriteResponse(w, ErrorResponseCode, "query user failed", nil)
return
}
if data.Id == 0 {
WriteResponse(w, ErrorResponseCode, "user not exists, no need to update", nil)
return
}
// update
_, err = models.Update(user)
if err != nil {
WriteResponse(w, ErrorResponseCode, "update user data failed, please try again!", nil)
return
}
WriteResponse(w, SuccessResponseCode, "update user data success!", nil)
}
然後再 doc.go 文件中編寫如下聲明:
package service
import "user.server/models"
// swagger:parameters UpdateUserResponseWrapper
type UpdateUserRequest struct {
// in: body
Body models.User
}
// Update User Info
//
// swagger:response UpdateUserResponseWrapper
type UpdateUserResponseWrapper struct {
// in: body
Body ResponseMessage
}
// swagger:route POST /users users UpdateUserResponseWrapper
//
// Update User
//
// This will update user info
//
// Responses:
// 200: UpdateUserResponseWrapper
這樣就把 api 聲明註釋給抽離出來了,然後使用命令swagger generate spec \-o ./swagger.json
生成 json 文件, 就可以看到這樣的結果:
很簡單吧,參照文檔編寫幾行註釋,然後一個命令生成 API 文檔。懶癌程序員福音~
轉自:
juejin.cn/post/6844903609390333965
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/DfZf8FEx-jgqb3yYRWNkWw