OpenAPI Generator で OAuth2 アクセストークン発行のコードまで生成してみる

これは TECHSCORE Advent Calendar 2019 の17日目の記事です。

OpenAPI Generator のコード生成について

OpenAPI GeneratorOpenAPI Specification の定義ファイルがあれば、API クライアントやサーバのスタブのコードを自動生成してくれるという便利な代物です。

ただ、生成されたコードがそのまま使えるとは言えません。例えば、OAuth2 で保護されている API にアクセスする場合、アクセストークンの発行が必要ですが、OpenAPI Generator のクライアントコード生成ではアクセストークン発行のコードは生成してくれません。
Java のクライアントコードを生成した場合、README に以下のようなサンプルコードが出力されますが、 setAccessToken してね、ということくらいしか書かれておらず、アクセストークンの発行の部分には触れられていません。
(Java のクライアントコード生成では、デフォルトで OkHttp 3 を利用したコードが生成されます。OkHttp 3 のクライアントコードの場合、一応アクセストークン発行のコードは生成されますが、Apache Oltu という既にプロジェクト終了したライブラリを使ったコードなので、あまり実案件では使いたくありません)

また、Spring WebFlux をライブラリとしてクライアントコード生成も可能ですが、これに関してはアクセストークン発行はおろか、そのままビルドも通らないという状況です。

今回は、 OpenAPI Generator で Spring WebFlux のクライアントコードを OAuth2 のアクセストークン発行付きで生成するところまでを試してみました。
実行環境は以下の通りです。OpenAPI Generator のバージョンは、現時点の最新安定版の 4.2.2 を使いました。

サンプルコードはこちらにあります。
OpenAPI の定義ファイルは、Synergy! メールAPI をベースにしたものを使っています。

Groovy を使う

OpenAPI Generator が生成するコードを変更したい場合、普通なら Github リポジトリ からソースコードを落としてきて、Java のコードを修正して Maven でビルドして..という感じになると思いますが、 Clone する手間や Maven をインストールしたりちょっと面倒です。

Groovy を使うことで、必要なクラスは @Grab を指定することで実行時に解決でき、Maven は不要になるので、Groovy を使います。私は普段 Mac で開発しているため、Homebrew で Groovy をインストールしました。

手始めとして、JavaClientCodegen を継承したクラスを実行する Groovy スクリプトを作ります。

上記をファイル名 techscore-client-codegen.groovy として保存後、以下のコマンド実行で、output フォルダに Spring WebFlux のクライアントコードが生成されます。

テンプレートのカスタマイズ

上記で生成されるクライアントコードは、前述したとおりそのままではビルドが通らない、アクセストークン発行のコードが生成されないなどといった状態です。

生成されるファイルを修正・追加する

ビルドが通らないのは、生成される build.gradle に Spring 関係の依存関係について一切記載が無いことが原因です。
これを解消するために、OpenAPI Generator はテンプレートからコード生成するため、OpenAPI Generator のテンプレートをカスタマイズする必要があります。

Java のクライアントコードのテンプレートは、こちら から取得できます。
これをコピーして、ファイルを修正・追加することで生成されるコードを変更することができます。
以下のようにして、template ディレクトリ配下にコピーします。

template ディレクトリの中は以下のような構成になっています。拡張子 .mustcache は OpenAPI Generator が利用しているテンプレートエンジン Mustache のテンプレートファイルです。

クライアントコード生成時、--library webclient (Spring WebFluxのコード生成)を指定すると、 libraries/webclient のテンプレートが使われることになります。
今回の場合、 libraries/webclient/build.gradle.mustache を作成すれば、build.gradle を変更できます。
build.gradle.mustache の内容はこちらを参照ください。
以下のように -t オプションを追加してテンプレート指定することでテンプレートの差し替えが可能です。

