50
56

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2015-12-09

はじめに

この記事は リクルートライフスタイル 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/

50
56
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
50
56

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?