個人的なメモ。
Swagger 2.0 についての説明は本家や適当に調べて下さい。
REST APIを記述せよ!Swagger紹介 #apijp - Groovyラボ
Swagger の紹介されているサイトでは、WebAPI と Swagger UI を同居させるパターンが多くて、public なサービスだと良いのかもですが、開発中だけ Swagger UI 欲しい場合はちょい不便。
というわけで、ビルド時に Swagger JSON を吐く時のメモです。
Swagger は v1 の時は Scala で書かれていて読むのしんどかった*1けど、v2 からは、Java で書き直されていて大分楽でした。
v2 といってるけど、jar 的には 1.5.2-M1 です。
今回は JAX-RS で使うのでそっちメインで追ってます。
.NET での利用(ASP.NET WebAPI や Azure API Apps 等?)方面はまったくノータッチ。
Swagger を使った ASP.NET Web API のドキュメント生成 - miso_soup3 Blog
Build web and mobile apps faster | ブチザッキ
パッケージは省略しています。~ は com.wordnik.swagger に置き換えて下さい。
Swagger generator
swagger-models.jar
~.models.Swagger
Swagger の構造持ってるやつ。add~ で色々追加していける。
Swagger ファイル(json/yaml) の出力
swagger-core.jar
~.util.Json/Yaml
Swagger インスタンスを食わすと出力
Json.mapper().writeValue(new File("api-docs.json"), swagger);
JAX-RS のリソースクラスを parse
swagger-jaxrs.jar
~.jaxrs.Reader
リソースクラスを食わすと、前述の Swagger インスタンスが返ってくる。
紐付く戻り値等のModel定義も全部返ってくるので、リソースクラスを食わすだけでOK
JAX-RS のリソースクラス/メソッド/戻り値等に情報を付与
swagger-annotations.jar
~.annotations パッケージ全般
アノテーション は RententionPolicy.RUNTIME になってるけど、war に Swagger の jar を含めなくても大丈夫そう。
RUNTIME になってるアノテーションでも classpath にいなくても平気らしい。*2
Java8 Date and Time API 対応
swagger-core.jar
~.jackson.TypeNameResolver
protected final static な Map インスタンスをいじる必要があるので拡張し難い
結局ここではやらなかった。
Java8 Optional 対応
swagger-core.jar
~.jackson.ModelResolver
private なメソッド boolean _isOptionalType でやってるので拡張し難そう。
Optional は使ってないしスルー。
無視するクラス指定
swagger-core.jar
~.converter.ModelConverters#add Class/Package ToSkip
List/Array のモデルを指定する
swagger-models.jar
~.models.ArrayModel
~.annotations.ApiOperation なら responseContainer も指定出来て List 等のコレクション表現が出来るが、 ~.annotations.ApiResponse では response のクラスしか指定出来ない。
なので、ApiResponse での定義を後で差し替えるために使った。
swagger.addDefinition("_ErrorCollection", new ArrayModel().items(new RefProperty().asDefault("ErrorDto")));
メソッドのパラメーター関係
swagger-models.jar
~.models.parameters パッケージ
よく使うのは SerializableParameter を実装した Cookie/Form/Header/Path/Query
type/format は SerializableParameter で OK だが、defaultValue は各具象クラスに定義。
JAX-RS メソッドパラメーターの解析
swagger-jaxrs.jar
~.jaxrs.ext.SwaggerExtension
~.jaxrs.DefaultParameterExtension
~.jaxrs.ext.SwaggerExtensions
既存の DefaultParameterExtension では、@BeanParam に対応していない。
@DefaultValue は TODO not supported yet
今の作りだと大変そうな気もする。
自前の SwaggerExtension を実装し、DefaultParameterExtension と入れ替えると色々捗る。
SwaggerExtensions.getExtensions().clear();
SwaggerExtensions.getExtensions().add(new SwaggerBeanParamExtensions());
大元の呼び出し側は、先頭の Extension しか呼び出さない。
多分設計思想は各 Extension 内で 次の Extension があれば続けて呼ぶような感じのはずだが、
DefaultParameterExtension の実装が chain してくれないので、自前の Extension を先に処理させる必要がある。
Swagger UI でのメソッドパラメーターの表示
swagger-client.js
Operation のとこ
getModelSignature の値が表示されてそう。
この値を決めるのが、SerializableParameter の type/format の値。
その他諸々
個人的に使ってるのは、ドキュメント用の自前アノテーション追加 & SwaggerExtension 差し替え から Reader で JAX-RS リソースクラス群を読まして出来た Swagger にちょいちょい細工してから JSON で吐くのを Gradle でやってます。
Reader で読んだ Swagger を加工は良く使いそうな気がします。
例:Servlet Filter で処理するような Cookie や Headder の値があるが、当然リソースメソッドにはパラメーターとして定義していないケース。
Swagger UI 上にパラメーターとして表示しないとAPIの呼び出しが出来ないので Swagger UI の魅力半減!
って時に、Reader で読んだ Swagger に対してこんな感じで追加してあげる。
コード例は groovy
swagger.paths.each { k, v -> v.operations.each { it.addParameter(additionalHeaderParam) } }
自前で拡張していくと本家のバージョン上げた時大変そうですが、使い捨てるならバージョン上げることも無さげなのでそんな気にする必要も無いかと。
サンプルはこちら sample/jaxrs_swagger_output_json at master · OdaShinsuke/sample · GitHub
Swagger 自体の欠点は情報を付与しようとしたら、アノテーション書く量が増えること。
しょうがないっちゃーしょうがないけど、JavaDoc から何とかならないかな?
あとは、Arquillian で書いたテストとテスト結果から情報補完してくれたら楽しそう!