こんにちは。KOUKIです。
とあるWeb系企業で、Goエンジニアをやっています。
前回は、Go言語のフレームワークである「Gin」を使って簡単なAPI開発手法を紹介しました。
今回は、OpenAPIの紹介をしたいと思います。
参考
以下のリポジトリを参考にしています。
https://github.com/PacktPublishing/Building-Distributed-Applications-in-Gin
環境
Mac + Chromeで開発します。
前回
前回は、CRUDのAPIを開発しました。
OpenAPIとは
OpenAPIは、開発したRestful APIの仕様をドキュメント化するツールです。Swaggerとも呼ばれます。
これは、以下の機能を持っています。
- APIの仕様をドキュメントとして生成する
- 簡単なHTTPリクエストのデモが行える
Install
go-swaggerをインストールしましょう。
色々と方法はありますが、今回は私の大好きなDockerでインストールしたいと思います。
1 2 3 4 5 6 7 8 9 |
# docker imageをpull docker pull quay.io/goswagger/swagger # aliasを貼る alias swagger='docker run --rm -it --user $(id -u):$(id -g) -e GOPATH=$(go env GOPATH):/go -v $HOME:$HOME -w $(pwd) quay.io/goswagger/swagger' swagger version version: v0.28.0 commit: 48a66e4bdbcde02c8c6c95ff9a08f64fe40b1b50 |
aliasを毎回貼るのはめんどくさそうですね。
OpenAPI(Swagger)のメタデータ
OpenAPIでドキュメントを生成するには、フォーマットとなるメタデータを理解する必要があります。
プロパティ | 説明 |
---|---|
Schemes | APIでサポートされているプロトコル(http or https)を指定する |
Host | APIサーバーのホスト(例: localhost:8080) |
BasePath | APIのデフォルトベースパス(/) |
Version | APIの現在のバージョン |
Contact | APIのオーナーか開発者 |
Consumes | 受け取る時のデフォルトのMIME type(例: application/json) |
Produces | 送る時のデフォルトのMIM typeのリスト |
上記を参考に、前回作成したmain関数にドキュメントを追加しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
// Recipes API // // これはサンプルAPIです。 // // Schemes: http // Host: localhost:8080 // BasePath: / // Version: 1.0.0 // Contact: Self Note<selfnote@example.com> https://selfnote.work/ // // Consumes: // - application/json // // Produces: // - application/json // swagger:meta // main.go package main import "recipe-api/routes" func main() { router := routes.NewRoutes() router.Run() } |
こんな感じで、package mainの上にドキュメント(コメント)を書きます。
ドキュメントの生成
以下のコマンドで、ドキュメントを生成します。
1 2 3 |
$ swagger generate spec -o ./swagger.json err: exit status 1: stderr: failed to initialize build cache at /.cache/go-build: mkdir /.cache: permission denied |
なんかエラーが出ました。Dockerから権限のあるフォルダにアクセスする時にエラーが出る様です…
上記の記事を参考にaliasを修正します。
1 |
alias swagger='docker run --rm -it --user $(id -u):$(id -g) -e GOPATH=$(go env GOPATH):/go -v $HOME:$HOME -w $(pwd) quay.io/goswagger/swagger' |
気を取り直して、再度コマンドを実行しましょう。
1 |
$ swagger generate spec -o ./swagger.json |
コマンドの実行に成功するとコマンドを実行したディレクトリの階層に「swagger.json」ファイルが生成されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
{ "consumes": [ "application/json" ], "produces": [ "application/json" ], "schemes": [ "http" ], "swagger": "2.0", "info": { "description": "これはサンプルAPIです。", "title": "Recipes API", "contact": { "name": "Self Note", "url": "https://selfnote.work/", "email": "selfnote@example.com" }, "version": "1.0.0" }, "host": "localhost:8080", "basePath": "/", "paths": {} } |
yaml形式で出力したい場合は、拡張子を変えるだけでOKです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
$ swagger generate spec -o ./swagger.yaml basePath: / consumes: - application/json host: localhost:8080 info: contact: email: selfnote@example.com name: Self Note url: https://selfnote.work/ description: これはサンプルAPIです。 title: Recipes API version: 1.0.0 paths: {} produces: - application/json schemes: - http swagger: "2.0" |
ドキュメントを表示する
ドキュメントを表示しましょう。
Dockerで動かしているので、外部からリクエストを受信できるようにportオプションを付ける必要があります。
1 |
alias swagger="docker run --rm -it -p 3000:3000 --user $(id -u):$(id -g) -e XDG_CACHE_HOME=/tmp/.cache -e GOPATH=$HOME/go:/go -v $HOME:$HOME -w $(pwd) quay.io/goswagger/swagger" |
上記は、3000番PortでDockerコンテナに繋げるようにした例です。
続いて、OpenAPIのサーバーを下記のコマンドで立ち上げます。
1 |
$ swagger serve ./swagger.json --no-open --port 3000 --host 0.0.0.02021/11/22 21:24:40 serving docs at http://localhost:3000/docs |
「http://localhost:3000」にアクセスしましょう。

おお。素晴らしいですね。
オプションを変えれば、別のUIが見れます。
1 2 |
$ swagger serve -F swagger ./swagger.json --no-open --port 3000 --host 0.0.0.0 2021/11/22 21:28:42 serving docs at http://localhost:3000/docs |

