1. HOME
  2. ブログ
  3. IT技術
  4. 【Swagger】SwaggerCodegen のコード生成をカスタマイズする
【Swagger】SwaggerCodegen のコード生成をカスタマイズする

【Swagger】SwaggerCodegen のコード生成をカスタマイズする

はじめに

今回は SwaggerCodegen を使ったdartのコード生成を色々カスタマイズしていきます。

dart言語を扱っていますが、ほとんど dart の知識は必要のない記事になっていますので、他の言語の場合でも参考になるかと思います!

SwaggerCodegen のバージョンはv3を使用します。

Swaggerについて

Swagger は RESTful API を設計するためのオープンソースの開発者ツールです。

SwaggerCodegen では Swagger で書かれた API 定義書から、API クライアントやモデルクラスなどのコード生成を行うことができます。

https://swagger.io/tools/swagger-codegen/

デフォルト設定で API クライアントを生成する

最初はデフォルト設定で SwaggerCodegen でコード生成していきましょう。

まずは Homebrew を使って SwaggerCodegen のインストールを行います。

そして、以下のコマンドでコードを生成することができます。

-i で指定している Swagger の API 定義書は、Swagger公式が提供している以下のサンプルを使用しています。

https://editor.swagger.io/

上記コマンドによってgenerated-swagger-filesフォルダと、その中に以下のファイルが出力されました。

出力されたファイル

ちなみに出力されたファイルがある状態で再度コマンドを実行した場合、上書きはされるんですが不要なファイルが残る可能性があるので、以下のようにフォルダを削除するコマンドを含め sh ファイルにしておくと後々楽になりますね。

実行する時は sh swagger-generate.sh を入力しましょう。

上記で生成されたファイルの利用方法は README.md に書いてあり、生成されたフォルダで個別にリポジトリを作成し、利用するプロジェクトの pubspec に以下を記入することで利用できます。

そして以下のように自身のプロジェクト上で API を呼び出すことができるようになりました。

今回はこの出力されたファイル構造や、ファイルの中身をいろいろいじっていきましょう!

ファイルの内容を書き換える

カスタマイズするためには色々と準備が必要になるので、まずはこちらを対応していきましょう

ファイルの内容を書き換えるための準備

SwaggerCodegen で出力されるファイルの中身がどのような記述になっているかは、mustache というファイル形式で定義されています。

mustache というのは、色々な言語ファイルの出力をテンプレートとして記述できるものです。

https://mustache.github.io/

まずはデフォルト設定で指定されている dart の mustache ファイルを見てみましょう。

https://github.com/swagger-api/swagger-codegen-generators/tree/master/src/main/resources/handlebars/dart

api_client や model などがあり、どういった種類のファイルのテンプレートなのかがわかりますね。

この dart フォルダごと、swagger-generate.sh と同じフォルダに移動させ、sh ファイルにテンプレートフォルダの指定を追加しましょう。

わかりやすくするため、dart フォルダは template という名前に変更してあります。

これでデフォルトの生成から、独自のテンプレートを参照しての生成になりました。

ちなみに SwaggerCodegen の dart のコード生成では null safety 対応がされていないのですが、これを対応するだけであれば、openapi-generatorのdart-dio-next を利用したほうが楽です。

https://github.com/OpenAPITools/openapi-generator

ただプラグインを色々使っている関係上カスタマイズしづらいので、カスタマイズ目的なら SwaggerCodegen のほうが楽そうですね。

これで書き換える準備は完了しましたが、その前に mustache ファイルの中身について理解していきましょう。

model.mustache ファイルについて

まずは model クラスの mustache からです。

コードは以下のようになっています。