アクセストークン発行のコードを生成するためには、新しくテンプレートファイルを追加する必要があります。
今回は、Spring WebFlux のクライアントコードのため、WebClient を DI できるように、テンプレートを作成し libraries/webclient/WebClientConfig.mustache に登録しました。
Synergy! メールAPI ではアクセストークン発行時に scope と audience をリクエストボディに含める必要があるため、そのような実装をしています。また、アクセストークンはある程度キャッシュを利用するようにしています。実装内容はリンク先を参照いただければと思います。

また、ApiClient.mustache, api.mustache も、上記 WebClient を DI できるように少しずつ内容を変更しています。こちらも内容はリンク先を参照ください。

ただし、新しいテンプレートを追加しても、それだけではテンプレートを読み取ってくれません。Groovy に以下の Override メソッドを追加して、テンプレートを読み取るようにします。

Spring Boot の設定ファイル application.yml を追加する

先ほど触れませんでしたが、上記の WebClientConfig.mustache を元に生成される WebClientConfig.java は、Spring Boot の定義ファイルである application.yml から OAuth2 関連の設定内容を読み取ることを前提としています。(この辺りや、この辺りです。)

application.yml もテンプレートファイルが存在しないため、先ほど同様テンプレートファイルを作成して、それを読み取るコードを Groovy スクリプトに追記する必要があります。

SecuritySchemes を読み取って置換する

先ほどの application.yml のテンプレートは、アクセストークン発行 URL やスコープ、audience を固定で記載していました。(以下の★マークをつけている部分です。)

どうせなら、OpenAPI の定義ファイルの SecuritySchemes から読み取った内容で置換したいです。

アクセストークン発行 URL やスコープは、デフォルトの状態で OpenAPI 定義ファイルから内容を読み取ってくれます。
application.yml のテンプレートを以下のように変更することで、差し替えが可能です。

audience に関しては、 OpenAPI の標準仕様には含まれていない内容となり、Specification Extensions として定義する必要があるため、デフォルトでは OpenAPI Generator では読み取ってくれません。

OpenAPI Generator での SecuritySchemes の読み取りは、DefaultCodegen#fromSecurity が行なっています。
DefaultCodegen は、 JavaClientCodegen の一番祖先の継承元です。
内容を見ると、SecuritySchemes から読み取った内容を、CodegenSecurity というオブジェクトに詰めていっているように見えます。

fromSecurity からさらに、 DefaultCodegen#setOAuth2Info という private メソッドが呼ばれています。
実装を見ると、OAuth Flow Object の内容を、CodegenSecurity に詰めているようです。

さらに読み進めると、OAuthFlow に getExtensions というメソッドがあり、
CodegenSecurity に、 vendorExtensions というプロパティが用意されていることが分かります。
Specification Extensions の内容を OAuthFlow#getExtensionsから読み取って、 CodegenSecurity の vendorExtensions にセットすれば、テンプレートファイルの置換が可能となるのではと推測できます。

実際に Groovy スクリプトを以下のように変更してみて試してみます。setOAuth2Info は private スコープなので、内容を DefaultCodegen からそのまま持ってきて getExtension するコードを追記しています。
fromSecurity が setOAuth2Info を呼ぶ作りになっているため、fromSecurity も内容は変更せずオーバーライドしています。

次に application.yml のテンプレートファイルを以下のように変更します。

この状態で Groovy を実行すると、SecuritySchemes から内容を読み取った src/main/resources/application.yml を得ることができます。

終わりに

今回は Java + Spring WebFlux の例で OpenAPI Generator のクライアントコード生成のカスタマイズについて説明しました。ClientCodegen を継承したクラスを作り、テンプレートを修正・追記することで、他のサポートされている言語のクライアントコードも自分の好きなように変更することが可能と思います。(OpenAPI Generator のコードは読み解く必要がありますが)
皆さんも是非一度試してみてはいかがでしょうか。

Comments are closed, but you can leave a trackback: Trackback URL.