openapi-generator-cli とは?
openapi-generator-cliは、OpenAPIで書かれた仕様書からコードを生成するものです。
特にGo言語用というわけではなく、WebApplicationFrameworkに従ったコードも生成してくれます。どんな言語、Frameworkに対応しているかは、READMEのOverviewを見てみると良いでしょう。Perlもありますね(ないと思ってた)。
今回、WebApplicationFrameworkにFiberを使ったのですが、残念ながら、Fiberには対応していません。ですが、生成したコードを使うことは出来ます。
openapi-cli-generatorを動かす
今回は、Dockerで動かしました。openapi-generator-cliのオプションとしては、generateから後ろですが、オプションが多いですね。
docker run --rm -u "${UID}:${GID}" -v "${PWD}:/local" \
openapitools/openapi-generator-cli generate -g go \
--skip-validate-spec \
--global-property models,supportingFiles,modelDocs \
--additional-properties withGoMod=false \
--package-name package名 \
-i /local/docs/openapi/openapi.json \
-o /local/internal/interfaces/api/generated/package名/
一つずつ見ていきましょう。
-
generate... コードを生成する。そのままです。以下は generateのオプションです -
-g go... Go用のコードを生成する -
--skip-validate-spec... 仕様書の書式のチェックをスキップ -
--global-property models,supportingFiles,modelDocs... models,supportingFiles,modelDocsを生成する -
--additional-properties withGoMod=false... go.mod を作らない -
--package-name package名... package名を指定する -
-i /local/docs/openapi/openapi.json... 仕様書を指定する -
-o /local/internal/interfaces/api/generated/package名/... 出力先の指定(/localに、current directoryをmountしています)
--global-property を指定しないと、生成したコードをそのまま使えませんでした。今回使用する用途的に必要そうな最低限の組み合わせになります(modelDocsは別に不要ですが)。
生成されたコードを使う
openapi-generator-cliが生成するのは、主に、
-
client.go... APIを叩くためのコード -
configuration.go... エンドポイントのURL等の設定っぽい -
model_*パス_request.go... 各APIのリクエストに関する型や実装 -
model_*パス_response.go... 各APIのレスポンスに関する型や実装
GET
で使え...ません。GETのAPIに関しては、model_*パス*request.goが存在しないので、fiberのQueryParserに渡せません。
--global-property に apis を渡せば、api_*.goにGETようの型は作ってくれるのですが、構造体のメンバがprivateなので、FiberのQueryParserに渡すことができません。残念。
コードを参考にして、構造体を作れば楽なのは楽かもしれません。
POST
model_*パス*request.goの中にJSON用の構造体が入っていますので、それが使えます。例えば、こんな感じですね。
type YourApiRequest struct {
UserID string `json:"user_id"`
}
fiberのBodyParserにそのまま渡すことが出来ます。
c.BodyParser(req)
レスポンス
model_*パス*response.goの中にJSON用の構造体が入っていますので、それが使えます。例えば、こんな感じですね。
type YourApiNameGet200Response struct {
Result []YourApiNameGet200ResponseResultInner `json:"result"`
}
この型通りにデータを作ってやって、JSONにすれば、そのままレスポンスに使えます。
data := YourApiNameGet200ResponseResultInner{
// 略
}
c.JSON(your_pacakge.NewYourApiResponse(data))
各POSTの型にダミーのメソッドを作る
codegen/openapi-request-generator.sh というプログラムで、CanWrapというメソッドを各作ります。やってることは、以下のように超単純です。
#!/bin/bash
dirs=$1
if [ "$dirs" = "" ]; then
dirs="your_pacakge_name"
fi
for dir in $dirs; do
echo -e "package $dir\n" > internal/interfaces/api/generated/$dir/generated_func.go;
grep 'Request struct' -r internal/interfaces/api/generated/$dir | grep type |cut -d ' ' -f 2 | sort | xargs -I {} echo "func (*{}) CanWrap() { }" >> internal/interfaces/api/generated/$dir/generated_func.go
go fmt internal/interfaces/api/generated/$dir/generated_func.go
done
各Postリクエストの型に対して、CanWrapという何もしないメソッドを定義しています。CanWrap()は、RequestWrapper interfaceを満たすためのメソッドです。
type RequestWrapper interface {
CanWrap()
}
これで何が嬉しいかと言うと...前回書いたやつが、できるようになりますね。
以下、略。
終わり
以上、openapi-generator-cli を使えば、楽できますよという話でした。