かっこいいですね。
エンドポイントを設定する
お次は、エンドポイントを設定してみましょう。
プロパティ | 説明 |
---|---|
Summary | エンドポイントの概要 |
Responses | レスポンスのリスト |
Parameters | エンドポイントに渡すパラメータのリスト |
Consumes | 受信時のMIMEタイプのリスト(例: application/json) |
Produces | 送信時のMIMEタイプのリスト(例: application/json) |
早速、定義してみましょう。
ListRecipesHandler
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
// handlers/listrecipeshandler.go // swagger:operation GET /recipes recipes listRecipes // Returns list of recipes // --- // produces: // - application/json // responses: // '200': // description: Successful operation package handlers import ( "net/http" "github.com/gin-gonic/gin" ) func ListRecipesHandler(c *gin.Context) { c.JSON(http.StatusOK, recipes) } |
main関数のようにコメントに書きました。インデントとか誤字に注意して下さい。
以下のコマンドで、swagger.jsonを生成します。
1 |
swagger generate spec -o ./swagger.json |
swagger.jsonの中身を確認してみると、新しく行が追加されたことがわかります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
{ "consumes": [ "application/json" ], "produces": [ "application/json" ], "schemes": [ "http" ], "swagger": "2.0", "info": { "description": "これはサンプルAPIです。", "title": "Recipes API", "contact": { "name": "Self Note", "url": "https://selfnote.work/", "email": "selfnote@example.com" }, "version": "1.0.0" }, "host": "localhost:8080", "basePath": "/", "paths": { "/recipes": { "get": { "description": "Returns list of recipes", "produces": [ "application/json" ], "tags": [ "recipes" ], "operationId": "listRecipes", "responses": { "200": { "description": "Successful operation" } } } } } } |
下記のコマンドで、Swagger サーバーを立ち上げましょう。
1 |
swagger serve -F swagger ./swagger.json --no-open --port 3000 --host 0.0.0.0 |

いい感じですね。
上記画面の「Try it out」->「Execute」を押下してみましょう。

curl例やRequest URLが出てきて、とてもいい感じのドキュメントですね。
そのほかのエンドポイント
他のエンドポイントも設定していきましょう。
NewRecipeHandler
1 2 3 4 5 6 7 8 9 10 11 |
// handlers/newrecipehandler.go // swagger:operation POST /recipes recipes newRecipe // Create a new recipe // --- // produces: // - application/json // responses: // '200': // description: Successful operation // '400': // description: Invalid input |
UpdateRecipeHandler
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
// handlers/updaterecipeshandler.go // swagger:operation PUT /recipes/{id} recipes updateRecipe // Update an existing recipe // --- // parameters: // - name: id // in: path // description: ID of the recipe // required: true // type: string // produces: // - application/json // responses: // '200': // description: Successful operation // '400': // description: Invalid input // '404': // description: Invalid recipe ID |
DeleteRecipeHandler
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// handlers/deleterecipehandler.go // swagger:operation DELETE /recipes/{id} recipes deleteRecipe // Delete an existing recipe // --- // produces: // - application/json // parameters: // - name: id // in: path // description: ID of the recipe // required: true // type: string // responses: // '200': // description: Successful operation // '404': // description: Invalid recipe ID |
SearchRecipesHandler
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// handlers/searchrecipehandler.go // swagger:operation GET /recipes/search recipes findRecipe // Search recipes based on tags // --- // produces: // - application/json // parameters: // - name: tag // in: query // description: recipe tag // required: true // type: string // responses: // '200': // description: Successful operation |
swagger.jsonの生成
1 |
swagger generate spec -o ./swagger.json |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
{ "consumes": [ "application/json" ], "produces": [ "application/json" ], "schemes": [ "http" ], "swagger": "2.0", "info": { "description": "これはサンプルAPIです。", "title": "Recipes API", "contact": { "name": "Self Note", "url": "https://selfnote.work/", "email": "selfnote@example.com" }, "version": "1.0.0" }, "host": "localhost:8080", "basePath": "/", "paths": { "/recipes": { "get": { "description": "Returns list of recipes", "produces": [ "application/json" ], "tags": [ "recipes" ], "operationId": "listRecipes", "responses": { "200": { "description": "Successful operation" } } }, "post": { "description": "Create a new recipe", "produces": [ "application/json" ], "tags": [ "recipes" ], "operationId": "newRecipe", "responses": { "200": { "description": "Successful operation" }, "400": { "description": "Invalid input" } } } }, "/recipes/search": { "get": { "description": "Search recipes based on tags", "produces": [ "application/json" ], "tags": [ "recipes" ], "operationId": "findRecipe", "parameters": [ { "type": "string", "description": "recipe tag", "name": "tag", "in": "query", "required": true } ], "responses": { "200": { "description": "Successful operation" } } } }, "/recipes/{id}": { "put": { "description": "Update an existing recipe", "produces": [ "application/json" ], "tags": [ "recipes" ], "operationId": "updateRecipe", "parameters": [ { "type": "string", "description": "ID of the recipe", "name": "id", "in": "path", "required": true } ], "responses": { "200": { "description": "Successful operation" }, "400": { "description": "Invalid input" }, "404": { "description": "Invalid recipe ID" } } }, "delete": { "description": "Delete an existing recipe", "produces": [ "application/json" ], "tags": [ "recipes" ], "operationId": "deleteRecipe", "parameters": [ { "type": "string", "description": "ID of the recipe", "name": "id", "in": "path", "required": true } ], "responses": { "200": { "description": "Successful operation" }, "404": { "description": "Invalid recipe ID" } } } } } } |
APIドキュメントの表示
下記のコマンドで、ドキュメントを表示します。
1 |
$ swagger serve -F swagger ./swagger.json --no-open --port 3000 --host 0.0.0.0 |

結構いい感じですね。
実務でも取り入れたいと思います。
次回
次回は未定ですが、Docker化とDBの導入に挑戦したいと思ってます!
コメントを残す
コメントを投稿するにはログインしてください。