這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。為你的 API 提供一個文檔比你想象中更加有用,即使你沒有公開你的 API ,為你的前端或者移動團隊提供一個文檔會比你提供/片段或使用 Postman/Insomnia (帶有同步的進階版本)等付費產品更容易。藉助 SwaggerUI ,您可以自動獲得所有 API 的設計良好的文檔。當切換到 Go 時,由於缺少文檔/教程,我在配置它的時候出現了一些問題,所以我決定寫一個。![goswagger](https://raw.githubusercontent.com/studygolang/gctt-images/master/swagger-golang/swagger-golang1.jpg)樣本程式:[連結](https://github.com/ribice/golang-swaggerui-example)大約兩年前,我曾經在開發一個 RESTful 風格的公司專屬應用程式的後台時,第一次知道 [SwaggerUI](https://swagger.io/swagger-ui/) 。 SwaggerUI 的創造者 SmartBear 將其產品描述為:> "Swagger UI 允許任何人(無論是你的Team Dev還是終端使用者)在沒有任何實現邏輯的情況下對 API 資源進行可視化和互動。它(API文檔)通過 Swagger 定義自動產生,可視化文檔使得後端實現和用戶端消費變得更加容易。"簡而言之,通過提供 Swagger(OpenAPI)定義,您可以獲得與 API 進行互動的介面,而不必關心程式設計語言本身。你可以將 Swagger(OpenAPI) 視為 REST 的 WSDL 。作為參考,Swagger Codegen 可以從這個定義中,用幾十種程式設計語言來產生用戶端和伺服器代碼。回到那個時候,我使用的是 Java 和 SpringBoot ,覺得 Swagger 簡單易用。你僅需建立一次 bean ,並添加一兩個註解到端點上,再添加一個標題和一個項目描述。此外,我習慣將所有請求從 “/” 重新導向到 “/swagger-ui” 以便在我開啟 `host:port` 時自動跳轉到 SwaggerUI 。在運行應用程式的時候, SwaggerUI 在同一個連接埠依然可用。(例如,您的應用程式運行在`[host]:[port]`, SwaggerUI 將在`[host]:[port]/swagger-ui`上訪問到)。快一年半之後,我想在我們的 Go 項目中實現 SwaggerUI 。問題是 —— 感覺太複雜了。當我在網路上搜尋時,我看到不僅僅是我,其他許多使用者也遇到了同樣的麻煩。我偶然發現了 Go-Swagger 項目。他們的 [GitHub Readme](https://github.com/go-swagger/go-swagger) 談論的是 Swagger ,而不是 SwaggerUI 。你得有一個用戶端,伺服器,中介軟體和一些其他的東西,才可以考慮 SwaggerUI 。簡而言之, Swagger 伺服器/用戶端用於從 Swagger 定義(swagger.json)中產生(後端)代碼。產生伺服器使您可以從規範中提供 API ,同時為這些 API 使用者產生用戶端。把它看作代碼產生工具。我覺得這很有用,但那不是我想要的。在社區的協助下(向 [casualjim](https://github.com/casualjim) 致意)和一些調查,我成功地為我們的項目產生了沒有太多的樣板代碼的 API 文檔。另外,我準備了一個實現了 go-swagger 注釋來產生有效 swagger 文檔樣本,可以[在這裡](https://github.com/ribice/golang-swaggerui-example)找到。## 安裝 Go-Swagger在開始之前,您需要在本地機器上安裝 go swagger 。這不是一個強制性的步驟,但會使得更容易的使用 swagger 工作。安裝它可以讓你在本地測試你的注釋,否則,你只能依靠你的 CI 工具。最簡單的安裝方式是通過運行 Homebrew / Linuxbrew :```consolebrew tap go-swagger/go-swaggerbrew install go-swagger```此外,你可以從[這裡](https://github.com/ribice/golang-swaggerui-example)得到最新的二進位檔案。## Swagger:meta [[docs]](https://goswagger.io/generate/spec/meta.html)![swagger-meta](https://raw.githubusercontent.com/studygolang/gctt-images/master/swagger-golang/swagger-golang2.jpg)這是你應該添加到項目中的第一個注釋。它被用來描述你的項目名稱,描述,聯絡電子郵件,網站,許可證等等。如果你的 API 僅提供在 HTTP 或 HTTPS 上,且只產生 JSON ,您應在此處添加它 - 允許你從每個路由中刪除該注釋。安全也被添加在 swagger:meta 中,在 SwaggerUI 上添加一個授權按鈕。為了實現JWT,我使用安全類型承載進行命名並將其定義為:```go// Security:// - bearer//// SecurityDefinitions:// bearer:// type: apiKey// name: Authorization// in: header//```## Swagger:route [[docs]](https://goswagger.io/generate/spec/route.html)有兩種方式兩個注釋你的路由,swagger:operation 和swagger:route 。兩者看起來都很相似,那麼主要區別是什嗎?把 swagger:route 看作簡單 API 的短注釋,它適用於沒有輸入參數(路徑/查詢參數)的 API 。那些(帶有參數)的例子是 /repos/{owner} , /user/{id} 或者 /users/search?name=ribice如果你有一個那種類型,那麼你就必須使用 swagger:operation ,除此之外,如 /user 或 /version 之類的 APIs 都可以用 swagger:route 來注釋。**swagger:route**注釋包含以下內容:```go// swagger:route POST /repo repos users createRepoReq// Creates a new repository for the currently authenticated user.// If repository name is "exists", error conflict (409) will be returned.// responses:// 200: repoResp// 400: badReq// 409: conflict// 500: internal```1. **swagger:route** - 註解2. **POST** - HTTP方法3. /**repo** - 匹配路徑,端點4. **repos** - 路由所在的空間分割標籤,例如,“repos users”5. **createRepoReq** - 用於此端點的請求(詳細的稍後會解釋)6. **Creates a new repository …** - 摘要(標題)。對於swager:route注釋,在第一個句號(.)前面的是標題。如果沒有句號,就會沒有標題並且這些文字會被用於描述。7. **If repository name exists …** - 描述。對於swager:route類型注釋,在第一個句號(.)後面的是描述。8. **responses**: - 這個端點的響應9. **200: repoResp** - 一個(成功的)響應HTTP狀態 200,包含 repoResp(用 swagger:response 注釋的模型)10. **400: badReq, 409: conflict, 500: internal** - 此端點的錯誤響應(錯誤請求,衝突和內部錯誤, 定義在 cmd/api/swagger/model.go 下)如此注釋您的端點將產生以下內容:![swagger-route-ui](https://raw.githubusercontent.com/studygolang/gctt-images/master/swagger-golang/swagger-golang3.jpg)請記住,您還可能需要使用其他注釋,具體取決於您的 API 。由於我將我的項目定義為僅使用單一模式( https ),並且我的所有 API 都使用 https ,所以我不需要單獨注釋方案。如果您為端點使用多個模式,則需要以下注釋:```go// Schemes: http, https, ws, wss```同樣適用於 消費者/生產者 媒體類型。我所有的 API 都只消費/產生 application/json 。如果您的 API 正在 消費/產生 其他類型,則需要使用該媒體類型對其進行注釋。例如:```go// consumes:// - application/json// - application/x-protobuf//// produces:// - application/json// - application/x-protobuf```安全性:```go// security:// api_key:// oauth: read, write// basicAuth:// type: basic// token:// type: apiKey// name: token// in: query// accessToken:// type: apiKey// name: access_token// in: query```另一方面,swagger:operation 用於更複雜的端點。三個破折號(-)下的部分被解析為 YAML ,允許更複雜的注釋。確保您的縮排是一致的和正確的,否則將無法正確解析。## Swagger:operation [docs](https://goswagger.io/generate/spec/operation.html)使用 Swagger:operation 可以讓你使用所有[OpenAPI規範](https://swagger.io/specification/),你可以描述你的複雜的端點。如果你對細節感興趣,你可以閱讀規範文檔。簡單來說 - swagger:operation 包含如下內容:```go// swagger:operation GET /repo/{author} repos repoList// ---// summary: List the repositories owned by the given author.// description: If author length is between 6 and 8, Error Not Found (404) will be returned.// parameters:// - name: author// in: path// description: username of author// type: string// required: true// responses:// "200":// "$ref": "#/responses/reposResp"// "404":// "$ref": "#/responses/notFound"```1. **swagger:operation** - 注釋2. **GET** - HTTP 方法3. /**repo/{author}** - 匹配路徑,端點4. **repos** - 路由所在的空間分割標籤,例如,“repos users”5. **repoList** - 用於此端點的請求。這個不存在(沒有定義),但參數是強制性的,所以你可以用任何東西來替換repoList(noReq,emptyReq等)6. --- - 這個部分下面是YAML格式的swagger規範。確保您的縮排是一致的和正確的,否則將無法正確解析。注意,如果你在YAML中定義了標籤,摘要,描述或操作標籤,將覆蓋上述常規swagger文法中的摘要,描述,標記或操作標籤。7. **summary**: - 標題8. **description**: - 描述9. **parameters**: - URL參數(在這個例子中是{author})。字串格式,強制性的(Swagger不會讓你調用端點而不輸入),位於路徑(/{author})中。另一種選擇是參數內嵌的請求 (?name="")定義你的路由後,你需要定義你的請求和響應。從樣本中,你可以看到,我建立了一個新的包,命名為 swagger 。這不是強制性的,它把所有樣板代碼放在一個名為 swagger 的包中。但缺點是你必須匯出你的所有 HTTP 要求和響應。如果你建立了一個單獨的 Swagger 包,確保將它匯入到你的主/伺服器檔案中(你可以通過在匯入前加一個底線來實現):```go_ "github.com/ribice/golang-swaggerui-example/cmd/swagger"```## Swagger:parameters [[docs]](https://goswagger.io/generate/spec/params.html)根據您的應用程式模型,您的 HTTP 要求可能會有所不同(簡單,複雜,封裝等)。要產生 Swagger 規範,您需要為每個不同的請求建立一個結構,甚至包含僅包含數字(例如id)或字串(名稱)的簡單請求。一旦你有這樣的結構(例如一個包含一個字串和一個布爾值的結構),在你的Swagger包中定義如下:```go// Request containing string// swagger:parameters createRepoReqtype swaggerCreateRepoReq struct {// in:bodyapi.CreateRepoReq}```- 第 1 行包含一個在 SwaggerUI 上可見的注釋- 第 2 行包含 swagger:parameters 注釋,以及請求的名稱(operationID)。此名稱用作路由注釋的最後一個參數,以定義請求。- 第 4 行包含這個參數的位置(in:body,in:query 等)- 第 5 行是實際的內嵌結構。正如前面所提到的,你不需要一個獨立的 swagger 批註包(你可以把swagger:parameters注釋放在 api.CreateRepoReq 上),但是一旦你開始建立響應注釋和驗證,那麼在 swagger 相關批註一個單獨的包會更清晰。![swagger-parameters](https://raw.githubusercontent.com/studygolang/gctt-images/master/swagger-golang/swagger-golang4.jpg)如果你有大的請求,比如建立或更新,你應該建立一個新類型的變數,而不是內嵌結構。例如(注意第五行的區別):```go// Request containing string// swagger:parameters createRepoReqtype swaggerCreateRepoReq struct {// in:bodyBody api.CreateRepoReq}```這會產生以下 SwaggerUI 請求:![swagger-patameters-ui](https://raw.githubusercontent.com/studygolang/gctt-images/master/swagger-golang/swagger-golang5.jpg) Swagger 有很多驗證注釋提供給 swagger:parameters和 swagger:response ,在注釋標題旁邊的文檔中有詳細的描述和使用方法。## Swagger:response [[docs]](https://goswagger.io/generate/spec/response.html)響應注釋與參數注釋非常相似。主要的區別在於,經常將響應包裹到更複雜的結構中,所以你必須要在 swagger 中考慮到這點。在我的樣本中,我的成功響應如下所示:```json{ "code":200, // Code containing HTTP status CODE "data":{} // Data containing actual response data}```雖然錯誤響應有點不同:```json{ "code":400, // Code containing HTTP status CODE "message":"" // String containing error message}```要使用常規響應,像上面錯誤響應那樣的,我通常在 swagger 包內部建立 model.go(或swagger.go)並在裡面定義它們。在樣本中,下面的響應用於 OK 響應(不返回任何資料):```go// Success response// swagger:response oktype swaggScsResp struct {// in:bodyBody struct {// HTTP status code 200 - OKCode int `json:"code"`}}```對於錯誤響應,除了名稱(和樣本的情況下的 HTTP 代碼注釋)之外,它們中的大多數類似於彼此。儘管如此,你仍然應該為每一個錯誤的情況進行定義,以便把它們作為你的端點可能的響應:```go// Error Forbidden// swagger:response forbiddentype swaggErrForbidden struct {// in:bodyBody struct {// HTTP status code 403 - ForbiddenCode int `json:"code"`// Detailed error messageMessage string `json:"message"`}}``` data 中包含 model.Repository 的樣本響應:```go// HTTP status code 200 and repository model in data// swagger:response repoResptype swaggRepoResp struct {// in:bodyBody struct {// HTTP status code 200/201Code int `json:"code"`// Repository modelData model.Repository `json:"data"`}}``` data 中包含 model.Repository 切片的樣本響應:```go// HTTP status code 200 and an array of repository models in data// swagger:response reposResptype swaggReposResp struct {// in:bodyBody struct {// HTTP status code 200 - Status OKCode int `json:"code"`// Array of repository modelsData []model.Repository `json:"data"`}}```總之,這將足以產生您的 API 文檔。您也應該向文檔添加驗證,但遵循本指南將協助您開始。由於這主要是由我自己的經驗組成,並且在某種程度上參考了 Gitea 的[原始碼](https://github.com/go-gitea/gitea),我將會聽取關於如何改進這部分並相應更新的反饋。如果您有一些問題或疑問,我建議您查看[如何產生FAQ](https://goswagger.io/faq/faq_spec.html)。## 本地運行 SwaggerUI一旦你的注釋準備就緒,你很可能會在你的本地環境中測試它。要做到這一點,你需要運行兩個命令:1. Generate spec [[docs]](https://goswagger.io/generate/spec.html)2. Serve [[docs]](https://goswagger.io/usage/serve_ui.html)這個命令我們用來產生 swagger.json 並使用 SwaggerUI:```consoleswagger generate spec -o ./swagger.json --scan-modelsswagger serve -F=swagger swagger.json```或者,如果你只想使它成為一個命令:```consoleswagger generate spec -o ./swagger.json --scan-models && swagger serve -F=swagger swagger.json```執行該命令後,將使用 [Petstore](http://petstore.swagger.io/) 託管的 SwaggerUI 開啟一個新選項卡。伺服器啟用了 CORS,並將標準 JSON 的 URL 作為請求字串附加到 petstore URL。另外,如果使用 Redoc flavor(-F = redoc),則文檔將託管在您自己的電腦上(localhost:port/docs)。## 在伺服器上部署在伺服器上部署產生的 SwaggerUI 有很多種方法。一旦你產生了 swagger.json,它應該相對容易地被運行。例如,我們的應用程式正在 Google App Engine 上運行。Swagger Spec 由我們的 CI 工具產生,並在 /docs 路徑上提供。我們將 SwaggerUI 作為 Docker 服務部署在 GKE(Google Container/Kubernates Engine)上,它從 /docs 路徑中擷取swagger.json。我們的 CI(Wercker)指令碼的一部分:```yamlbuild:steps:- script:name: workspace setupcode: |mkdir -p $GOPATH/src/github.com/orga/repocp -R * $GOPATH/src/github.com/orga/repo/- script:cwd: $GOPATH/src/bitbucket.org/orga/repo/cmd/api/name: buildcode: |go get -u github.com/go-swagger/go-swagger/cmd/swaggerswagger generate spec -o ./swagger.json --scan-modelsCGO_ENABLED=0 go build -a -ldflags '-s' -installsuffix cgo -o app .cp app *.template Dockerfile swagger.json "$WERCKER_OUTPUT_DIR"```路由:```gofunc (d *Doc) docHandler(c context.Context, w http.ResponseWriter, r *http.Request) {r.Header.Add("Content-Type", "application/json")data, _ := ioutil.ReadFile("/swagger.json")w.Write(data)}```Dockerfile:```DockerfileFROM swaggerapi/swagger-uiENV API_URL "https://api.orga.com/swagger"```## 總結SwaggerUI 是一個功能強大的 API 文檔工具,可以讓您輕鬆而漂亮地記錄您的 API。在 go-swagger 項目的協助下,您可以輕鬆地產生 SwaggerUI 所需的swagger規範檔案(swagger.json)。總之,我描述了為實現這一目標所採取的步驟。可能有更好的方法,我會確保根據收到的反饋更新這篇文章。樣本在 [GitHub](https://github.com/ribice/golang-swaggerui-example)上可用。從樣本產生的 Swagger.json 在[LINK](https://ribice.ba/goswagg/v1/swagger)。
via: https://www.ribice.ba/swagger-golang/
作者:Emir Ribic 譯者:fatalc 校對:rxcai
本文由 GCTT 原創編譯,Go語言中文網 榮譽推出
本文由 GCTT 原創翻譯,Go語言中文網 首發。也想加入譯者行列,為開源做一些自己的貢獻嗎?歡迎加入 GCTT!
翻譯工作和譯文發表僅用於學習和交流目的,翻譯工作遵照 CC-BY-NC-SA 協議規定,如果我們的工作有侵犯到您的權益,請及時聯絡我們。
歡迎遵照 CC-BY-NC-SA 協議規定 轉載,敬請在本文中標註並保留原文/譯文連結和作者/譯者等資訊。
文章僅代表作者的知識和看法,如有不同觀點,請樓下排隊吐槽
2447 次點擊 ∙ 1 贊