SwaggerでREST APIドキュメントを生成する
2016/06/24 追記
www.itmedia.co.jp
今のところまだこの脆弱性の対策版がリリースされていないので注意。
だいぶ昔にJersey(JAX-RS参照実装)についての記事を書いてからずっと気になっていたんですが、せっかくアノテーションを使ってURLとメソッドとの間にヒモ付が出来たのに、このアノテーション情報からJavadoc的なAPIドキュメントを生成する方法は無いものかと思っていました。
(追記: いやjerseyでwadlを生成できるけどレスポンスのJSONやXMLの構造については何も情報が出ないので・・・)
JAX-RSでは今のところAPIドキュメント生成についてはカバーして無いようですが、最近仕事でREST APIドキュメントを生成出来ないかという話が出てきたので調べてみるとSwaggerというREST APIドキュメント生成フレームワーク?が有るようなので触ってみました。
Swaggerを使ったREST APIドキュメントはこんな感じです
URLとHttpメソッドの組み合わせで、どのようなパラメータを受け付けるのか、戻ってくるJSONの構造、エラー時のhttpステータスコードといった情報を一覧取得することが可能です。
例: http://petstore.swagger.wordnik.com/#!/pet/getPetById
ちょうどJersey(Jax-RS) + AngularJSの組み合わせでサンプルを作っていたので、こいつをSwaggerによるREST APIドキュメント生成に対応させてみます。
というか、あっけなくREST APIドキュメントが生成されてちょっと感動したので、手順を書いてみます。
JerseyベースのRESTサービスでREST APIドキュメントを生成するためのステップ
以下の環境を前提としています。
(ソースについては後日githubへpush予定)
1. pom.xmlの編集(maven使用時)
dependenciesエレメントに下記のdependencyを追加してください。
<dependency> <groupId>com.wordnik</groupId> <artifactId>swagger-jersey-jaxrs_2.10</artifactId> <version>1.3.0</version> </dependency>
2. web.xmlの編集
まずはjerseyのservletについて。
元々のservlet定義は
<servlet> <servlet-name>Example Web Application</servlet-name> <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class> <init-param> <param-name>com.sun.jersey.config.property.packages</param-name> <param-value>jp.gr.java_conf.ka_ka_xyz.example.service</param-value> </init-param> <init-param> <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name> <param-value>true</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Example Web Application</servlet-name> <url-pattern>/service/*</url-pattern> </servlet-mapping>
ですが、以下のように"com.sun.jersey.config.property.packages"にswaggerのパッケージ名を追加してください。
<servlet> <servlet-name>Example Web Application</servlet-name> <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class> <init-param> <param-name>com.sun.jersey.config.property.packages</param-name> <param-value>jp.gr.java_conf.ka_ka_xyz.example.service;com.wordnik.swagger.jersey.listing</param-value> </init-param> <init-param> <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name> <param-value>true</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Example Web Application</servlet-name> <url-pattern>/service/*</url-pattern> </servlet-mapping>
また、以下のservlet定義を追加してください。
<servlet> <servlet-name>JerseyJaxrsConfig</servlet-name> <servlet-class>com.wordnik.swagger.jersey.config.JerseyJaxrsConfig</servlet-class> <init-param> <param-name>api.version</param-name> <param-value>1.0.0</param-value> </init-param> <init-param> <param-name>swagger.api.basepath</param-name> <param-value>http://localhost:8080/AngularjsWithSwagger/service</param-value> </init-param> <load-on-startup>2</load-on-startup> </servlet>
初期パラメータ"api.version"はREST APIバージョン、 "swagger.api.basepath"はREST APIのURLを指定します。
3. リソースクラスの編集
もともと、クラス自体に@Pathアノテーションが付いていましたが
@Path("/employee") public class EmployeeService { //
このようにjavax.ws.rs.Pathとcom.wordnik.swagger.annotations.Apiアノテーションを追加してください。
@Path("/employee") @Produces(MediaType.APPLICATION_JSON) @Api(value = "/employee", description = "社員に関するサービス") public class EmployeeService { //略
また、もともとこんな感じでメソッドとURL・戻り値のMediaTypeを対応付けていましたが、
@GET @Produces(MediaType.APPLICATION_JSON) @Path("/all") public List<Employee> getEmployees(){ //略
以下のようにcom.wordnik.swagger.annotations.ApiOperation, com.wordnik.swagger.annotations.ApiResponses, com.wordnik.swagger.annotations.ApiResponseアノテーションを使ってREST APIドキュメント用の説明を書いてください。
@GET @Produces(MediaType.APPLICATION_JSON) @Path("/all") @ApiOperation(value = "全ての社員情報を取得", notes = "条件指定せず、すべての社員情報を取得する", response = Employee.class) @ApiResponses(value = { @ApiResponse(code = 500, message = "サーバー内部エラー") }) public List<Employee> getEmployees(){
4. モデルクラスの編集
もともとこんな感じでJax-RBアノテーションを使用してJSONとの対応付けていましたが
@XmlRootElement(name = "employee") @XmlAccessorType(XmlAccessType.FIELD) public class Employee implements Serializable{ /**内部的に使用されるUUID*/ @XmlAttribute private String id; /**一意な社員コード*/ @XmlAttribute private String employeeCode;
以下のように、com.wordnik.swagger.annotations.ApiModel、 com.wordnik.swagger.annotations.ApiModelPropertyアノテーションを使ってREST APIドキュメント用の説明を書いてください。
@XmlRootElement(name = "employee") @XmlAccessorType(XmlAccessType.FIELD) @ApiModel(value = "社員情報") public class Employee implements Serializable{ private static final long serialVersionUID = -7816174850279421158L; /**内部的に使用されるUUID*/ @XmlAttribute @ApiModelProperty(value = "内部的に使用されるUUID", required=true) private String id; /**一意な社員コード*/ @XmlAttribute @ApiModelProperty(value = "社員コード", required=true) private String employeeCode;
5. api-doc JSON生成を確認
さて、mavenでビルドしてwarファイル(AngularjsWithSwagger.war)をデプロイします。
http://localhost:8080/AngularjsWithSwagger/service/api-docs
へアクセスすると、
{"apiVersion":"1.0.0","swaggerVersion":"1.2","apis":[{"path":"/employee","description":"社員に関するサービス"}]}
のようなJSONを取得できるはずです。これはweb.xmlおよびリソースクラスのアノテーションで記述したREST API全体についての情報がJSON形式で出力されているものです。
また、
http://localhost:8080/AngularjsWithSwagger/service/api-docs/employee
へアクセスすると("employee"はリソースクラスのcom.wordnik.swagger.annotations.Apiアノテーションで指定されたパス)、swaggerが生成したREST APIに関する説明を示すJSON文字列が出力されるはずです。
6. swagger-uiでドキュメントを見る
さて、取得したJSONをユーザーフレンドリーな形で表示するには、swagger-uiを使用する必要があります。
とりあえず
からzipをダウンロードし、binフォルダの内容を適当な名前(swagger-ui)に変更し、webappsフォルダへ配置します。
その後
http://localhost:8080/swagger-ui/?url=http://localhost:8080/AngularjsWithSwagger/service/api-docs
へアクセスすると、
と、REST APIドキュメントが表示されます。各メソッドをクリックすると
のように、JSON構造やパラメータ、レスポンスコード情報等が表示されます。
追伸(業務連絡):東宝怪獣的なサーバー名に心当たりのある人は「これ書いたのはアイツか」とか思わずに素知らぬ顔でスルーしてください。