OpenAPI Specification(以降OASとします)はREST APIの仕様を定義する仕組みです。
YAML等のフォーマットで仕様を記述し、ドキュメントや各種言語向けのコードを生成して使います。おかしな仕様にはエラーを出してくれるし、入力値の取得やバリデーションなど自動生成すべきコードをいい感じに用意してくれるので、とても便利です。わかりやすく言うとREST APIのための形式仕様記述(formal specification)1です。
OASで定義したAPI仕様からGoのコードを生成することを考えます。
OpenAPI GeneratorのGo対応は微妙な感じです。ググるとgo-swaggerがよく使われているようですが、OAS 3.0の前身であるSwagger 2.0にしか対応していません。OAS 3.0に対応したものはoapi-codegenがあります。READMEやFuture Tech Blogの記事(本記事がいらないくらい詳しい)がよさげだったので使ってみたところ、普通に使えたので備忘録がてらまとめておきます。
前提
- oapi-codegen v1.5.0 (Feb 09, 2021)
- chiルータを利用
- oapi-codegen自体はEcho, Chi, net/httpに対応している
- サーバコードの生成だけ
- 今回はクライアントをGoで実装しなかったので
- APIキーで認証
※ 以下、一部でGitHubからコードを引用しています。ライセンス等は引用元を参照してください!
コード生成と実装
コード生成
公式のexamplesがめっちゃわかりやすいです。↓に引用します。
このようにgo generateでやるか手動で実行するかですね。
基本形は↓です。
|
|
これを実行するとServerInterface
を含めたコードを生成します。あとはこのインタフェースを満たす実装(後述)をするだけです。生成されるコードが薄くて普通に読めるのが良いですね。
よく使うはずのオプションを入れると↓こうなります。
|
|
-generate
: 何を生成するかtypes
chi-server
spec
あたりですかね?client
はサーバコードの場合不要- Echoなら
chi-server
の代わりにserver
spec
はOASのdump、Validatorに必要
-include-tags
: OASのタグを見て、指定したタグだけ生成するFuga
は別で実装したいんだよね〜ってときにHoge
のコードだけ生成できます- ただし、別々で生成した
Hoge
とFuga
を同じchiルータで動かすのは大変そうです(後述)。
実装
↓の公式の例のように、ServerInterface
を満たす実装をするだけです。
Goのtipsとして、パッケージ変数にvar _ ServerInterface = (*PetStore)(nil)
を定義しておくと何が足りないのかがわかって便利です。
呼び出し側も公式の例がわかりやすいのですが、1)OpenAPIを読み込んで、
2)OapiRequestValidator
に食わせてValidatorのMiddlewareを生成します。
なので、-include-tags
でHoge
とFuga
を別々に生成した場合、同じchiルータで動かすのが難しいです。
細かい話なのでクリックで展開
OapiRequestValidator
がswagger
ごと(Hoge
とFuga
で異なる)なので、HogeValidator->FugaValidator->リクエストハンドラという流れになり、Fuga
宛のリクエストはHogeValidatorに弾かれます。
ルーティングをがんばって設定すればできるんですかね🤔
CORSとPreflight
Middlewareを使いました。試しにYAMLにOPTIONSメソッドを書いてみたところ、なにも生成されませんでした。
これってAmazon API GatewayやCloud Endpointsではどうするんだろう?PreflightでOPTIONSが飛んでくるのはAPIの仕様ではなくブラウザの仕様だし?詳しい人教えてください。
注意点は、CORSのMiddlewareをOapiRequestValidator
の前に入れる必要があることです(OapiRequestValidator
でOPTIONSが弾かれるため)。
|
|
Heartbeat
K8sにデプロイする場合などで必要になると思います。これもAPIの仕様じゃないと思うので、Middlewareを使いました。
|
|
middleware.Heartbeat
を使う代わりに自前で実装してもいいでしょう。
|
|
認証
↓こんな感じでOptions.AuthenticationFunc
をセットすればとりあえず動きます。
|
|
どうやらOASでメソッドにsecurity
が定義されていたらOptions.AuthenticationFunc
を見に行くようなので、適切なAuthenticationFunc
をセットしておく、でよさそうです。詳細は↓
クリックで展開
↓のcase *openapi3filter.SecurityRequirementsError
の元をたどっていくと、
↓でOptions.AuthenticationFunc
を取り出していて、そのあと実行しています。
おわりに
oapi-codegen、生成されるコードが簡潔だし使い方も簡単なのでオヌヌメです。今回作ったものはそのうち書けたら書きます。
厳密な定義はよくわからないですが、仕様が破綻していたらエラーを出してくれるので形式仕様記述ですよね?🤔 ↩︎