Help us understand the problem. What is going on with this article?

Spring REST Docsでドキュメント作成

More than 3 years have passed since last update.

はじめに

この記事は リクルートライフスタイル Advent Calendar 2015
リクルートライフスタイル Advent Calendar 2015 - Qiita の9日目です。
ホットペッパービューティーで開発を担当している満澤です。

現在、Java 8 + Spring Boot 1.3.0 + MyBatis 3.2.8でRestfulな新規APIを開発しています。

Spring Bootは、小・中規模な新規サービスを高いスピード感で、
開発していくのに適しているんじゃないかと感じています。
現実、まわりでもそういった案件がどんどん増えてます。

その際、当然、新たにドキュメントの整備をしていかなければならないのですが、
ここで、最近新しい技術をSpringが提供し始めました。
その名もSpring REST Docs。

何ができるかというと、
Spring MVC Test を実行した結果をスニペット(Asciidoc)として出力できます。
自分で手書きしたドキュメント(Asciidoc)とスニペットを組み合わせられます。

さっそく、どんなドキュメントが出力されるか試してみます。

環境

  • Java 1.8.0_45
  • Maven 3.2.1
  • Spring Boot 1.3.0
  • Spring REST Docs 1.0.0

サンプル

Spring BootのREST APIにREST Docsでドキュメント生成するサンプルです。
※Spring Bootの実装については色んなところで記事がでているので割愛

pom.xml
    <!-- REST Docsに関する記載を抜粋 -->

    <properties>
        <snippetsDirectory>${project.build.directory}/generated-snippets</snippetsDirectory>
    </properties>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <configuration>
            <includes>
                <include>**/*Documentation.java</include>
            </includes>
        </configuration>
    </plugin>
    <plugin>
        <groupId>org.asciidoctor</groupId>
        <artifactId>asciidoctor-maven-plugin</artifactId>
        <version>1.5.2</version>
        <executions>
            <execution>
                <id>generate-docs</id>
                <phase>package</phase>
                <goals>
                    <goal>process-asciidoc</goal>
                </goals>
                <configuration>
                    <backend>html</backend>
                    <doctype>book</doctype>
                    <attributes>
                        <snippets>${snippetsDirectory}</snippets>
                    </attributes>
                </configuration>
            </execution>
        </executions>
    </plugin>
    <plugin>
        <artifactId>maven-resources-plugin</artifactId>
        <version>2.7</version>
        <executions>
            <execution>
                <id>copy-resources</id>
                <phase>prepare-package</phase>
                <goals>
                    <goal>copy-resources</goal>
                </goals>
                <configuration>
                    <outputDirectory>
                        ${project.build.outputDirectory}/static/docs
                    </outputDirectory>
                    <resources>
                        <resource>
                            <directory>
                                ${project.build.directory}/generated-docs
                            </directory>
                        </resource>
                    </resources>
                </configuration>
            </execution>
        </executions>
    </plugin>

    <dependency>
        <groupId>org.springframework.restdocs</groupId>
        <artifactId>spring-restdocs-mockmvc</artifactId>
        <version>1.0.0.RELEASE</version>
        <scope>test</scope>
    </dependency>
RestDocsExampleTest.java
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.http.MediaType;
import org.springframework.restdocs.RestDocumentation;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
import static org.springframework.restdocs.request.RequestDocumentation.pathParameters;
import static org.springframework.restdocs.request.RequestDocumentation.requestParameters;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = ApplicationContext.class)
@WebAppConfiguration
public class RestDocsExampleTest {

    @Rule
    public final RestDocumentation restDocumentation = new RestDocumentation("target/generated-snippets");

    @Autowired
    private WebApplicationContext context;

    private MockMvc mockMvc;

    @Before
    public void setUp() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
                .apply(documentationConfiguration(this.restDocumentation)).build();
    }

    @Test
    public void testRequestMapping() throws Exception {
        this.mockMvc.perform(get("/api/v1/employee/{year}?employeId=E000000001", "2015")
                .accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andDo(document("controller-doc",
                        pathParameters(
                                parameterWithName("year").description("入社年:必須、yyyy形式")),
                        requestParameters(
                                parameterWithName("employeId").description("従業員ID:任意、半角英数字10桁"))
                ));
    }

ポイントはMockMvc.andDo(document("controller-doc", ・・・)でドキュメントが出力されるところ、
pathParameters()、requestParameters()でドキュメントに出力する内容が記載できます。
上記の例ではコントローラクラスをテスト対象にして、
URLパラメータについて、ドキュメントに出力するようにしていますが、
これ以外にも、レスポンスやヘッダの中身など様々な記載が可能です。

出力されたドキュメント
doc.jpg

まとめ

簡単です、とてもシンプル。
ドキュメントの質も、一定のラインは満たせているでしょうし、(Asciidocなので、リッチにカスタマイズも可能)
何より、ドキュメント作成のコストをテストコードにかけれるという仕組みがとても好印象をもちました。
ドキュメントが置いてけぼりというのはよく聞く話ですが、
テストが成功した時にドキュメントが生成されるので、最新の状態を保ちやすい、
CIと組み合わせて色んなことできるでしょうし、Jarなどに含めて一緒に配布することも容易です。
実際のプロダクトに適用させるには、詰めるところはありそうですが、
Springで開発しているのであれば、導入を検討してもいいのではないでしょうか。

参考
http://docs.spring.io/spring-restdocs/docs/1.0.0.RELEASE/reference/html5/

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away