The Gopher character is based on the Go mascot designed by Renée French.
TIG DXチームの伊藤真彦です。
今回はgo-swaggerの具体的な実装方法を紹介します。
目次
- はじめに
- go-swaggerのインストール
- swagger.yamlを準備する
- ソースコードをビルドする
- 試しにサーバーを立ち上げてみる
- ハンドラを実装する
- ついにhello world完了
はじめに
最近の私のメイン業務はgo-swaggerを用いたAPI開発です。
go-swaggerはOpenAPI(Swagger) からGoのコードを生成するライブラリです。
フューチャーでは複数案件での採用実績があり、この技術ブログでも様々な記事が書かれています。
しかし、技術選定としての参考情報やtips集はあるものの、どのように実装していけばAPIが動くのかを理解するドキュメントは少なく、いざ実装となると学習コストがかかってしまいます。
そこで、今回はストーリーベースでの実装手順を説明します。
go-swaggerのインストール
go-swaggerは開発環境にインストールして使用します。
下記コマンドでインストールできます。
go get -u github.com/go-swagger/go-swagger/cmd/swagger |
その他にも様々なインストール方法があります。
- brew、apt、wget等のコマンドを経由してインストール
- ソースコード、バイナリファイルのダウンロード
- go installコマンドを経由したインストール
- dockerコンテナとしての実行
Dockerコンテナ以外は概ね開発環境のOSによる入手経路の違い程度の認識で差し支えないと思います。詳しくはInstallingを確認してください。
リリースページからお使いのOSに応じた実行ファイルをダウンロードしてインストールすることも可能です。
アプリケーションをコンテナイメージの上で実行する場合、公式のコンテナイメージをマルチステージビルドに用いる事も可能ですね、夢が広がります。
方法は様々ですが、インストール後にswaggerコマンドが利用可能になります。(コンテナ形式での導入を除く)
swagger.yamlを準備する
OpenAPIの仕様に従ってアプリケーションが生成される以上、まずはAPIの仕様を定義するファイルが無いと始まりません。
まずはswagger.yaml
を作成します。
swagger.yaml
の書き方はOpenAPI Specificationなどに記載があります。
スキーマファースト開発のためのOpenAPI(Swagger)設計規約もあわせてお読みください。swagger.yaml
の書き方についての詳細な説明は今回は省略します。
hello worldのためのサンプルとなるswagger.yaml
はgo-swaggerのリポジトリに用意されています。
tutorials/custom-serverを例に説明します。
|
サンプルの中では特にシンプルな構成です。
paths: |
上記部分に記載の通り、{host-name}/hello
にGETでアクセスする場合のリクエストパラメータ、レスポンスが定義されています。
レスポンスのフォーマットはtext/plain
。
URLのクエリパラメータにname
を持たせることができる。
成功した場合のHTTPレスポンスステータスは200 OK
。
レスポンスのbodyに単一の文字列が返ってくる。
…という事がswagger.yaml
の内容から推測できます。
作成したファイルはOpenAPI Previewで確認することが可能です。Chrome拡張、vscode向けのプラグインなどで利用可能です。editor.swagger.ioのようなウェブサイトとしても公開されています。
vimプラグインもありますね…素晴らしい。
このswagger.yaml
を元に実際にソースコードをビルドしてみましょう。
ソースコードをビルドする
ディレクトリの構成は自由ですが、私のチームでは自動生成されたコードはserver/gen
に配置される構成をとっています。
下記のような構成でserver/genまでディレクトリを作成します。
. |
serverディレクトリに移動し、下記コマンドでソースコードをビルドします。
swagger generate server -a factory -A factory -t gen f ./swagger/swagger.yaml |
オプションの詳細についてはgo-swaggerを用いたWebアプリケーション開発Tips19選のTips2をご覧ください。
今回は--exclude-main
を使用せずにmain.go
も生成してもらいます。コマンドの実行に成功すると、server/gen
配下に各種ファイルが生成されます。
試しにサーバーを立ち上げてみる
main.goを実行することでサーバーが起動します。
server
ディレクトリ上で下記コマンドを実行します。
go run gen/cmd/factory-server/main.go --host 0.0.0.0 --port 3000 |
コマンド実行後にブラウザでlocalhost:3000/hello
にアクセスしてみましょう。
エラーが出ます、hello worldまではあと一歩ですが、まだやることがあります。
ハンドラを実装する
自動生成したコードだけではAPIサーバは完成しません。
なぜならAPIが表示したいデータをどこから用意し、どのような形式でレスポンスに返すかはswagger.yaml
への記載だけではカバーしきれないからです。例えばリクエストを元にデータベースから情報を取得、返却するAPIを構築するとします。
データベース層はRDSでしょうか、NoSQLでしょうか、クラウド上のマネージドDBでしょうか、はたまたオンプレミスでしょうか。取りうる可能性は無限大です。そのためデータベースへのアクセスやレスポンスデータの加工は自前で実装する必要があるわけですね。
今回は下記のようなファイルを用意します。
package server |
※importするパスはご自身のGitHubリポジトリになります。
. |
今回は上記のようなディレクトリ構成で配置しました。
GetGreetingParams
、NewGetGreetingOK()
などが自動生成された関数、及び構造体です。GetGreetingParams
はリクエストパラメータであり、p.Name
でクエリパラメータの内容が取得できます。生成されたコードのお作法に則りハンドラを実装します。今回は受け取ったクエリパラメータをそのままレスポンスとして返してみます。このファイルの変数payload
を任意の文字列にすると実際にレスポンスが変化します。
ファイルの用意ができたら実装したハンドラ関数をアプリケーションが実行するように設定します。実は自動生成したファイルの中には、手動での変更を認めないものと、認めるものが存在します。server\gen\restapi\configure_factory.go
が手動での変更を許可するファイルです。書き換えても良いファイルは先頭行に// This file is safe to edit. Once it exists it will not be overwritten
とコメントされています。
さてこのファイルの下記の部分を見てみましょう。
if api.GetGreetingHandler == nil { |
api.GetGreetingHandlerがnilのままではnot yet been implemented
と出力する設定になっています。
改めて先ほどのエラーを見てみましょう、細かい表示はともかく同じような内容のメッセージが出力されています。
この部分を書き換えるか、ここより先に評価される行で下記のようにapi.GetGreetingHandlerを定義しましょう。
api.GetGreetingHandler = factory.GetGreetingHandlerFunc(server.GetGreeting) |
configure_factory.go
のimport文の更新も必要です。
import ( |
ここまで書けたら今度こそサーバーを起動して動かしてみましょう。
ついにhello world完了
先ほど書いた内容と同じ手順でサーバーを立ち上げます。
go run gen/cmd/factory-server/main.go --host 0.0.0.0 --port 3000 |
ブラウザでlocalhost:3000/hello?name=hello-go-swagger
にアクセスします。
期待したレスポンスが返ってきました。ちなみに記事の通りのget_greeting_handler.go
では、nameが与えられていない場合のエラーハンドリングが実装されていないため、?name=hello-go-swagger
をURLに含めないと500番台のエラーすら返せずに処理に失敗してしまいます。
実際には400番、500番のエラーもswagger.yaml
に定義し、どのような場合にどのエラーを返すかをハンドラに実装していく必要があります。(どの程度不正なリクエストを許容するのかといった柔軟性も、ハンドラで要件に合わせ実装していく形になります。)
今回はhello world編ということでここまでになります、是非皆さんも実際に試してみてください。