{{#models}}{{/models}} で、Swagger の yaml ファイルから読み込んだ model データごとに1つの dart ファイルが生成され、 {{#model}}{{/model}} の中でそれぞれの model データを取得しています。

HTML のタグみたいな感じですね。

そして取り出した model から、 {{#isEnum}}{{/isEnum}} で model データが Enum形式だった場合、 {{^isEnum}}{{/isEnum}} で Enum 以外だった場合の判定を行なっています。

{{>enum}}{{>class}} では、それぞれ enum.mustache ファイルと class.mustache ファイルの中身を、そのままこちらにコピーするような形になります。

なので dart の model.mustache では、単純に Enum かそうでないかを判定して、Swagger の yaml ファイルにある model データごとに dart ファイルを生成しているだけですね。

class.mustacheファイルについて

model.mustache から参照しているファイルで、以下のようになっています。

これを使った出力前と出力後を見てみましょう。

以下が Swagger の yaml にある User のレスポンス仕様です。

Swagger の yaml にある User のレスポンス仕様

以下が出力されたファイルになります。

いくつか被ってる部分があるので、fromJson 以降は省略しています。

上から順番に見ていきましょう。

{{classname}} ではその名の通りクラス名が出力されていますね。

変数宣言ではコメント出力部分がいくつかありますが、肝心なところは {{#vars}} {{{datatype}}} {{name}} = {{{defaultValue}}}; {{/vars}} で出力されています。

また json からモデルデータに変換するということで、json から取得する各変数のキーについても、 {{#vars}}{{baseName}}{{/vars}} で出力しています。

このような感じで、 {{}} があって少しとっつき難いところはありますが、出力前と出力後と mustache ファイルを見ればなんとなくわかるようになってます。

ファイルの内容を書き換える

基本的には mustache にあるコードを変更するだけで、好きなように書き換えることが可能です。

例えば hoge() という関数をそれぞれの class で持ちたい場合、以下のようにするだけで生成される class ファイル全てに hoge() が実装されます。

ファイルごとに何か変更するだけであれば、これだけで解決するのですが、例えば Utility 的なファイルが一つ欲しいとか、ファイル構成自体を変えたい場合などはもう少し踏み込んだ作業が必要になります。

次はそちらを試していきましょう。

ファイル構成を変更する

ファイル構成を変更する場合は、SwaggerCodegen のジェネレータを変更する必要があります。

手順に関してはこちらに記載されていますので、まずはジェネレータを変更するための環境構築をしていきましょう。

ファイル構成を変更するための環境構築

今回は Docker を使って開発していきます。

記載されているコマンドを打つだけでできるのですが、その前に色々必要になるものをインストールしておきましょう。

まずは Homebrew を使って Maven と wget をインストールしておきます。

あとは Docker をインストールしておきましょう。

公式サイトでインストールした後、起動して Docker コマンドが打てる状態にまでしておきます。

これでコマンドを打ってもエラーにならなくなったはずなので、SwaggerCodegen にある手順を進めていきましょう!

まずは SwaggerCodegen を git から落とします。

この記事を書いた時点では、v2が master になっているので、Tag などからv3に変更しておいてください。

その後に落としてきた SwaggerCodegen へ cd コマンドで移動して、以下のコマンドを実行しましょう。

あとはこちらにあるコマンドをコピペ(#コメントは除く)して入れていきます。

以下のコマンドが最初にありますが、 generator-stub-docker.sh の実行で、generate コマンドの -l で指定するものが決まったりするので、それだけ除いてコピペするのをおすすめします。

続けて generator-stub-docker.sh を実行しましょう。

2箇所ある custom の部分は好きなように変更してください。

これで tmp/codegen/mygenerator 下に色々とファイルが作成されました。

mygenerator

tmp フォルダは隠しフォルダになってるので、Finder で見たい場合は command + shift + .で隠しフォルダを表示するようにしておきましょう。

src フォルダの中にはジェネレータである CustomGenerator.java と、mustache で作られたテンプレートファイルが作成されています。

mygenerator srcフォルダ内のデータ

META-INF フォルダの中にある CodegenConfig ファイルにはジェネレータ名が記載されています。

ジェネレータのクラス名・ファイル名と連動しているので、そちらを変更した場合はこちらも変更するようにしておきましょう。

src の中身が作成されたことで、続けて以下のコマンドを入力して petstore-simple.yaml からコードを生成することができます。

2回目以降は最後の行にあるコマンドだけで大丈夫です。

このコマンドを実行することで、mygenerator 下にある generated フォルダに色々と生成されます。

mygenerator 下にある generated フォルダに色々と生成される

ここまでの手順は、 swagger-codegen generate の時と若干異なっていますが、最終的なコマンドはだいたい同じですね。

ちなみに generate した辺りから、mygenerator フォルダの直下にtagertフォルダが生成されています。

この中身には mustache ファイルなどが入っており、2回目以降はおそらくここを参考に generate しているっぽいので、変更したのに反映されていない場合は target フォルダごと削除することで解決するかと思います。

これで環境構築はできたので、ジェネレータのコードを見つつ編集していきましょう!

CustomGenerator.java について

そこそこ長いコードになっているので、重要なコード以外は省いてます。

上から順に見ていきましょう。

getName メソッドで -l dart のような指定する名前を決めることができます。

CustomGenerator() コンストラクタでは、主にどの mustache ファイルを読み込むかなどを定義していますね。

modelTemplateFilesapiTemplateFiles では複数ある Model や API ごとにファイルを生成したい場合に利用します。

これは複数 put することで複数種類のファイルを Model と API ごとに生成することが可能です。

modelPackageapiPackage では生成先のフォルダを指定することができます。

現状の生成先にフォルダがない場合は勝手にフォルダが作られるので、ファイル構成を変更したい場合はこちらを変更してあげましょう。

templateDir は mustacheファイルを読み込む場所を決めています。

上記コードからは省いていますが、 templateDir は CustomGeneratorの getTemplateDir メソッドに利用されている変数です。

Docker で生成する場合、 templateDir は必須の項目になるのでコピペ時に消えてしまわないように注意しておきましょう!

supportingFiles でも出力先の引数があるので、こちらで自由に変更することができます。

ここで省略した部分だったり、自分が生成したい言語の場合はどうしたらいいの?という疑問があると思いますが、

そういった場合は以下の URL から確認してみてください。

既に定義されている言語がある場合は、それをコピペしてから編集していくのが一番楽ですね。

https://github.com/swagger-api/swagger-codegen-generators/tree/master/src/main/java/io/swagger/codegen/v3/generators

親クラスである DefaultCodegenConfig も同じ階層にあるので、そちらも確認してみてください。

これである程度はファイル構成を変更できるようになったと思います。

TIPS

ここからは、私自身がジェネレータを編集していく中で、詰まった部分と解決方法をいくつか紹介します。

mustache に出力する文字列をキャメルケースにしたい

additionalProperties.put でキャメルケースにした文字列を mustache に送ること自体は簡単なのですが、既にある{{}}タグの出力をキャメルケースにする方法です。

まずはジェネレータで以下のようにコードを追加しましょう。

import では以下の場所から CamelCaseLambda を取得しています。

https://github.com/swagger-api/swagger-codegen-generators/tree/master/src/main/java/io/swagger/codegen/v3/generators/handlebars/lambda

他のケースもあるのでそれらも同様に取得して使用することができると思います。

上記のコードが入ったジェネレータを実装後、mustacheファイルで以下のようにすることで、部分的にキャメルケースを適用できます。

複数種類のAPI/Modelファイルを生成したい

APIの場合、apiTemplateFilesに複数putすることで複数種類のAPIファイルが生成されますが、デフォルト設定だとAPI名がそのままファイル名になるため、どちらかが上書きされてしまいます。

それを回避するためにはジェネレータにて以下のように、mustacheファイルごとにファイル名を書き換えましょう。

apiFilenameメソッドでは、その名の通りapiTemplateFilesより生成されるAPIファイルの名前を決めるものです。

templateNameから、どのmustacheをテンプレートとしてファイルを生成するかがわかるので、それによって返却値を変えているだけです。

また返却値にはフォルダの情報も含まれているので、種類ごとに別フォルダに出力したい場合にもこちらで対応できますね。

まとめ

今回はSwaggerCodegenによるコード生成をカスタマイズする方法を紹介しました。

この方法ではSwaggerCodegenで定義されている言語以外のものでも生成できるので、興味があれば是非活用してみてください!

関連記事

採用情報

\ あの有名サービスに参画!? /

バックエンドエンジニア

\ クリエイティブの最前線 /

フロントエンドエンジニア

\ 世界を変える…! /

Androidエンジニア

\ みんなが使うアプリを創る /

iOSエンジニア