SwaggerでREST APIドキュメントを生成する


2016/06/24 追記
www.itmedia.co.jp

今のところまだこの脆弱性の対策版がリリースされていないので注意。


だいぶ昔にJersey(JAX-RS参照実装)についての記事を書いてからずっと気になっていたんですが、せっかくアノテーションを使ってURLとメソッドとの間にヒモ付が出来たのに、このアノテーション情報からJavadoc的なAPIドキュメントを生成する方法は無いものかと思っていました。
追記: いやjerseyでwadlを生成できるけどレスポンスのJSONXMLの構造については何も情報が出ないので・・・)

JAX-RSでは今のところAPIドキュメント生成についてはカバーして無いようですが、最近仕事でREST APIドキュメントを生成出来ないかという話が出てきたので調べてみるとSwaggerというREST APIドキュメント生成フレームワーク?が有るようなので触ってみました。

Swaggerを使ったREST APIドキュメントはこんな感じです

Swagger-UI デモサイト


URLとHttpメソッドの組み合わせで、どのようなパラメータを受け付けるのか、戻ってくるJSONの構造、エラー時のhttpステータスコードといった情報を一覧取得することが可能です。

例: http://petstore.swagger.wordnik.com/#!/pet/getPetById



ちょうどJersey(Jax-RS) + AngularJSの組み合わせでサンプルを作っていたので、こいつをSwaggerによるREST APIドキュメント生成に対応させてみます。
というか、あっけなくREST APIドキュメントが生成されてちょっと感動したので、手順を書いてみます。

JerseyベースのRESTサービスでREST APIドキュメントを生成するためのステップ

以下の環境を前提としています。

  • Java8
  • Tomcat8
  • maven2以降
  • Jerseyを使用した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を使用する必要があります。

とりあえず

GitHub - swagger-api/swagger-ui: Swagger UI is a dependency-free collection of HTML, Javascript, and CSS assets that dynamically generate beautiful documentation from a Swagger-compliant API.

からzipをダウンロードし、binフォルダの内容を適当な名前(swagger-ui)に変更し、webappsフォルダへ配置します。

その後

http://localhost:8080/swagger-ui/?url=http://localhost:8080/AngularjsWithSwagger/service/api-docs

へアクセスすると、

f:id:ka-ka_xyz:20141030003117p:plain

と、REST APIドキュメントが表示されます。各メソッドをクリックすると

f:id:ka-ka_xyz:20141030003145p:plain

のように、JSON構造やパラメータ、レスポンスコード情報等が表示されます。



追伸(業務連絡)東宝怪獣的なサーバー名に心当たりのある人は「これ書いたのはアイツか」とか思わずに素知らぬ顔でスルーしてください。