Spring MVC テストまたは WebTestClient で生成された自動生成スニペットと手書きのドキュメントを組み合わせて、RESTful サービスをドキュメント化します。

導入

Spring REST Docs の目的は、RESTful サービスに関する正確で読みやすいドキュメントを作成できるようにすることです。

高品質のドキュメントを書くことは困難です。その難しさを軽減する 1 つの方法は、ジョブに適したツールを使用することです。このため、Spring REST Docs はデフォルトで Asciidoctor (英語) を使用します。Asciidoctor は、プレーンテキストを処理し、ニーズに合わせてスタイルとレイアウトが設定された HTML を生成します。必要に応じて、Markdown を使用するように Spring REST Docs を構成することもできます。

Spring REST Docs は、Spring MVC のテストフレームワークSpring WebFluxWebTestClient または安心 5 (英語) で書かれたテストによって生成されたスニペットを使用します。このテスト主導のアプローチは、サービスのドキュメントの正確性を保証できます。スニペットが正しくない場合、それを生成するテストは失敗します。

RESTful サービスをドキュメント化することは、主にそのリソースを説明することです。各リソースの説明の 2 つの重要な部分は、それが消費する HTTP リクエストの詳細と、それが生成する HTTP レスポンスです。Spring REST Docs を使用すると、これらのリソースと HTTP リクエストおよびレスポンスを操作して、サービスの実装の詳細からドキュメントを保護できます。この分離は、サービスの実装ではなく、サービスの API をドキュメント化できます。また、ドキュメントを作り直すことなく実装を進化させることができます。

入門

このセクションでは、Spring REST Docs の使用を開始する方法について説明します。

要件

Spring REST Docs には、次の最小要件があります。

さらに、spring-restdocs-restassured モジュールには REST Assured 5.2 が必要です。

ビルド構成

Spring REST Docs を使用するための最初のステップは、プロジェクトのビルドを構成することです。Spring HATEOAS [GitHub] (英語) および Spring Data REST [GitHub] (英語) サンプルには、それぞれ build.gradle および pom.xml が含まれており、参照として使用できます。構成の主要部分は、次のリストで説明されています。

Maven
<dependency> (1)
	<groupId>org.springframework.restdocs</groupId>
	<artifactId>spring-restdocs-mockmvc</artifactId>
	<version>{project-version}</version>
	<scope>test</scope>
</dependency>

<build>
	<plugins>
		<plugin> (2)
			<groupId>org.asciidoctor</groupId>
			<artifactId>asciidoctor-maven-plugin</artifactId>
			<version>2.2.1</version>
			<executions>
				<execution>
					<id>generate-docs</id>
					<phase>prepare-package</phase> (3)
					<goals>
						<goal>process-asciidoc</goal>
					</goals>
					<configuration>
						<backend>html</backend>
						<doctype>book</doctype>
					</configuration>
				</execution>
			</executions>
			<dependencies>
				<dependency> (4)
					<groupId>org.springframework.restdocs</groupId>
					<artifactId>spring-restdocs-asciidoctor</artifactId>
					<version>{project-version}</version>
				</dependency>
			</dependencies>
		</plugin>
	</plugins>
</build>
1test スコープに spring-restdocs-mockmvc への依存関係を追加します。MockMvc ではなく WebTestClient または REST Assured を使用する場合は、代わりにそれぞれ spring-restdocs-webtestclient または spring-restdocs-restassured への依存関係を追加してください。
2Asciidoctor プラグインを追加します。
3prepare-package を使用すると、ドキュメントをパッケージに含めることができます。
4Asciidoctor プラグインの依存関係として spring-restdocs-asciidoctor を追加します。これにより、.adoc ファイルで使用する snippets 属性が target/generated-snippets を指すように自動的に構成されます。また、operation ブロックマクロを使用できるようになります。
Gradle
plugins { (1)
	id "org.asciidoctor.jvm.convert" version "3.3.2"
}

configurations {
	asciidoctorExt (2)
}

dependencies {
	asciidoctorExt 'org.springframework.restdocs:spring-restdocs-asciidoctor:{project-version}' (3)
	testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc:{project-version}' (4)
}

ext { (5)
	snippetsDir = file('build/generated-snippets')
}

test { (6)
	outputs.dir snippetsDir
}

asciidoctor { (7)
	inputs.dir snippetsDir (8)
	configurations 'asciidoctorExt' (9)
	dependsOn test (10)
}
1Asciidoctor プラグインを適用します。
2Asciidoctor を継承する依存関係の asciidoctorExt 構成を宣言します。
3asciidoctorExt 構成で spring-restdocs-asciidoctor への依存関係を追加します。これにより、.adoc ファイルで使用する snippets 属性が build/generated-snippets を指すように自動的に構成されます。また、operation ブロックマクロを使用できるようになります。
4testImplementation 構成で spring-restdocs-mockmvc への依存関係を追加します。MockMvc ではなく WebTestClient または REST Assured を使用する場合は、代わりにそれぞれ spring-restdocs-webtestclient または spring-restdocs-restassured への依存関係を追加してください。
5 生成されたスニペットの出力場所を定義する snippetsDir プロパティを構成します。
6test タスクを実行すると出力が snippetsDir に書き込まれることを Gradle に認識させます。これは増分ビルド (英語) に必要です。
7asciidoctor タスクを構成します。
8 タスクを実行すると、snippetsDir から入力が読み取られることを Gradle に認識させます。これは増分ビルド (英語) に必要です。
9 拡張機能の asciidoctorExt 構成の使用を構成します。
10 ドキュメントが作成される前にテストが実行されるように、タスクを test タスクに依存させます。

ドキュメントのパッケージ化

生成されたドキュメントをプロジェクトの jar ファイルにパッケージ化することができます。たとえば、Spring Boot によって静的コンテンツとして提供されるようにすることができます。これを行うには、プロジェクトのビルドを次のように構成します。

  1. ドキュメントは jar が構築される前に生成されます

  2. 生成されたドキュメントは jar に含まれています

次のリストは、Maven と Gradle の両方で行う方法を示しています。

Maven
<plugin> (1)
	<groupId>org.asciidoctor</groupId>
	<artifactId>asciidoctor-maven-plugin</artifactId>
	<!-- … -->
</plugin>
<plugin> (2)
	<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> (3)
				<outputDirectory>
					${project.build.outputDirectory}/static/docs
				</outputDirectory>
				<resources>
					<resource>
						<directory>
							${project.build.directory}/generated-docs
						</directory>
					</resource>
				</resources>
			</configuration>
		</execution>
	</executions>
</plugin>
1Asciidoctor プラグインの既存の宣言。
2 リソースプラグインは同じフェーズ (prepare-package) にバインドされているため、Asciidoctor プラグインの後に宣言する必要があり、リソースプラグインは Asciidoctor プラグインの後に実行して、ドキュメントがコピーされる前に生成されるようにする必要があります。
3 生成されたドキュメントをビルド出力の static/docs ディレクトリにコピーします。ここから、jar ファイルに含まれます。
Gradle
bootJar {
	dependsOn asciidoctor (1)
	from ("${asciidoctor.outputDir}/html5") { (2)
		into 'static/docs'
	}
}
1jar を構築する前に、ドキュメントが生成されていることを確認してください。
2 生成されたドキュメントを jar の static/docs ディレクトリにコピーします。

ドキュメントスニペットの生成

Spring REST Docs は、Spring MVC のテストフレームワーク、Spring WebFlux の WebTestClient、または安心してください (英語) を使用して、ドキュメント化するサービスにリクエストを行います。次に、リクエストと結果のレスポンスのドキュメントスニペットを生成します。

テストのセットアップ

テストをどのように設定するかは、使用するテストフレームワークによって異なります。Spring REST Docs は、JUnit 5 および JUnit 4 に最高のサポートを提供します。JUnit 5 をお勧めします。TestNG などの他のフレームワークもサポートされていますが、少し多くのセットアップが必要です。

JUnit 5 テストのセットアップ

JUnit 5 を使用する場合、ドキュメントスニペットを生成する最初のステップは、RestDocumentationExtension をテストクラスに適用することです。次の例は、その方法を示しています。

@ExtendWith(RestDocumentationExtension.class)
public class JUnit5ExampleTests {

典型的な Spring アプリケーションをテストするときは、SpringExtension も適用する必要があります。

@ExtendWith({RestDocumentationExtension.class, SpringExtension.class})
public class JUnit5ExampleTests {

RestDocumentationExtension は、プロジェクトのビルドツールに基づく出力ディレクトリで自動的に構成されます。

ビルドツール 出力ディレクトリ

Maven

target/generated-snippets

Gradle

build/generated-snippets

JUnit 5.1 を使用している場合は、拡張機能をテストクラスのフィールドとして登録し、作成時に出力ディレクトリを提供することで、デフォルトをオーバーライドできます。次の例は、その方法を示しています。

public class JUnit5ExampleTests {

	@RegisterExtension
	final RestDocumentationExtension restDocumentation = new RestDocumentationExtension ("custom");

}

次に、MockMvc または WebTestClient、または REST Assured を構成するための @BeforeEach メソッドを提供する必要があります。次のリストは、その方法を示しています。

MockMvc
private MockMvc mockMvc;

@BeforeEach
void setUp(WebApplicationContext webApplicationContext, RestDocumentationContextProvider restDocumentation) {
	this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
		.apply(documentationConfiguration(restDocumentation)) (1)
		.build();
}
1MockMvc インスタンスは、MockMvcRestDocumentationConfigurer を使用して構成されます。このクラスのインスタンスは、org.springframework.restdocs.mockmvc.MockMvcRestDocumentation の静的 documentationConfiguration() メソッドから取得できます。
WebTestClient
private WebTestClient webTestClient;

@BeforeEach
void setUp(ApplicationContext applicationContext, RestDocumentationContextProvider restDocumentation) {
	this.webTestClient = WebTestClient.bindToApplicationContext(applicationContext)
		.configureClient()
		.filter(documentationConfiguration(restDocumentation)) (1)
		.build();
}
1WebTestClient インスタンスは、WebTestClientRestDocumentationConfigurer を ExchangeFilterFunction として追加することによって構成されます。このクラスのインスタンスは、org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation の静的 documentationConfiguration() メソッドから取得できます。
REST Assured
private RequestSpecification spec;

@BeforeEach
void setUp(RestDocumentationContextProvider restDocumentation) {
	this.spec = new RequestSpecBuilder().addFilter(documentationConfiguration(restDocumentation)) (1)
		.build();
}
1REST Assured は、RestAssuredRestDocumentationConfigurer を Filter として追加することによって構成されます。このクラスのインスタンスは、org.springframework.restdocs.restassured パッケージの RestAssuredRestDocumentation の静的 documentationConfiguration() メソッドから取得できます。

コンフィギュアラーは適切なデフォルトを適用し、構成をカスタマイズするための API も提供します。詳細については、構成セクションを参照してください。

JUnit 4 テストのセットアップ

JUnit 4 を使用する場合、ドキュメントスニペットを生成する最初のステップは、JUnit @Rule としてアノテーションが付けられた publicJUnitRestDocumentation フィールドを宣言することです。次の例は、その方法を示しています。

@Rule
public JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();

デフォルトでは、JUnitRestDocumentation ルールは、プロジェクトのビルドツールに基づく出力ディレクトリで自動的に構成されます。

ビルドツール 出力ディレクトリ

Maven

target/generated-snippets

Gradle

build/generated-snippets

JUnitRestDocumentation インスタンスの作成時に出力ディレクトリを指定することで、デフォルトをオーバーライドできます。次の例は、その方法を示しています。

@Rule
public JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation("custom");

次に、MockMvc または WebTestClient、または REST Assured を構成するための @Before メソッドを提供する必要があります。次の例は、その方法を示しています。

MockMvc
private MockMvc mockMvc;

@Autowired
private WebApplicationContext context;

@Before
public void setUp() {
	this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
		.apply(documentationConfiguration(this.restDocumentation)) (1)
		.build();
}
1MockMvc インスタンスは、MockMvcRestDocumentationConfigurer を使用して構成されます。このクラスのインスタンスは、org.springframework.restdocs.mockmvc.MockMvcRestDocumentation の静的 documentationConfiguration() メソッドから取得できます。
WebTestClient
private WebTestClient webTestClient;

@Autowired
private ApplicationContext context;

@Before
public void setUp() {
	this.webTestClient = WebTestClient.bindToApplicationContext(this.context)
		.configureClient()
		.filter(documentationConfiguration(this.restDocumentation)) (1)
		.build();
}
1WebTestClient インスタンスは、WebTestclientRestDocumentationConfigurer を ExchangeFilterFunction として追加することによって構成されます。このクラスのインスタンスは、org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation の静的 documentationConfiguration() メソッドから取得できます。
REST Assured
private RequestSpecification spec;

@Before
public void setUp() {
	this.spec = new RequestSpecBuilder().addFilter(documentationConfiguration(this.restDocumentation)) (1)
		.build();
}
1REST Assured は、RestAssuredRestDocumentationConfigurer を Filter として追加することによって構成されます。このクラスのインスタンスは、org.springframework.restdocs.restassured パッケージの RestAssuredRestDocumentation の静的 documentationConfiguration() メソッドから取得できます。

コンフィギュアラーは適切なデフォルトを適用し、構成をカスタマイズするための API も提供します。詳細については、構成セクションを参照してください。

JUnit を使用しないテストのセットアップ

JUnit が使用されていない場合の構成は、使用されている場合とほとんど同じです。このセクションでは、主な違いについて説明します。TestNG サンプル [GitHub] (英語) もこのアプローチを示しています。

最初の違いは、JUnitRestDocumentation の代わりに ManualRestDocumentation を使用する必要があることです。また、@Rule アノテーションは必要ありません。次の例は、ManualRestDocumentation の使用方法を示しています。

private ManualRestDocumentation restDocumentation = new ManualRestDocumentation();

次に、各テストの前に ManualRestDocumentation.beforeTest(Class, String) を呼び出す必要があります。これは、MockMvc、WebTestClient、REST Assured を構成する方法の一部として行うことができます。次の例は、その方法を示しています。

MockMvc
private MockMvc mockMvc;

@Autowired
private WebApplicationContext context;

@BeforeMethod
public void setUp(Method method) {
	this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
		.apply(documentationConfiguration(this.restDocumentation))
		.build();
	this.restDocumentation.beforeTest(getClass(), method.getName());
}
WebTestClient
private WebTestClient webTestClient;

@Autowired
private ApplicationContext context;

@BeforeMethod
public void setUp(Method method) {
	this.webTestClient = WebTestClient.bindToApplicationContext(this.context)
		.configureClient()
		.filter(documentationConfiguration(this.restDocumentation)) (1)
		.build();
	this.restDocumentation.beforeTest(getClass(), method.getName());
}
REST Assured
private RequestSpecification spec;

@BeforeMethod
public void setUp(Method method) {
	this.spec = new RequestSpecBuilder().addFilter(documentationConfiguration(this.restDocumentation)).build();
	this.restDocumentation.beforeTest(getClass(), method.getName());
}

最後に、各テストの後に ManualRestDocumentation.afterTest を呼び出す必要があります。次の例は、TestNG でこれを行う方法を示しています。

@AfterMethod
public void tearDown() {
	this.restDocumentation.afterTest();
}

RESTful サービスの呼び出し

テストフレームワークを構成したため、それを使用して RESTful サービスを呼び出し、リクエストとレスポンスをドキュメント化できます。次の例は、その方法を示しています。

MockMvc
this.mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON)) (1)
	.andExpect(status().isOk()) (2)
	.andDo(document("index")); (3)
1 サービスのルート (/) を呼び出し、application/json レスポンスが必要であることを示します。
2 サービスが予期したレスポンスを生成したことをアサートします。
3 サービスの呼び出しをドキュメント化し、スニペットを index という名前のディレクトリ (構成済みの出力ディレクトリにあります) に書き込みます。スニペットは RestDocumentationResultHandler によって書かれています。このクラスのインスタンスは、org.springframework.restdocs.mockmvc.MockMvcRestDocumentation の静的 document メソッドから取得できます。
WebTestClient
this.webTestClient.get()
	.uri("/")
	.accept(MediaType.APPLICATION_JSON) (1)
	.exchange()
	.expectStatus()
	.isOk() (2)
	.expectBody()
	.consumeWith(document("index")); (3)
1 サービスのルート (/) を呼び出し、application/json レスポンスが必要であることを示します。
2 サービスが予期したレスポンスを生成したことをアサートします。
3 サービスの呼び出しをドキュメント化し、スニペットを index という名前のディレクトリ (構成済みの出力ディレクトリにあります) に書き込みます。スニペットは ExchangeResult の Consumer によって書き込まれます。このようなコンシューマーは、org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation の静的 document メソッドから取得できます。
REST Assured
RestAssured.given(this.spec) (1)
	.accept("application/json") (2)
	.filter(document("index")) (3)
	.when()
	.get("/") (4)
	.then()
	.assertThat()
	.statusCode(is(200)); (5)
1@Before メソッドで初期化された仕様を適用します。
2application/json レスポンスが必要であることを示します。
3 サービスの呼び出しをドキュメント化し、スニペットを index という名前のディレクトリ (構成済みの出力ディレクトリにあります) に書き込みます。スニペットは RestDocumentationFilter によって書かれています。このクラスのインスタンスは、org.springframework.restdocs.restassured パッケージの RestAssuredRestDocumentation の静的 document メソッドから取得できます。
4 サービスのルート (/) を呼び出します。
5 サービスが期待されるレスポンスを生成することをアサートします。

デフォルトでは、6 つのスニペットが書き込まれます。

  • <output-directory>/index/curl-request.adoc

  • <output-directory>/index/http-request.adoc

  • <output-directory>/index/http-response.adoc

  • <output-directory>/index/httpie-request.adoc

  • <output-directory>/index/request-body.adoc

  • <output-directory>/index/response-body.adoc

Spring REST Docs で作成できるこれらのスニペットおよびその他のスニペットの詳細については、API のドキュメント化を参照してください。

スニペットを使用する

生成されたスニペットを使用する前に、.adoc ソースファイルを作成する必要があります。ファイルに .adoc 接尾辞が付いていれば、好きな名前を付けることができます。結果の HTML ファイルは同じ名前ですが、.html サフィックスが付いています。ソースファイルと結果の HTML ファイルのデフォルトの場所は、Maven と Gradle のどちらを使用するかによって異なります。

ビルドツール ソースファイル 生成されたファイル

Maven

src/main/asciidoc/*.adoc

target/generated-docs/*.html

Gradle

src/docs/asciidoc/*.adoc

build/asciidoc/html5/*.html

インクルードマクロ (英語) を使用して、生成されたスニペットを手動で作成した Asciidoc ファイル (このセクションで前述) に含めることができます。ビルド構成で構成された spring-restdocs-asciidoctor によって自動的に設定される snippets 属性を使用して、スニペットの出力ディレクトリを参照できます。次の例は、その方法を示しています。

include::{snippets}/index/curl-request.adoc[]

API のドキュメント化

このセクションでは、Spring REST Docs を使用して API をドキュメント化する方法について詳しく説明します。

ハイパーメディア

Spring REST Docs は、ハイパーメディアベース [Wikipedia] (英語) の API でリンクをドキュメント化するためのサポートを提供します。次の例は、その使用方法を示しています。

MockMvc
this.mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON))
	.andExpect(status().isOk())
	.andDo(document("index", links((1)
			linkWithRel("alpha").description("Link to the alpha resource"), (2)
			linkWithRel("bravo").description("Link to the bravo resource")))); (3)
1Spring REST ドキュメントを構成して、レスポンスのリンクを説明するスニペットを生成します。org.springframework.restdocs.hypermedia.HypermediaDocumentation で静的 links メソッドを使用します。
2rel が alpha であるリンクを期待します。org.springframework.restdocs.hypermedia.HypermediaDocumentation で静的 linkWithRel メソッドを使用します。
3rel が bravo であるリンクを期待します。
WebTestClient
this.webTestClient.get()
	.uri("/")
	.accept(MediaType.APPLICATION_JSON)
	.exchange()
	.expectStatus()
	.isOk()
	.expectBody()
	.consumeWith(document("index", links((1)
			linkWithRel("alpha").description("Link to the alpha resource"), (2)
			linkWithRel("bravo").description("Link to the bravo resource")))); (3)
1Spring REST ドキュメントを構成して、レスポンスのリンクを説明するスニペットを生成します。org.springframework.restdocs.hypermedia.HypermediaDocumentation で静的 links メソッドを使用します。
2rel が alpha であるリンクを期待します。org.springframework.restdocs.hypermedia.HypermediaDocumentation で静的 linkWithRel メソッドを使用します。
3rel が bravo であるリンクを期待します。
REST Assured
RestAssured.given(this.spec)
	.accept("application/json")
	.filter(document("index", links((1)
			linkWithRel("alpha").description("Link to the alpha resource"), (2)
			linkWithRel("bravo").description("Link to the bravo resource")))) (3)
	.get("/")
	.then()
	.assertThat()
	.statusCode(is(200));
1Spring REST ドキュメントを構成して、レスポンスのリンクを説明するスニペットを生成します。org.springframework.restdocs.hypermedia.HypermediaDocumentation で静的 links メソッドを使用します。
2rel が alpha であるリンクを期待します。org.springframework.restdocs.hypermedia.HypermediaDocumentation で静的 linkWithRel メソッドを使用します。
3rel が bravo であるリンクを期待します。

その結果、リソースのリンクを説明するテーブルを含む links.adoc という名前のスニペットが作成されます。

レスポンス内のリンクに title がある場合、記述子から説明を省略でき、title が使用されます。説明を省略し、リンクに title がない場合、エラーが発生します。

リンクをドキュメント化する場合、ドキュメント化されていないリンクがレスポンスで見つかった場合、テストは失敗します。同様に、ドキュメント化されたリンクがレスポンスに見つからず、リンクがオプションとしてマークされていない場合も、テストは失敗します。

リンクをドキュメント化したくない場合は、無視するようにマークできます。そうすることで、上記の失敗を回避しながら、生成されたスニペットに表示されなくなります。

ドキュメント化されていないリンクがテストの失敗を引き起こさない、緩和モードでリンクをドキュメント化することもできます。これを行うには、org.springframework.restdocs.hypermedia.HypermediaDocumentation で relaxedLinks メソッドを使用します。これは、リンクのサブセットのみに注目したい特定のシナリオをドキュメント化する場合に役立ちます。

デフォルトでは、次の 2 つのリンク形式が認識されます。

  • 原子: リンクは links という名前の配列にあると予想されます。これは、レスポンスのコンテンツ型が application/json と互換性がある場合にデフォルトで使用されます。

  • HAL: リンクは _links という名前のマップにあると予想されます。これは、レスポンスのコンテンツ型が application/hal+json と互換性がある場合にデフォルトで使用されます。

Atom または HAL 形式のリンクを使用するが、コンテンツ型が異なる場合は、組み込みの LinkExtractor 実装の 1 つを links に提供できます。次の例は、その方法を示しています。

MockMvc
.andDo(document("index", links(halLinks(), (1)
		linkWithRel("alpha").description("Link to the alpha resource"),
		linkWithRel("bravo").description("Link to the bravo resource"))));
1 リンクが HAL 形式であることを示します。org.springframework.restdocs.hypermedia.HypermediaDocumentation で静的 halLinks メソッドを使用します。
WebTestClient
.consumeWith(document("index", links(halLinks(), (1)
		linkWithRel("alpha").description("Link to the alpha resource"),
		linkWithRel("bravo").description("Link to the bravo resource"))));
1 リンクが HAL 形式であることを示します。org.springframework.restdocs.hypermedia.HypermediaDocumentation で静的 halLinks メソッドを使用します。
REST Assured
.filter(document("index", links(halLinks(), (1)
		linkWithRel("alpha").description("Link to the alpha resource"),
		linkWithRel("bravo").description("Link to the bravo resource"))))
1 リンクが HAL 形式であることを示します。org.springframework.restdocs.hypermedia.HypermediaDocumentation で静的 halLinks メソッドを使用します。

API が Atom または HAL 以外の形式でリンクを表す場合、LinkExtractor インターフェースの独自の実装を提供して、レスポンスからリンクを抽出できます。

HAL を使用する場合の self や curies など、すべてのレスポンスに共通するリンクをドキュメント化するのではなく、概要セクションで一度ドキュメント化してから、残りの API ドキュメントで無視することをお勧めします。そのために、スニペットを再利用するためのサポートを構築して、特定のリンクを無視するように事前構成されたスニペットにリンク記述子を追加できます。次の例は、その方法を示しています。

public static LinksSnippet links(LinkDescriptor... descriptors) {
	return HypermediaDocumentation.links(linkWithRel("self").ignored().optional(), linkWithRel("curies").ignored())
		.and(descriptors);
}

リクエストとレスポンスのペイロード

前述のハイパーメディア固有のサポートに加えて、リクエストおよびレスポンスペイロードの一般的なドキュメントのサポートも提供されます。

デフォルトでは、Spring REST Docs はリクエストの本文とレスポンスの本文のスニペットを自動的に生成します。これらのスニペットには、それぞれ request-body.adoc および response-body.adoc という名前が付けられます。

リクエストとレスポンスのフィールド

リクエストまたはレスポンスペイロードのより詳細なドキュメントを提供するために、ペイロードのフィールドをドキュメント化するためのサポートが提供されています。

次のペイロードを検討してください。

{
	"contact": {
		"name": "Jane Doe",
		"email": "[email protected] (英語)  "
	}
}

前の例のフィールドを次のようにドキュメント化できます。

MockMvc
this.mockMvc.perform(get("/user/5").accept(MediaType.APPLICATION_JSON))
	.andExpect(status().isOk())
	.andDo(document("index", responseFields((1)
			fieldWithPath("contact.email").description("The user's email address"), (2)
			fieldWithPath("contact.name").description("The user's name")))); (3)
1Spring REST ドキュメントを構成して、レスポンスペイロードのフィールドを説明するスニペットを生成します。リクエストをドキュメント化するには、requestFields を使用できます。どちらも org.springframework.restdocs.payload.PayloadDocumentation の静的メソッドです。
2 パスが contact.email のフィールドが必要です。org.springframework.restdocs.payload.PayloadDocumentation で静的 fieldWithPath メソッドを使用します。
3 パスが contact.name のフィールドが必要です。
WebTestClient
this.webTestClient.get().uri("user/5").accept(MediaType.APPLICATION_JSON)
	.exchange().expectStatus().isOk().expectBody()
	.consumeWith(document("user",
		responseFields((1)
			fieldWithPath("contact.email").description("The user's email address"), (2)
			fieldWithPath("contact.name").description("The user's name")))); (3)
1Spring REST ドキュメントを構成して、レスポンスペイロードのフィールドを説明するスニペットを生成します。リクエストをドキュメント化するには、requestFields を使用できます。どちらも org.springframework.restdocs.payload.PayloadDocumentation の静的メソッドです。
2 パスが contact.email のフィールドが必要です。org.springframework.restdocs.payload.PayloadDocumentation で静的 fieldWithPath メソッドを使用します。
3 パスが contact.name のフィールドが必要です。
REST Assured
RestAssured.given(this.spec)
	.accept("application/json")
	.filter(document("user", responseFields((1)
			fieldWithPath("contact.name").description("The user's name"), (2)
			fieldWithPath("contact.email").description("The user's email address")))) (3)
	.when()
	.get("/user/5")
	.then()
	.assertThat()
	.statusCode(is(200));
1Spring REST ドキュメントを構成して、レスポンスペイロードのフィールドを説明するスニペットを生成します。リクエストをドキュメント化するには、requestFields を使用できます。どちらも org.springframework.restdocs.payload.PayloadDocumentation の静的メソッドです。
2 パスが contact.email のフィールドが必要です。org.springframework.restdocs.payload.PayloadDocumentation で静的 fieldWithPath メソッドを使用します。
3 パスが contact.name のフィールドが必要です。

結果は、フィールドを説明するテーブルを含むスニペットです。リクエストの場合、このスニペットの名前は request-fields.adoc です。レスポンスの場合、このスニペットの名前は response-fields.adoc です。

フィールドをドキュメント化する場合、ペイロードにドキュメント化されていないフィールドが見つかった場合、テストは失敗します。同様に、ドキュメント化されたフィールドがペイロードに見つからず、そのフィールドがオプションとしてマークされていない場合も、テストは失敗します。

すべてのフィールドに詳細なドキュメントを提供したくない場合は、ペイロードのサブセクション全体をドキュメント化できます。次の例は、その方法を示しています。

MockMvc
this.mockMvc.perform(get("/user/5").accept(MediaType.APPLICATION_JSON))
	.andExpect(status().isOk())
	.andDo(document("index", responseFields((1)
			subsectionWithPath("contact").description("The user's contact details")))); (1)
1 パス contact でサブセクションをドキュメント化します。contact.email と contact.name もドキュメント化されているように見えるようになりました。org.springframework.restdocs.payload.PayloadDocumentation で静的 subsectionWithPath メソッドを使用します。
WebTestClient
this.webTestClient.get().uri("user/5").accept(MediaType.APPLICATION_JSON)
	.exchange().expectStatus().isOk().expectBody()
	.consumeWith(document("user",
		responseFields(
			subsectionWithPath("contact").description("The user's contact details")))); (1)
1 パス contact でサブセクションをドキュメント化します。contact.email と contact.name もドキュメント化されているように見えるようになりました。org.springframework.restdocs.payload.PayloadDocumentation で静的 subsectionWithPath メソッドを使用します。
REST Assured
RestAssured.given(this.spec)
	.accept("application/json")
	.filter(document("user",
			responseFields(subsectionWithPath("contact").description("The user's contact details")))) (1)
	.when()
	.get("/user/5")
	.then()
	.assertThat()
	.statusCode(is(200));
1 パス contact でサブセクションをドキュメント化します。contact.email と contact.name もドキュメント化されているように見えるようになりました。org.springframework.restdocs.payload.PayloadDocumentation で静的 subsectionWithPath メソッドを使用します。

subsectionWithPath は、ペイロードの特定のセクションの概要を提供できます。その後、サブセクション用に個別のより詳細なドキュメントを作成できます。リクエストまたはレスポンスペイロードのサブセクションのドキュメント化を参照してください。

フィールドまたはサブセクションをまったくドキュメント化したくない場合は、無視するようにマークできます。これにより、前述の失敗を回避しながら、生成されたスニペットに表示されなくなります。

ドキュメント化されていないフィールドがテストの失敗の原因にならない、緩和モードでフィールドをドキュメント化することもできます。これを行うには、org.springframework.restdocs.payload.PayloadDocumentation で relaxedRequestFields および relaxedResponseFields メソッドを使用します。これは、ペイロードのサブセットのみに注目したい特定のシナリオをドキュメント化する場合に役立ちます。

デフォルトでは、Spring REST Docs は、ドキュメント化するペイロードが JSON であると想定します。XML ペイロードをドキュメント化する場合、リクエストまたはレスポンスのコンテンツ型は application/xml と互換性がある必要があります。
JSON ペイロードのフィールド

このセクションでは、JSON ペイロードのフィールドを操作する方法について説明します。

JSON フィールドパス

JSON フィールドパスは、ドット表記または 括弧 表記のいずれかを使用します。ドット表記では "." を使用します。パス内の各キーを区切ります (たとえば、a.b)。括弧 表記では、各キーを 角括弧 と一重引用符で囲みます (たとえば、['a']['b'])。いずれの場合も、[] を使用して配列を識別します。ドット表記はより簡潔ですが、括弧 表記を使用すると、キー名内で . を使用できます (たとえば、['a.b'])。2 つの異なる表記を同じパスで使用できます (たとえば、a['b'])。

次の JSON ペイロードを検討してください。

{
	"a":{
		"b":[
			{
				"c":"one"
			},
			{
				"c":"two"
			},
			{
				"d":"three"
			}
		],
		"e.dot" : "four"
	}
}

上記の JSON ペイロードには、次のパスがすべて存在します。

パス

a

b を含むオブジェクト

a.b

3 つのオブジェクトを含む配列

['a']['b']

3 つのオブジェクトを含む配列

a['b']

3 つのオブジェクトを含む配列

['a'].b

3 つのオブジェクトを含む配列

a.b[]

3 つのオブジェクトを含む配列

a.b[].c

文字列 one および two を含む配列

a.b[].d

文字列 three

a['e.dot']

文字列 four

['a']['e.dot']

文字列 four

ルートで配列を使用するペイロードをドキュメント化することもできます。パス [] は配列全体を指します。次に、括弧 またはドット表記を使用して、配列のエントリ内のフィールドを識別できます。例: [].id は、次の配列で見つかったすべてのオブジェクトの id フィールドに対応します。

[
	{
		"id":1
	},
	{
		"id":2
	}
]

* をワイルドカードとして使用して、異なる名前のフィールドに一致させることができます。例: users.*.role を使用して、次の JSON ですべてのユーザーのロールをドキュメント化できます。

{
	"users":{
		"ab12cd34":{
			"role": "Administrator"
		},
		"12ab34cd":{
			"role": "Guest"
		}
	}
}
JSON フィールドの種類

フィールドがドキュメント化されると、Spring REST Docs はペイロードを調べてその型を判別しようとします。7 つの異なる型がサポートされています。

タイプ 説明

array

フィールドの各出現箇所の値は配列です。

boolean

フィールドの各出現箇所の値はブール値 (true または false) です。

object

フィールドの各出現箇所の値はオブジェクトです。

number

フィールドの各出現箇所の値は数値です。

null

フィールドの各出現箇所の値は null です。

string

フィールドの各出現箇所の値は文字列です。

varies

このフィールドは、さまざまな型のペイロードで複数回発生します。

FieldDescriptor で type(Object) メソッドを使用して、型を明示的に設定することもできます。提供された Object の toString メソッドの結果は、ドキュメントで使用されます。通常、JsonFieldType によって列挙された値の 1 つが使用されます。次の例は、その方法を示しています。

MockMvc
.andDo(document("index", responseFields(fieldWithPath("contact.email").type(JsonFieldType.STRING) (1)
	.description("The user's email address"))));
1 フィールドの型を String に設定します。
WebTestClient
.consumeWith(document("user",
	responseFields(
		fieldWithPath("contact.email")
			.type(JsonFieldType.STRING) (1)
			.description("The user's email address"))));
1 フィールドの型を String に設定します。
REST Assured
.filter(document("user", responseFields(fieldWithPath("contact.email").type(JsonFieldType.STRING) (1)
	.description("The user's email address"))))
1 フィールドの型を String に設定します。
XML ペイロード

このセクションでは、XML ペイロードを操作する方法について説明します。

XML フィールドパス

XML フィールドパスは、XPath を使用して記述されます。/ は、子ノードに降りるために使用されます。

XML フィールド型

XML ペイロードをドキュメント化する場合、FieldDescriptor で type(Object) メソッドを使用して、フィールドの型を指定する必要があります。提供された型の toString メソッドの結果は、ドキュメントで使用されます。

フィールド記述子の再利用

スニペットの再利用の一般的なサポートに加えて、リクエストスニペットとレスポンススニペットでは、パスプレフィックスを使用して追加の記述子を構成できます。これにより、リクエストまたはレスポンスペイロードの繰り返し部分の記述子を一度作成してから再利用できます。

本を返すエンドポイントを考えてみましょう:

{
	"title": "Pride and Prejudice",
	"author": "Jane Austen"
}

title および author のパスは、それぞれ title および author です。

ここで、本の配列を返すエンドポイントを考えてみましょう:

[{
	"title": "Pride and Prejudice",
	"author": "Jane Austen"
},
{
	"title": "To Kill a Mockingbird",
	"author": "Harper Lee"
}]

title および author のパスは、それぞれ [].title および [].author です。単一のブックとブックの配列の唯一の違いは、フィールドのパスに []. プレフィックスが付いていることです。

ブックをドキュメント化する記述子は、次のように作成できます。

FieldDescriptor[] book = new FieldDescriptor[] { fieldWithPath("title").description("Title of the book"),
		fieldWithPath("author").description("Author of the book") };

次に、使用して、次のように 1 つのブックをドキュメント化できます。

MockMvc
this.mockMvc.perform(get("/books/1").accept(MediaType.APPLICATION_JSON))
	.andExpect(status().isOk())
	.andDo(document("book", responseFields(book))); (1)
1 既存の記述子を使用して title と author をドキュメント化する
WebTestClient
this.webTestClient.get().uri("/books/1").accept(MediaType.APPLICATION_JSON)
	.exchange().expectStatus().isOk().expectBody()
	.consumeWith(document("book",
		responseFields(book))); (1)
1 既存の記述子を使用して title と author をドキュメント化する
REST Assured
RestAssured.given(this.spec)
	.accept("application/json")
	.filter(document("book", responseFields(book))) (1)
	.when()
	.get("/books/1")
	.then()
	.assertThat()
	.statusCode(is(200));
1 既存の記述子を使用して title と author をドキュメント化する

次のように、記述子を使用して書籍の配列をドキュメント化することもできます。

MockMvc
this.mockMvc.perform(get("/books").accept(MediaType.APPLICATION_JSON))
	.andExpect(status().isOk())
	.andDo(document("book", responseFields(fieldWithPath("[]").description("An array of books")) (1)
		.andWithPrefix("[].", book))); (2)
1 配列をドキュメント化します。
2[]. で始まる既存の記述子を使用して、[].title および [].author をドキュメント化します。
WebTestClient
this.webTestClient.get().uri("/books").accept(MediaType.APPLICATION_JSON)
	.exchange().expectStatus().isOk().expectBody()
	.consumeWith(document("books",
		responseFields(
			fieldWithPath("[]")
				.description("An array of books")) (1)
				.andWithPrefix("[].", book))); (2)
1 配列をドキュメント化します。
2[]. で始まる既存の記述子を使用して、[].title および [].author をドキュメント化します。
REST Assured
RestAssured.given(this.spec)
	.accept("application/json")
	.filter(document("books", responseFields(fieldWithPath("[]").description("An array of books")) (1)
		.andWithPrefix("[].", book))) (2)
	.when()
	.get("/books")
	.then()
	.assertThat()
	.statusCode(is(200));
1 配列をドキュメント化します。
2[]. で始まる既存の記述子を使用して、[].title および [].author をドキュメント化します。

リクエストまたはレスポンスペイロードのサブセクションのドキュメント化

ペイロードが大きい場合や構造的に複雑な場合は、ペイロードの個々のセクションをドキュメント化すると便利です。REST ドキュメントを使用すると、ペイロードのサブセクションを抽出してドキュメント化することで、これを行うことができます。

リクエストまたはレスポンス本文のサブセクションのドキュメント化

次の JSON レスポンス本文を検討してください。

{
	"weather": {
		"wind": {
			"speed": 15.3,
			"direction": 287.0
		},
		"temperature": {
			"high": 21.2,
			"low": 14.8
		}
	}
}

次のように、temperature オブジェクトをドキュメント化するスニペットを作成できます。

MockMvc
this.mockMvc.perform(get("/locations/1").accept(MediaType.APPLICATION_JSON))
	.andExpect(status().isOk())
	.andDo(document("location", responseBody(beneathPath("weather.temperature")))); (1)
1 レスポンス本文のサブセクションを含むスニペットを生成します。org.springframework.restdocs.payload.PayloadDocumentation で静的 responseBody および beneathPath メソッドを使用します。リクエスト本文のスニペットを作成するには、responseBody の代わりに requestBody を使用できます。
WebTestClient
this.webTestClient.get().uri("/locations/1").accept(MediaType.APPLICATION_JSON)
	.exchange().expectStatus().isOk().expectBody()
	.consumeWith(document("temperature",
		responseBody(beneathPath("weather.temperature")))); (1)
1 レスポンス本文のサブセクションを含むスニペットを生成します。org.springframework.restdocs.payload.PayloadDocumentation で静的 responseBody および beneathPath メソッドを使用します。リクエスト本文のスニペットを作成するには、responseBody の代わりに requestBody を使用できます。
REST Assured
RestAssured.given(this.spec)
	.accept("application/json")
	.filter(document("location", responseBody(beneathPath("weather.temperature")))) (1)
	.when()
	.get("/locations/1")
	.then()
	.assertThat()
	.statusCode(is(200));
1 レスポンス本文のサブセクションを含むスニペットを生成します。org.springframework.restdocs.payload.PayloadDocumentation で静的 responseBody および beneathPath メソッドを使用します。リクエスト本文のスニペットを作成するには、responseBody の代わりに requestBody を使用できます。

結果は、次の内容のスニペットです。

{
	"temperature": {
		"high": 21.2,
		"low": 14.8
	}
}

スニペットの名前を区別するために、サブセクションの識別子が含まれています。デフォルトでは、この識別子は beneath-${path} です。例: 上記のコードは、response-body-beneath-weather.temperature.adoc という名前のスニペットになります。次のように、withSubsectionId(String) メソッドを使用して識別子をカスタマイズできます。

responseBody(beneathPath("weather.temperature").withSubsectionId("temp"));

結果は request-body-temp.adoc という名前のスニペットです。

リクエストまたはレスポンスのサブセクションのフィールドのドキュメント化

リクエストまたはレスポンス本文のサブセクションをドキュメント化するだけでなく、特定のサブセクション内のフィールドをドキュメント化することもできます。次のように、temperature オブジェクト (high および low) のフィールドをドキュメント化するスニペットを作成できます。

MockMvc
this.mockMvc.perform(get("/locations/1").accept(MediaType.APPLICATION_JSON))
	.andExpect(status().isOk())
	.andDo(document("location", responseFields(beneathPath("weather.temperature"), (1)
			fieldWithPath("high").description("The forecast high in degrees celcius"), (2)
			fieldWithPath("low").description("The forecast low in degrees celcius"))));
1 パス weather.temperature のレスポンスペイロードのサブセクションにあるフィールドを説明するスニペットを生成します。org.springframework.restdocs.payload.PayloadDocumentation で静的 beneathPath メソッドを使用します。
2high および low フィールドをドキュメント化します。
WebTestClient
this.webTestClient.get().uri("/locations/1").accept(MediaType.APPLICATION_JSON)
	.exchange().expectStatus().isOk().expectBody()
	.consumeWith(document("temperature",
		responseFields(beneathPath("weather.temperature"), (1)
			fieldWithPath("high").description("The forecast high in degrees celcius"), (2)
			fieldWithPath("low").description("The forecast low in degrees celcius"))));
1 パス weather.temperature のレスポンスペイロードのサブセクションにあるフィールドを説明するスニペットを生成します。org.springframework.restdocs.payload.PayloadDocumentation で静的 beneathPath メソッドを使用します。
2high および low フィールドをドキュメント化します。
REST Assured
RestAssured.given(this.spec)
	.accept("application/json")
	.filter(document("location", responseFields(beneathPath("weather.temperature"), (1)
			fieldWithPath("high").description("The forecast high in degrees celcius"), (2)
			fieldWithPath("low").description("The forecast low in degrees celcius"))))
	.when()
	.get("/locations/1")
	.then()
	.assertThat()
	.statusCode(is(200));
1 パス weather.temperature のレスポンスペイロードのサブセクションにあるフィールドを説明するスニペットを生成します。org.springframework.restdocs.payload.PayloadDocumentation で静的 beneathPath メソッドを使用します。
2high および low フィールドをドキュメント化します。

結果は、weather.temperature の high および low フィールドを説明するテーブルを含むスニペットです。スニペットの名前を区別するために、サブセクションの識別子が含まれています。デフォルトでは、この識別子は beneath-${path} です。例: 上記のコードは、response-fields-beneath-weather.temperature.adoc という名前のスニペットになります。

クエリパラメーター

queryParameters を使用して、リクエストのクエリパラメーターをドキュメント化できます。次の例は、その方法を示しています。

MockMvc
this.mockMvc.perform(get("/users?page=2&per_page=100")) (1)
	.andExpect(status().isOk())
	.andDo(document("users", queryParameters((2)
			parameterWithName("page").description("The page to retrieve"), (3)
			parameterWithName("per_page").description("Entries per page") (4)
	)));
1 クエリ文字列に page と per_page の 2 つのパラメーターを指定して GET リクエストを実行します。
2Spring REST Docs を構成して、リクエストのクエリパラメーターを説明するスニペットを生成します。org.springframework.restdocs.request.RequestDocumentation で静的 queryParameters メソッドを使用します。
3page パラメーターをドキュメント化します。org.springframework.restdocs.request.RequestDocumentation で静的 parameterWithName メソッドを使用します。
4per_page パラメーターをドキュメント化します。
WebTestClient
this.webTestClient.get().uri("/users?page=2&per_page=100") (1)
	.exchange().expectStatus().isOk().expectBody()
	.consumeWith(document("users", queryParameters((2)
			parameterWithName("page").description("The page to retrieve"), (3)
			parameterWithName("per_page").description("Entries per page") (4)
	)));
1 クエリ文字列に page と per_page の 2 つのパラメーターを指定して GET リクエストを実行します。
2Spring REST Docs を構成して、リクエストのクエリパラメーターを説明するスニペットを生成します。org.springframework.restdocs.request.RequestDocumentation で静的 queryParameters メソッドを使用します。
3page パラメーターをドキュメント化します。org.springframework.restdocs.request.RequestDocumentation で静的 parameterWithName メソッドを使用します。
4per_page パラメーターをドキュメント化します。
REST Assured
RestAssured.given(this.spec)
	.filter(document("users", queryParameters((1)
			parameterWithName("page").description("The page to retrieve"), (2)
			parameterWithName("per_page").description("Entries per page")))) (3)
	.when()
	.get("/users?page=2&per_page=100") (4)
	.then()
	.assertThat()
	.statusCode(is(200));
1Spring REST Docs を構成して、リクエストのクエリパラメーターを説明するスニペットを生成します。org.springframework.restdocs.request.RequestDocumentation で静的 queryParameters メソッドを使用します。
2page パラメーターをドキュメント化します。org.springframework.restdocs.request.RequestDocumentation で静的 parameterWithName メソッドを使用します。
3per_page パラメーターをドキュメント化します。
4 クエリ文字列に page と per_page の 2 つのパラメーターを指定して GET リクエストを実行します。

クエリパラメーターをドキュメント化する場合、ドキュメント化されていないクエリパラメーターがリクエストのクエリ文字列で使用されていると、テストは失敗します。同様に、ドキュメント化されたクエリパラメーターがリクエストのクエリ文字列に見つからず、パラメーターがオプションとしてマークされていない場合も、テストは失敗します。

クエリパラメーターをドキュメント化したくない場合は、無視するようにマークできます。これにより、上記の失敗を回避しながら、生成されたスニペットに表示されなくなります。

ドキュメント化されていないパラメーターがテストの失敗を引き起こさないリラックスモードでクエリパラメーターをドキュメント化することもできます。これを行うには、org.springframework.restdocs.request.RequestDocumentation で relaxedQueryParameters メソッドを使用します。これは、クエリパラメーターのサブセットのみに注目したい特定のシナリオをドキュメント化する場合に役立ちます。

フォームパラメーター

formParameters を使用して、リクエストのフォームパラメーターをドキュメント化できます。次の例は、その方法を示しています。

MockMvc
this.mockMvc.perform(post("/users").param("username", "Tester")) (1)
	.andExpect(status().isCreated())
	.andDo(document("create-user", formParameters((2)
			parameterWithName("username").description("The user's username") (3)
	)));
1 単一のフォームパラメーター username を指定して POST リクエストを実行します。
2Spring REST Docs を構成して、リクエストのフォームパラメーターを説明するスニペットを生成します。org.springframework.restdocs.request.RequestDocumentation で静的 formParameters メソッドを使用します。
3username パラメーターをドキュメント化します。org.springframework.restdocs.request.RequestDocumentation で静的 parameterWithName メソッドを使用します。
WebTestClient
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
formData.add("username", "Tester");
this.webTestClient.post().uri("/users").body(BodyInserters.fromFormData(formData)) (1)
		.exchange().expectStatus().isCreated().expectBody()
		.consumeWith(document("create-user", formParameters((2)
				parameterWithName("username").description("The user's username") (3)
		)));
1 単一のフォームパラメーター username を指定して POST リクエストを実行します。
2Spring REST Docs を構成して、リクエストのフォームパラメーターを説明するスニペットを生成します。org.springframework.restdocs.request.RequestDocumentation で静的 formParameters メソッドを使用します。
3username パラメーターをドキュメント化します。org.springframework.restdocs.request.RequestDocumentation で静的 parameterWithName メソッドを使用します。
REST Assured
RestAssured.given(this.spec)
	.filter(document("create-user", formParameters((1)
			parameterWithName("username").description("The user's username")))) (2)
	.formParam("username", "Tester")
	.when()
	.post("/users") (3)
	.then()
	.assertThat()
	.statusCode(is(200));
1Spring REST Docs を構成して、リクエストのフォームパラメーターを説明するスニペットを生成します。org.springframework.restdocs.request.RequestDocumentation で静的 formParameters メソッドを使用します。
2username パラメーターをドキュメント化します。org.springframework.restdocs.request.RequestDocumentation で静的 parameterWithName メソッドを使用します。
3 単一のフォームパラメーター username を指定して POST リクエストを実行します。

いずれの場合も、リソースによってサポートされるフォームパラメーターを説明するテーブルを含む form-parameters.adoc という名前のスニペットが結果として得られます。

フォームパラメーターをドキュメント化する場合、ドキュメント化されていないフォームパラメーターがリクエスト本文で使用されていると、テストは失敗します。同様に、ドキュメント化されたフォームパラメーターがリクエスト本文に見つからず、フォームパラメーターがオプションとしてマークされていない場合も、テストは失敗します。

フォームパラメーターをドキュメント化したくない場合は、無視するようにマークできます。これにより、上記の失敗を回避しながら、生成されたスニペットに表示されなくなります。

ドキュメント化されていないパラメーターがテストの失敗を引き起こさない緩和モードで、フォームパラメーターをドキュメント化することもできます。これを行うには、org.springframework.restdocs.request.RequestDocumentation で relaxedFormParameters メソッドを使用します。これは、フォームパラメーターのサブセットのみに注目したい特定のシナリオをドキュメント化する場合に役立ちます。

パスパラメーター

pathParameters を使用して、リクエストのパスパラメーターをドキュメント化できます。次の例は、その方法を示しています。

MockMvc
this.mockMvc.perform(get("/locations/{latitude}/{longitude}", 51.5072, 0.1275)) (1)
	.andExpect(status().isOk())
	.andDo(document("locations", pathParameters((2)
			parameterWithName("latitude").description("The location's latitude"), (3)
			parameterWithName("longitude").description("The location's longitude") (4)
	)));
1latitude と longitude の 2 つのパスパラメーターを指定して GET リクエストを実行します。
2 リクエストのパスパラメーターを説明するスニペットを生成するように Spring REST Docs を設定します。org.springframework.restdocs.request.RequestDocumentation で静的 pathParameters メソッドを使用します。
3latitude という名前のパラメーターをドキュメント化します。org.springframework.restdocs.request.RequestDocumentation で静的 parameterWithName メソッドを使用します。
4longitude という名前のパラメーターをドキュメント化します。
WebTestClient
this.webTestClient.get().uri("/locations/{latitude}/{longitude}", 51.5072, 0.1275) (1)
	.exchange().expectStatus().isOk().expectBody()
	.consumeWith(document("locations",
		pathParameters((2)
			parameterWithName("latitude").description("The location's latitude"), (3)
			parameterWithName("longitude").description("The location's longitude")))); (4)
1latitude と longitude の 2 つのパスパラメーターを指定して GET リクエストを実行します。
2 リクエストのパスパラメーターを説明するスニペットを生成するように Spring REST Docs を設定します。org.springframework.restdocs.request.RequestDocumentation で静的 pathParameters メソッドを使用します。
3latitude という名前のパラメーターをドキュメント化します。org.springframework.restdocs.request.RequestDocumentation で静的 parameterWithName メソッドを使用します。
4longitude という名前のパラメーターをドキュメント化します。
REST Assured
RestAssured.given(this.spec)
	.filter(document("locations", pathParameters((1)
			parameterWithName("latitude").description("The location's latitude"), (2)
			parameterWithName("longitude").description("The location's longitude")))) (3)
	.when()
	.get("/locations/{latitude}/{longitude}", 51.5072, 0.1275) (4)
	.then()
	.assertThat()
	.statusCode(is(200));
1 リクエストのパスパラメーターを説明するスニペットを生成するように Spring REST Docs を設定します。org.springframework.restdocs.request.RequestDocumentation で静的 pathParameters メソッドを使用します。
2latitude という名前のパラメーターをドキュメント化します。org.springframework.restdocs.request.RequestDocumentation で静的 parameterWithName メソッドを使用します。
3longitude という名前のパラメーターをドキュメント化します。
4latitude と longitude の 2 つのパスパラメーターを指定して GET リクエストを実行します。

その結果、path-parameters.adoc という名前のスニペットが作成されます。このスニペットには、リソースでサポートされているパスパラメーターを説明するテーブルが含まれています。

MockMvc を使用する場合、ドキュメントでパスパラメーターを使用できるようにするには、MockMvcRequestBuilders ではなく RestDocumentationRequestBuilders のいずれかのメソッドを使用してリクエストを作成する必要があります。

パスパラメーターをドキュメント化する場合、ドキュメント化されていないパスパラメーターがリクエストで使用されていると、テストは失敗します。同様に、ドキュメント化されたパスパラメーターがリクエストに見つからず、パスパラメーターがオプションとしてマークされていない場合も、テストは失敗します。

ドキュメント化されていないパラメーターがテストの失敗を引き起こさない緩和モードで、パスパラメーターをドキュメント化することもできます。これを行うには、org.springframework.restdocs.request.RequestDocumentation で relaxedPathParameters メソッドを使用します。これは、パスパラメーターのサブセットのみに注目したい特定のシナリオをドキュメント化する場合に役立ちます。

パスパラメーターをドキュメント化したくない場合は、無視するようにマークできます。そうすることで、前述の失敗を回避しながら、生成されたスニペットに表示されなくなります。

リクエストパート

requestParts を使用して、マルチパートリクエストのパーツをドキュメント化できます。次の例は、その方法を示しています。

MockMvc
this.mockMvc.perform(multipart("/upload").file("file", "example".getBytes())) (1)
	.andExpect(status().isOk())
	.andDo(document("upload", requestParts((2)
			partWithName("file").description("The file to upload")) (3)
	));
1file という名前の単一のパーツで POST リクエストを実行します。
2 リクエストの部分を説明するスニペットを生成するように Spring REST Docs を構成します。org.springframework.restdocs.request.RequestDocumentation で静的 requestParts メソッドを使用します。
3file という名前のパーツをドキュメント化します。org.springframework.restdocs.request.RequestDocumentation で静的 partWithName メソッドを使用します。
WebTestClient
MultiValueMap<String, Object> multipartData = new LinkedMultiValueMap<>();
multipartData.add("file", "example".getBytes());
this.webTestClient.post().uri("/upload").body(BodyInserters.fromMultipartData(multipartData)) (1)
	.exchange().expectStatus().isOk().expectBody()
	.consumeWith(document("upload", requestParts((2)
		partWithName("file").description("The file to upload")) (3)
));
1file という名前の単一のパーツで POST リクエストを実行します。
2 リクエストの部分を説明するスニペットを生成するように Spring REST Docs を構成します。org.springframework.restdocs.request.RequestDocumentation で静的 requestParts メソッドを使用します。
3file という名前のパーツをドキュメント化します。org.springframework.restdocs.request.RequestDocumentation で静的 partWithName メソッドを使用します。
REST Assured
RestAssured.given(this.spec)
	.filter(document("users", requestParts((1)
			partWithName("file").description("The file to upload")))) (2)
	.multiPart("file", "example") (3)
	.when()
	.post("/upload") (4)
	.then()
	.statusCode(is(200));
1 リクエストの部分を説明するスニペットを生成するように Spring REST Docs を構成します。org.springframework.restdocs.request.RequestDocumentation で静的 requestParts メソッドを使用します。
2file という名前のパーツをドキュメント化します。org.springframework.restdocs.request.RequestDocumentation で静的 partWithName メソッドを使用します。
3file という名前の部分でリクエストを構成します。
4/upload に対して POST リクエストを実行します。

結果は、リソースでサポートされているリクエストパーツを説明するテーブルを含む request-parts.adoc という名前のスニペットです。

リクエストパーツをドキュメント化する場合、ドキュメント化されていないパーツがリクエストで使用されていると、テストは失敗します。同様に、ドキュメント化された部分がリクエスト内に見つからず、その部分がオプションとしてマークされていない場合も、テストは失敗します。

ドキュメント化されていない部分がテストの失敗を引き起こさないリラックスしたモードでリクエスト部分をドキュメント化することもできます。これを行うには、org.springframework.restdocs.request.RequestDocumentation で relaxedRequestParts メソッドを使用します。これは、リクエストパーツのサブセットのみに注目したい特定のシナリオをドキュメント化する場合に役立ちます。

リクエストパーツをドキュメント化したくない場合は、無視するようにマークできます。これにより、前述の失敗を回避しながら、生成されたスニペットに表示されなくなります。

ペイロードのリクエストパート

リクエストパーツのペイロードは、リクエストパーツの本文とそのフィールドのドキュメント化をサポートすることで、リクエスト のペイロードとほぼ同じ方法でドキュメント化できます。

リクエストパーツの本文のドキュメント化

次のように、リクエストパーツの本文を含むスニペットを生成できます。

MockMvc
MockMultipartFile image = new MockMultipartFile("image", "image.png", "image/png", "<<png data>>".getBytes());
MockMultipartFile metadata = new MockMultipartFile("metadata", "", "application/json",
		"{ \"version\": \"1.0\"}".getBytes());

this.mockMvc.perform(multipart("/images").file(image).file(metadata).accept(MediaType.APPLICATION_JSON))
	.andExpect(status().isOk())
	.andDo(document("image-upload", requestPartBody("metadata"))); (1)
1Spring REST ドキュメントを構成して、metadata という名前のリクエストパーツの本文を含むスニペットを生成します。PayloadDocumentation で静的 requestPartBody メソッドを使用します。
WebTestClient
MultiValueMap<String, Object> multipartData = new LinkedMultiValueMap<>();
Resource imageResource = new ByteArrayResource("<<png data>>".getBytes()) {

	@Override
	public String getFilename() {
		return "image.png";
	}

};
multipartData.add("image", imageResource);
multipartData.add("metadata", Collections.singletonMap("version",  "1.0"));

this.webTestClient.post().uri("/images").body(BodyInserters.fromMultipartData(multipartData))
	.accept(MediaType.APPLICATION_JSON).exchange()
	.expectStatus().isOk().expectBody()
	.consumeWith(document("image-upload",
			requestPartBody("metadata"))); (1)
1Spring REST ドキュメントを構成して、metadata という名前のリクエストパーツの本文を含むスニペットを生成します。PayloadDocumentation で静的 requestPartBody メソッドを使用します。
REST Assured
Map<String, String> metadata = new HashMap<>();
metadata.put("version", "1.0");
RestAssured.given(this.spec)
	.accept("application/json")
	.filter(document("image-upload", requestPartBody("metadata"))) (1)
	.when()
	.multiPart("image", new File("image.png"), "image/png")
	.multiPart("metadata", metadata)
	.post("images")
	.then()
	.assertThat()
	.statusCode(is(200));
1Spring REST ドキュメントを構成して、metadata という名前のリクエストパーツの本文を含むスニペットを生成します。PayloadDocumentation で静的 requestPartBody メソッドを使用します。

その結果、パーツの本体を含む request-part-${part-name}-body.adoc という名前のスニペットが作成されます。例: metadata という名前のパーツをドキュメント化すると、request-part-metadata-body.adoc という名前のスニペットが生成されます。

リクエストパーツのフィールドのドキュメント化

次のように、リクエストまたはレスポンスのフィールドとほぼ同じ方法で、リクエストパーツのフィールドをドキュメント化できます。

MockMvc
MockMultipartFile image = new MockMultipartFile("image", "image.png", "image/png", "<<png data>>".getBytes());
MockMultipartFile metadata = new MockMultipartFile("metadata", "", "application/json",
		"{ \"version\": \"1.0\"}".getBytes());

this.mockMvc.perform(multipart("/images").file(image).file(metadata).accept(MediaType.APPLICATION_JSON))
	.andExpect(status().isOk())
	.andDo(document("image-upload", requestPartFields("metadata", (1)
			fieldWithPath("version").description("The version of the image")))); (2)
1Spring REST ドキュメントを構成して、metadata という名前のリクエストパーツのペイロード内のフィールドを説明するスニペットを生成します。PayloadDocumentation で静的 requestPartFields メソッドを使用します。
2 パスが version のフィールドが必要です。org.springframework.restdocs.payload.PayloadDocumentation で静的 fieldWithPath メソッドを使用します。
WebTestClient
MultiValueMap<String, Object> multipartData = new LinkedMultiValueMap<>();
Resource imageResource = new ByteArrayResource("<<png data>>".getBytes()) {

	@Override
	public String getFilename() {
		return "image.png";
	}

};
multipartData.add("image", imageResource);
multipartData.add("metadata", Collections.singletonMap("version",  "1.0"));
this.webTestClient.post().uri("/images").body(BodyInserters.fromMultipartData(multipartData))
	.accept(MediaType.APPLICATION_JSON).exchange()
	.expectStatus().isOk().expectBody()
	.consumeWith(document("image-upload",
		requestPartFields("metadata", (1)
			fieldWithPath("version").description("The version of the image")))); (2)
1Spring REST ドキュメントを構成して、metadata という名前のリクエストパーツのペイロード内のフィールドを説明するスニペットを生成します。PayloadDocumentation で静的 requestPartFields メソッドを使用します。
2 パスが version のフィールドが必要です。org.springframework.restdocs.payload.PayloadDocumentation で静的 fieldWithPath メソッドを使用します。
REST Assured
Map<String, String> metadata = new HashMap<>();
metadata.put("version", "1.0");
RestAssured.given(this.spec)
	.accept("application/json")
	.filter(document("image-upload", requestPartFields("metadata", (1)
			fieldWithPath("version").description("The version of the image")))) (2)
	.when()
	.multiPart("image", new File("image.png"), "image/png")
	.multiPart("metadata", metadata)
	.post("images")
	.then()
	.assertThat()
	.statusCode(is(200));
1Spring REST ドキュメントを構成して、metadata という名前のリクエストパーツのペイロード内のフィールドを説明するスニペットを生成します。PayloadDocumentation で静的 requestPartFields メソッドを使用します。
2 パスが version のフィールドが必要です。org.springframework.restdocs.payload.PayloadDocumentation で静的 fieldWithPath メソッドを使用します。

結果は、パーツのフィールドを説明するテーブルを含むスニペットです。このスニペットの名前は request-part-${part-name}-fields.adoc です。例: metadata という名前のパーツをドキュメント化すると、request-part-metadata-fields.adoc という名前のスニペットが生成されます。

フィールドをドキュメント化する場合、パーツのペイロードにドキュメント化されていないフィールドが見つかった場合、テストは失敗します。同様に、ドキュメント化されたフィールドがパーツのペイロードに見つからず、そのフィールドがオプションとしてマークされていない場合も、テストは失敗します。階層構造を持つペイロードの場合、フィールドをドキュメント化するだけで、そのすべての子孫もドキュメント化されたものとして扱われます。

フィールドをドキュメント化したくない場合は、無視するようにマークできます。そうすることで、上記の失敗を回避しながら、生成されたスニペットに表示されなくなります。

ドキュメント化されていないフィールドがテストの失敗の原因にならない、緩和モードでフィールドをドキュメント化することもできます。これを行うには、org.springframework.restdocs.payload.PayloadDocumentation で relaxedRequestPartFields メソッドを使用します。これは、パーツのペイロードのサブセットのみに注目したい特定のシナリオをドキュメント化する場合に役立ちます。

フィールドの説明、XML を使用するペイロードのドキュメント化などの詳細については、リクエストおよびレスポンスペイロードのドキュメント化に関するセクションを参照してください。

HTTP ヘッダー

requestHeaders と responseHeaders をそれぞれ使用して、リクエストまたはレスポンスのヘッダーをドキュメント化できます。次の例は、その方法を示しています。

MockMvc
this.mockMvc.perform(get("/people").header("Authorization", "Basic dXNlcjpzZWNyZXQ=")) (1)
	.andExpect(status().isOk())
	.andDo(document("headers", requestHeaders((2)
			headerWithName("Authorization").description("Basic auth credentials")), (3)
			responseHeaders((4)
					headerWithName("X-RateLimit-Limit")
						.description("The total number of requests permitted per period"),
					headerWithName("X-RateLimit-Remaining")
						.description("Remaining requests permitted in current period"),
					headerWithName("X-RateLimit-Reset")
						.description("Time at which the rate limit period will reset"))));
1 基本認証を使用する Authorization ヘッダーで GET リクエストを実行します。
2 リクエストのヘッダーを説明するスニペットを生成するように Spring REST Docs を構成します。org.springframework.restdocs.headers.HeaderDocumentation で静的 requestHeaders メソッドを使用します。
3Authorization ヘッダーをドキュメント化します。org.springframework.restdocs.headers.HeaderDocumentation で静的 headerWithName メソッドを使用します。
4 レスポンスのヘッダーを説明するスニペットを作成します。org.springframework.restdocs.headers.HeaderDocumentation で静的 responseHeaders メソッドを使用します。
WebTestClient
this.webTestClient
	.get().uri("/people").header("Authorization", "Basic dXNlcjpzZWNyZXQ=") (1)
	.exchange().expectStatus().isOk().expectBody()
	.consumeWith(document("headers",
		requestHeaders((2)
			headerWithName("Authorization").description("Basic auth credentials")), (3)
		responseHeaders((4)
			headerWithName("X-RateLimit-Limit")
				.description("The total number of requests permitted per period"),
			headerWithName("X-RateLimit-Remaining")
				.description("Remaining requests permitted in current period"),
			headerWithName("X-RateLimit-Reset")
				.description("Time at which the rate limit period will reset"))));
1 基本認証を使用する Authorization ヘッダーで GET リクエストを実行します。
2 リクエストのヘッダーを説明するスニペットを生成するように Spring REST Docs を構成します。org.springframework.restdocs.headers.HeaderDocumentation で静的 requestHeaders メソッドを使用します。
3Authorization ヘッダーをドキュメント化します。org.springframework.restdocs.headers.HeaderDocumentation で静的 headerWithName メソッドを使用します。
4 レスポンスのヘッダーを説明するスニペットを作成します。org.springframework.restdocs.headers.HeaderDocumentation で静的 responseHeaders メソッドを使用します。
REST Assured
RestAssured.given(this.spec)
	.filter(document("headers", requestHeaders((1)
			headerWithName("Authorization").description("Basic auth credentials")), (2)
			responseHeaders((3)
					headerWithName("X-RateLimit-Limit")
						.description("The total number of requests permitted per period"),
					headerWithName("X-RateLimit-Remaining")
						.description("Remaining requests permitted in current period"),
					headerWithName("X-RateLimit-Reset")
						.description("Time at which the rate limit period will reset"))))
	.header("Authorization", "Basic dXNlcjpzZWNyZXQ=") (4)
	.when()
	.get("/people")
	.then()
	.assertThat()
	.statusCode(is(200));
1 リクエストのヘッダーを説明するスニペットを生成するように Spring REST Docs を構成します。org.springframework.restdocs.headers.HeaderDocumentation で静的 requestHeaders メソッドを使用します。
2Authorization ヘッダーをドキュメント化します。` org.springframework.restdocs.headers.HeaderDocumentation で静的 headerWithName メソッドを使用します。
3 レスポンスのヘッダーを説明するスニペットを作成します。org.springframework.restdocs.headers.HeaderDocumentation で静的 responseHeaders メソッドを使用します。
4 基本認証を使用する Authorization ヘッダーでリクエストを構成します。

その結果、request-headers.adoc という名前のスニペットと response-headers.adoc という名前のスニペットが作成されます。それぞれに、ヘッダーを説明する表が含まれています。

HTTP ヘッダーをドキュメント化する場合、ドキュメント化されたヘッダーがリクエストまたはレスポンスで見つからない場合、テストは失敗します。

HTTP クッキー

requestCookies と responseCookies をそれぞれ使用して、リクエストまたはレスポンスで Cookie をドキュメント化できます。次の例は、その方法を示しています。

MockMvc
this.mockMvc.perform(get("/").cookie(new Cookie("JSESSIONID", "ACBCDFD0FF93D5BB"))) (1)
	.andExpect(status().isOk())
	.andDo(document("cookies", requestCookies((2)
			cookieWithName("JSESSIONID").description("Session token")), (3)
			responseCookies((4)
					cookieWithName("JSESSIONID").description("Updated session token"),
					cookieWithName("logged_in")
						.description("Set to true if the user is currently logged in"))));
1JSESSIONID Cookie を使用して GET リクエストを行います。
2 リクエストの Cookie を説明するスニペットを生成するように Spring REST Docs を構成します。org.springframework.restdocs.cookies.CookieDocumentation で静的 requestCookies メソッドを使用します。
3JSESSIONID Cookie をドキュメント化します。org.springframework.restdocs.cookies.CookieDocumentation で静的 cookieWithName メソッドを使用します。
4 レスポンスの Cookie を説明するスニペットを生成します。org.springframework.restdocs.cookies.CookieDocumentation で静的 responseCookies メソッドを使用します。
WebTestClient
this.webTestClient.get()
	.uri("/people")
	.cookie("JSESSIONID", "ACBCDFD0FF93D5BB=") (1)
	.exchange()
	.expectStatus()
	.isOk()
	.expectBody()
	.consumeWith(document("cookies", requestCookies((2)
			cookieWithName("JSESSIONID").description("Session token")), (3)
			responseCookies((4)
					cookieWithName("JSESSIONID").description("Updated session token"),
					cookieWithName("logged_in").description("User is logged in"))));
1JSESSIONID Cookie を使用して GET リクエストを行います。
2 リクエストの Cookie を説明するスニペットを生成するように Spring REST Docs を構成します。org.springframework.restdocs.cookies.CookieDocumentation で静的 requestCookies メソッドを使用します。
3JSESSIONID Cookie をドキュメント化します。org.springframework.restdocs.cookies.CookieDocumentation で静的 cookieWithName メソッドを使用します。
4 レスポンスの Cookie を説明するスニペットを生成します。org.springframework.restdocs.cookies.CookieDocumentation で静的 responseCookies メソッドを使用します。
REST Assured
RestAssured.given(this.spec)
	.filter(document("cookies", requestCookies((1)
			cookieWithName("JSESSIONID").description("Saved session token")), (2)
			responseCookies((3)
					cookieWithName("logged_in").description("If user is logged in"),
					cookieWithName("JSESSIONID").description("Updated session token"))))
	.cookie("JSESSIONID", "ACBCDFD0FF93D5BB") (4)
	.when()
	.get("/people")
	.then()
	.assertThat()
	.statusCode(is(200));
1 リクエストの Cookie を説明するスニペットを生成するように Spring REST Docs を構成します。org.springframework.restdocs.cookies.CookieDocumentation で静的 requestCookies メソッドを使用します。
2JSESSIONID Cookie をドキュメント化します。org.springframework.restdocs.cookies.CookieDocumentation で静的 cookieWithName メソッドを使用します。
3 レスポンスの Cookie を説明するスニペットを生成します。org.springframework.restdocs.cookies.CookieDocumentation で静的 responseCookies メソッドを使用します。
4 リクエストとともに JSESSIONID Cookie を送信します。

その結果、request-cookies.adoc という名前のスニペットと response-cookies.adoc という名前のスニペットが作成されます。それぞれに、Cookie を説明する表が含まれています。

HTTP Cookie をドキュメント化する場合、ドキュメント化されていない Cookie がリクエストまたはレスポンスで見つかった場合、テストは失敗します。同様に、ドキュメント化された Cookie が見つからず、Cookie がオプションとしてマークされていない場合も、テストは失敗します。ドキュメント化されていない Cookie がテストの失敗を引き起こさない緩和モードで Cookie をドキュメント化することもできます。これを行うには、org.springframework.restdocs.cookies.CookieDocumentation で relaxedRequestCookies および relaxedResponseCookies メソッドを使用します。これは、Cookie のサブセットのみに注目したい特定のシナリオをドキュメント化する場合に役立ちます。Cookie を記録したくない場合は、無視するようにマークできます。そうすることで、前述の失敗を回避しながら、生成されたスニペットに表示されなくなります。

スニペットの再利用

ドキュメント化されている API には、そのリソースのいくつかに共通するいくつかの機能があるのが一般的です。このようなリソースをドキュメント化する際の繰り返しを避けるために、共通の要素で構成された Snippet を再利用できます。

まず、共通要素を記述する Snippet を作成します。次の例は、その方法を示しています。

protected final LinksSnippet pagingLinks = links(
		linkWithRel("first").optional().description("The first page of results"),
		linkWithRel("last").optional().description("The last page of results"),
		linkWithRel("next").optional().description("The next page of results"),
		linkWithRel("prev").optional().description("The previous page of results"));

次に、このスニペットを使用して、リソース固有の記述子をさらに追加します。次の例は、その方法を示しています。

MockMvc
this.mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON))
	.andExpect(status().isOk())
	.andDo(document("example", this.pagingLinks.and((1)
			linkWithRel("alpha").description("Link to the alpha resource"),
			linkWithRel("bravo").description("Link to the bravo resource"))));
1pagingLinksSnippet を再利用し、and を呼び出して、ドキュメント化されているリソースに固有の記述子を追加します。
WebTestClient
this.webTestClient.get().uri("/").accept(MediaType.APPLICATION_JSON).exchange()
	.expectStatus().isOk().expectBody()
	.consumeWith(document("example", this.pagingLinks.and((1)
		linkWithRel("alpha").description("Link to the alpha resource"),
		linkWithRel("bravo").description("Link to the bravo resource"))));
1pagingLinksSnippet を再利用し、and を呼び出して、ドキュメント化されているリソースに固有の記述子を追加します。
REST Assured
RestAssured.given(this.spec)
	.accept("application/json")
	.filter(document("example", this.pagingLinks.and((1)
			linkWithRel("alpha").description("Link to the alpha resource"),
			linkWithRel("bravo").description("Link to the bravo resource"))))
	.get("/")
	.then()
	.assertThat()
	.statusCode(is(200));
1pagingLinksSnippet を再利用し、and を呼び出して、ドキュメント化されているリソースに固有の記述子を追加します。

この例の結果は、firstlastnextpreviousalphabravo の rel 値を持つリンクがすべてドキュメント化されていることです。

制約のドキュメント化

Spring REST Docs は、制約をドキュメント化するのに役立つ多くのクラスを提供します。ConstraintDescriptions のインスタンスを使用して、クラスの制約の説明にアクセスできます。次の例は、その方法を示しています。

public void example() {
	ConstraintDescriptions userConstraints = new ConstraintDescriptions(UserInput.class); (1)
	List<String> descriptions = userConstraints.descriptionsForProperty("name"); (2)
}

static class UserInput {

	@NotNull
	@Size(min = 1)
	String name;

	@NotNull
	@Size(min = 8)
	String password;

}
1UserInput クラスの ConstraintDescriptions のインスタンスを作成します。
2name プロパティの制約の説明を取得します。このリストには、NotNull 制約と Size 制約の 2 つの説明が含まれています。

Spring HATEOAS サンプルの ApiDocumentation [GitHub] (英語) クラスは、この機能の動作を示しています。

制約を見つける

デフォルトでは、制約は Bean 検証 Validator を使用して検出されます。現在、プロパティ制約のみがサポートされています。カスタム ValidatorConstraintResolver インスタンスで ConstraintDescriptions を作成することにより、使用される Validator をカスタマイズできます。制約解決を完全に制御するには、独自の ConstraintResolver 実装を使用できます。

制約の記述

すべての Bean 検証 3.0 の制約について、デフォルトの説明が提供されています。

  • AssertFalse

  • AssertTrue

  • DecimalMax

  • DecimalMin

  • Digits

  • Email

  • Future

  • FutureOrPresent

  • Max

  • Min

  • Negative

  • NegativeOrZero

  • NotBlank

  • NotEmpty

  • NotNull

  • Null

  • Past

  • PastOrPresent

  • Pattern

  • Positive

  • PositiveOrZero

  • Size

Hibernate Validator からの次の制約について、デフォルトの説明も提供されます。

  • CodePointLength

  • CreditCardNumber

  • Currency

  • EAN

  • Email

  • Length

  • LuhnCheck

  • Mod10Check

  • Mod11Check

  • NotBlank

  • NotEmpty

  • Currency

  • Range

  • SafeHtml

  • URL

デフォルトの説明をオーバーライドするか、新しい説明を提供するために、ベース名 org.springframework.restdocs.constraints.ConstraintDescriptions でリソースバンドルを作成できます。Spring HATEOAS ベースのサンプルには、このようなリソースバンドルの例 [GitHub] (英語) が含まれています。

リソースバンドル内の各キーは、制約の完全修飾名と .description です。例: 標準の @NotNull 制約のキーは jakarta.validation.constraints.NotNull.description です。

説明で制約の属性を参照するプロパティプレースホルダーを使用できます。例: @Min 制約のデフォルトの説明である Must be at least ${value} は、制約の value 属性を参照しています。

制約記述の解決をより詳細に制御するには、カスタム ResourceBundleConstraintDescriptionResolver を使用して ConstraintDescriptions を作成できます。完全に制御するために、カスタム ConstraintDescriptionResolver 実装で ConstraintDescriptions を作成できます。

生成されたスニペットでの制約の説明の使用

制約の説明ができたら、生成されたスニペットで好きなように自由に使用できます。例: フィールドの説明の一部として制約の説明を含めたい場合があります。または、リクエストフィールドスニペットに追加情報として制約を含めることもできます。Spring HATEOAS ベースのサンプルの ApiDocumentation [GitHub] (英語) クラスは、後者のアプローチを示しています。

デフォルトのスニペット

リクエストとレスポンスをドキュメント化すると、多数のスニペットが自動的に生成されます。

スニペット 説明

curl-request.adoc

ドキュメント化されている MockMvc 呼び出しと同等の curl (英語) コマンドが含まれています。

httpie-request.adoc

ドキュメント化されている MockMvc 呼び出しと同等の HTTPie (英語) コマンドが含まれています。

http-request.adoc

ドキュメント化されている MockMvc 呼び出しと同等の HTTP リクエストが含まれています。

http-response.adoc

返された HTTP レスポンスが含まれます。

request-body.adoc

送信されたリクエストの本文が含まれます。

response-body.adoc

返されたレスポンスの本文が含まれます。

デフォルトで生成されるスニペットを構成できます。詳細については、構成セクションを参照してください。

パラメーター化された出力ディレクトリの使用

document で使用される出力ディレクトリをパラメーター化できます。次のパラメーターがサポートされています。

パラメーター 説明

{methodName}

テストメソッドの変更されていない名前。

{method-name}

kebab-case を使用してフォーマットされたテストメソッドの名前。

{method_name}

snake_case を使用してフォーマットされたテストメソッドの名前。

{ClassName}

テストクラスの変更されていない単純な名前。

{class-name}

kebab-case を使用してフォーマットされた、テストクラスの単純な名前。

{class_name}

snake_case を使用してフォーマットされた、テストクラスの単純な名前。

{step}

現在のテストでサービスに対して行われた呼び出しの数。

例: テストクラス GettingStartedDocumentation の creatingANote という名前のテストメソッド内の document("{class-name}/{method-name}") は、スニペットを getting-started-documentation/creating-a-note という名前のディレクトリに書き込みます。

パラメーター化された出力ディレクトリは、@Before メソッドと組み合わせると特に便利です。セットアップメソッドでドキュメントを一度構成すると、クラス内のすべてのテストで再利用できます。次の例は、その方法を示しています。

MockMvc
@Before
public void setUp() {
	this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
		.apply(documentationConfiguration(this.restDocumentation))
		.alwaysDo(document("{method-name}/{step}/"))
		.build();
}
REST Assured
@Before
public void setUp() {
	this.spec = new RequestSpecBuilder().addFilter(documentationConfiguration(this.restDocumentation))
		.addFilter(document("{method-name}/{step}"))
		.build();
}
WebTestClient
@Before
public void setUp() {
	this.webTestClient = WebTestClient.bindToApplicationContext(this.context)
		.configureClient()
		.filter(documentationConfiguration(this.restDocumentation))
		.entityExchangeResultConsumer(document("{method-name}/{step}"))
		.build();
}

この構成を使用すると、テストしているサービスへのすべての呼び出しで、追加の構成なしで既定のスニペットが生成されます。各サンプルアプリケーションの GettingStartedDocumentation クラスを見て、この機能の動作を確認してください。

出力のカスタマイズ

このセクションでは、Spring REST Docs の出力をカスタマイズする方法について説明します。

生成されたスニペットのカスタマイズ

Spring REST Docs は Mustache (英語) テンプレートを使用して、生成されたスニペットを生成します。デフォルトテンプレート [GitHub] (英語) は、Spring REST Docs が生成できるスニペットごとに提供されます。スニペットのコンテンツをカスタマイズするために、独自のテンプレートを提供できます。

テンプレートは、org.springframework.restdocs.templates サブパッケージのクラスパスからロードされます。サブパッケージの名前は、使用中のテンプレート形式の ID によって決まります。デフォルトのテンプレート形式 Asciidoctor の ID は asciidoctor であるため、スニペットは org.springframework.restdocs.templates.asciidoctor からロードされます。各テンプレートは、それが生成するスニペットにちなんで名付けられています。例: curl-request.adoc スニペットのテンプレートをオーバーライドするには、src/test/resources/org/springframework/restdocs/templates/asciidoctor に curl-request.snippet という名前のテンプレートを作成します。

追加情報を含む

生成されたスニペットに含める追加情報を提供するには、次の 2 つの方法があります。

  • 記述子で attributes メソッドを使用して、1 つ以上の属性を追加します。

  • curlRequesthttpRequesthttpResponse などを呼び出すときに、いくつかの属性を渡します。このような属性は、スニペット全体に関連付けられています。

追加の属性は、テンプレートのレンダリングプロセス中に使用可能になります。カスタムスニペットテンプレートと組み合わせると、生成されたスニペットに追加情報を含めることができます。

具体的な例は、リクエストフィールドをドキュメント化する際の制約列とタイトルの追加です。最初のステップは、ドキュメント化する各フィールドに constraints 属性を提供し、title 属性を提供することです。次の例は、その方法を示しています。

MockMvc
.andDo(document("create-user", requestFields(attributes(key("title").value("Fields for user creation")), (1)
		fieldWithPath("name").description("The user's name")
			.attributes(key("constraints").value("Must not be null. Must not be empty")), (2)
		fieldWithPath("email").description("The user's email address")
			.attributes(key("constraints").value("Must be a valid email address"))))); (3)
1 リクエストフィールドスニペットの title 属性を設定します。
2name フィールドの constraints 属性を設定します。
3email フィールドの constraints 属性を設定します。
WebTestClient
.consumeWith(document("create-user",
	requestFields(
		attributes(key("title").value("Fields for user creation")), (1)
		fieldWithPath("name")
			.description("The user's name")
			.attributes(key("constraints").value("Must not be null. Must not be empty")), (2)
		fieldWithPath("email")
			.description("The user's email address")
			.attributes(key("constraints").value("Must be a valid email address"))))); (3)
1 リクエストフィールドスニペットの title 属性を設定します。
2name フィールドの constraints 属性を設定します。
3email フィールドの constraints 属性を設定します。
REST Assured
.filter(document("create-user", requestFields(attributes(key("title").value("Fields for user creation")), (1)
		fieldWithPath("name").description("The user's name")
			.attributes(key("constraints").value("Must not be null. Must not be empty")), (2)
		fieldWithPath("email").description("The user's email address")
			.attributes(key("constraints").value("Must be a valid email address"))))) (3)
1 リクエストフィールドスニペットの title 属性を設定します。
2name フィールドの constraints 属性を設定します。
3email フィールドの constraints 属性を設定します。

2 番目のステップは、生成されたスニペットのテーブル内のフィールドの制約に関する情報を含み、タイトルを追加する request-fields.snippet という名前のカスタムテンプレートを提供することです。

.{{title}} (1)
|===
|Path|Type|Description|Constraints (2)

{{#fields}}
|{{path}}
|{{type}}
|{{description}}
|{{constraints}} (3)

{{/fields}}
|===
1 表にタイトルを追加します。
2「制約」という名前の新しい列を追加します。
3 テーブルの各行に記述子の constraints 属性を含めます。

リクエストとレスポンスのカスタマイズ

送信されたとおりのリクエストや、受信されたとおりのレスポンスをドキュメント化したくない場合があります。Spring REST Docs は、ドキュメント化される前にリクエストまたはレスポンスを変更するために使用できる多数のプリプロセッサーを提供します。

前処理は、OperationRequestPreprocessor または OperationResponsePreprocessor で document を呼び出すことによって構成されます。Preprocessors で静的 preprocessRequest および preprocessResponse メソッドを使用してインスタンスを取得できます。次の例は、その方法を示しています。

MockMvc
this.mockMvc.perform(get("/"))
	.andExpect(status().isOk())
	.andDo(document("index", preprocessRequest(modifyHeaders().remove("Foo")), (1)
			preprocessResponse(prettyPrint()))); (2)
1Foo という名前のヘッダーを削除するリクエストプリプロセッサーを適用します。
2 コンテンツをきれいに出力するレスポンスプリプロセッサーを適用します。
WebTestClient
this.webTestClient.get().uri("/").exchange().expectStatus().isOk().expectBody()
	.consumeWith(document("index",
		preprocessRequest(modifyHeaders().remove("Foo")), (1)
		preprocessResponse(prettyPrint()))); (2)
1Foo という名前のヘッダーを削除するリクエストプリプロセッサーを適用します。
2 コンテンツをきれいに出力するレスポンスプリプロセッサーを適用します。
REST Assured
RestAssured.given(this.spec)
	.filter(document("index", preprocessRequest(modifyHeaders().remove("Foo")), (1)
			preprocessResponse(prettyPrint()))) (2)
	.when()
	.get("/")
	.then()
	.assertThat()
	.statusCode(is(200));
1Foo という名前のヘッダーを削除するリクエストプリプロセッサーを適用します。
2 コンテンツをきれいに出力するレスポンスプリプロセッサーを適用します。

または、すべてのテストに同じプリプロセッサーを適用することもできます。これを行うには、@Before メソッドで RestDocumentationConfigurer API を使用してプリプロセッサーを構成します。例: すべてのリクエストから Foo ヘッダーを削除し、すべてのレスポンスをきれいに出力するには、次のいずれかを実行できます (テスト環境によって異なります)。

MockMvc
private MockMvc mockMvc;

@Before
public void setup() {
	this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
		.apply(documentationConfiguration(this.restDocumentation).operationPreprocessors()
			.withRequestDefaults(modifyHeaders().remove("Foo")) (1)
			.withResponseDefaults(prettyPrint())) (2)
		.build();
}
1Foo という名前のヘッダーを削除するリクエストプリプロセッサーを適用します。
2 コンテンツをきれいに出力するレスポンスプリプロセッサーを適用します。
WebTestClient
private WebTestClient webTestClient;

@Before
public void setup() {
	this.webTestClient = WebTestClient.bindToApplicationContext(this.context)
		.configureClient()
		.filter(documentationConfiguration(this.restDocumentation)
			.operationPreprocessors()
				.withRequestDefaults(modifyHeaders().remove("Foo")) (1)
				.withResponseDefaults(prettyPrint())) (2)
		.build();
}
1Foo という名前のヘッダーを削除するリクエストプリプロセッサーを適用します。
2 コンテンツをきれいに出力するレスポンスプリプロセッサーを適用します。
REST Assured
private RequestSpecification spec;

@Before
public void setup() {
	this.spec = new RequestSpecBuilder()
		.addFilter(documentationConfiguration(this.restDocumentation).operationPreprocessors()
			.withRequestDefaults(modifyHeaders().remove("Foo")) (1)
			.withResponseDefaults(prettyPrint())) (2)
		.build();
}
1Foo という名前のヘッダーを削除するリクエストプリプロセッサーを適用します。
2 コンテンツをきれいに出力するレスポンスプリプロセッサーを適用します。

次に、各テストで、そのテストに固有の構成を実行できます。次の例は、その方法を示しています。

MockMvc
this.mockMvc.perform(get("/"))
	.andExpect(status().isOk())
	.andDo(document("index", links(linkWithRel("self").description("Canonical self link"))));
WebTestClient
this.webTestClient.get().uri("/").exchange().expectStatus().isOk()
	.expectBody().consumeWith(document("index",
		links(linkWithRel("self").description("Canonical self link"))));
REST Assured
RestAssured.given(this.spec)
	.filter(document("index", links(linkWithRel("self").description("Canonical self link"))))
	.when()
	.get("/")
	.then()
	.assertThat()
	.statusCode(is(200));

上に示したものを含むさまざまな組み込みプリプロセッサーは、Preprocessors の静的メソッドを通じて利用できます。詳細については、以下を参照してください。

プリプロセッサー

プリティー印刷

 Preprocessors 上の prettyPrint は、リクエストまたはレスポンスの内容をフォーマットして、読みやすくします。

ハイパーメディアベースの API をドキュメント化する場合、ハードコーディングされた URI を使用するのではなく、リンクを使用して API をナビゲートするようにクライアントに勧めることができます。そのための 1 つの方法は、ドキュメントでの URI の使用を制限することです。Preprocessors 上の maskLinks は、レスポンス内のすべてのリンクの href を …​ に置き換えます。必要に応じて、別の置換を指定することもできます。

ヘッダーの変更

Preprocessors で modifyHeaders を使用して、リクエストヘッダーまたはレスポンスヘッダーを追加、設定、削除できます。

パターンの置き換え

 Preprocessors 上の replacePattern は、リクエストまたはレスポンスのコンテンツを置き換えるための汎用メカニズムを提供します。正規表現に一致する出現箇所はすべて置き換えられます。

URI の変更

サーバーにバインドされていない MockMvc または WebTestClient を使用する場合は、構成を変更して URI をカスタマイズする必要があります。

Preprocessors で modifyUris を使用して、リクエストまたはレスポンス内の任意の URI を変更できます。サーバーにバインドされた REST Assured または WebTestClient を使用する場合、これにより、サービスのローカルインスタンスをテストしながら、ドキュメントに表示される URI をカスタマイズできます。

独自のプリプロセッサーを作成する

組み込みのプリプロセッサーの 1 つがニーズを満たさない場合は、OperationPreprocessor インターフェースを実装することで独自のプリプロセッサーを作成できます。その後、任意の組み込みプリプロセッサーとまったく同じ方法でカスタムプリプロセッサーを使用できます。

リクエストまたはレスポンスのコンテンツ (本文) のみを変更する場合は、ContentModifier インターフェースを実装し、それを組み込みの ContentModifyingOperationPreprocessor と共に使用することを検討してください。

構成

このセクションでは、Spring REST Docs の構成方法について説明します。

ドキュメント化された URI

このセクションでは、ドキュメント化された URI の構成について説明します。

MockMvc URI のカスタマイズ

MockMvc を使用する場合、Spring REST Docs でドキュメント化されている URI のデフォルト設定は次のとおりです。

設定 デフォルト

スキーム

http

ホスト

localhost

ポート

8080

この構成は MockMvcRestDocumentationConfigurer によって適用されます。その API を使用して、ニーズに合わせて 1 つ以上のデフォルトを変更できます。次の例は、その方法を示しています。

this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
	.apply(documentationConfiguration(this.restDocumentation).uris()
		.withScheme("https")
		.withHost("example.com")
		.withPort(443))
	.build();
ポートが構成されたスキームのデフォルト (HTTP の場合はポート 80、HTTPS の場合はポート 443) に設定されている場合、生成されたスニペットの URI からポートが省略されます。
リクエストのコンテキストパスを設定するには、MockHttpServletRequestBuilder で contextPath メソッドを使用します。

REST 保証 URI のカスタマイズ

REST Assured は、実際の HTTP リクエストを作成してサービスをテストします。そのため、サービスに対する操作が実行されたら、ドキュメント化する前に URI をカスタマイズする必要があります。この目的のために REST-Assured 固有のプリプロセッサーが用意されています。

WebTestClient URI のカスタマイズ

WebTestClient を使用する場合、Spring REST Docs によってドキュメント化された URI のデフォルトのベースは http://localhost:8080 です。このベースは、 WebTestClient.Builder 上の baseUrl(String) メソッド (Javadoc) を使用してカスタマイズできます。次の例は、その方法を示しています。

@Before
public void setUp() {
	this.webTestClient = WebTestClient.bindToApplicationContext(this.context)
		.configureClient()
		.baseUrl("https://api.example.com") (1)
		.filter(documentationConfiguration(this.restDocumentation))
		.build();
}
1 ドキュメント化された URI のベースを https://api.example.com (英語) に設定します。

スニペットのエンコーディング

デフォルトのスニペットエンコーディングは UTF-8 です。RestDocumentationConfigurer API を使用して、デフォルトのスニペットエンコーディングを変更できます。例: 次の例では ISO-8859-1 を使用しています。

MockMvc
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
	.apply(documentationConfiguration(this.restDocumentation).snippets().withEncoding("ISO-8859-1"))
	.build();
WebTestClient
this.webTestClient = WebTestClient.bindToApplicationContext(this.context).configureClient()
	.filter(documentationConfiguration(this.restDocumentation)
		.snippets().withEncoding("ISO-8859-1"))
	.build();
REST Assured
this.spec = new RequestSpecBuilder()
	.addFilter(documentationConfiguration(this.restDocumentation).snippets().withEncoding("ISO-8859-1"))
	.build();
Spring REST Docs がリクエストまたはレスポンスの内容を String に変換するとき、Content-Type ヘッダーで指定された charset が使用可能な場合はそれが使用されます。これがない場合、JVM のデフォルトの Charset が使用されます。file.encoding システムプロパティを使用して、JVM のデフォルト Charset を設定できます。

スニペットテンプレートの形式

デフォルトのスニペットテンプレートの形式は Asciidoctor です。Markdown も標準でサポートされています。RestDocumentationConfigurer API を使用して、デフォルトの形式を変更できます。次の例は、その方法を示しています。

MockMvc
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
	.apply(documentationConfiguration(this.restDocumentation).snippets()
		.withTemplateFormat(TemplateFormats.markdown()))
	.build();
WebTestClient
this.webTestClient = WebTestClient.bindToApplicationContext(this.context).configureClient()
	.filter(documentationConfiguration(this.restDocumentation)
		.snippets().withTemplateFormat(TemplateFormats.markdown()))
	.build();
REST Assured
this.spec = new RequestSpecBuilder()
	.addFilter(documentationConfiguration(this.restDocumentation).snippets()
		.withTemplateFormat(TemplateFormats.markdown()))
	.build();

デフォルトのスニペット

デフォルトでは、6 つのスニペットが生成されます。

  • curl-request

  • http-request

  • http-response

  • httpie-request

  • request-body

  • response-body

RestDocumentationConfigurer API を使用して、セットアップ中にデフォルトのスニペット構成を変更できます。次の例では、デフォルトで curl-request スニペットのみが生成されます。

MockMvc
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
	.apply(documentationConfiguration(this.restDocumentation).snippets().withDefaults(curlRequest()))
	.build();
WebTestClient
this.webTestClient = WebTestClient.bindToApplicationContext(this.context)
	.configureClient().filter(
		documentationConfiguration(this.restDocumentation)
			.snippets().withDefaults(curlRequest()))
	.build();
REST Assured
this.spec = new RequestSpecBuilder()
	.addFilter(documentationConfiguration(this.restDocumentation).snippets().withDefaults(curlRequest()))
	.build();

デフォルトの操作プリプロセッサー

RestDocumentationConfigurer API を使用して、セットアップ中にデフォルトのリクエストおよびレスポンスプリプロセッサーを構成できます。次の例では、すべてのリクエストから Foo ヘッダーを削除し、すべてのレスポンスをきれいに出力します。

MockMvc
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
	.apply(documentationConfiguration(this.restDocumentation).operationPreprocessors()
		.withRequestDefaults(modifyHeaders().remove("Foo")) (1)
		.withResponseDefaults(prettyPrint())) (2)
	.build();
1Foo という名前のヘッダーを削除するリクエストプリプロセッサーを適用します。
2 コンテンツをきれいに出力するレスポンスプリプロセッサーを適用します。
WebTestClient
this.webTestClient = WebTestClient.bindToApplicationContext(this.context)
	.configureClient()
	.filter(documentationConfiguration(this.restDocumentation)
		.operationPreprocessors()
			.withRequestDefaults(modifyHeaders().remove("Foo")) (1)
			.withResponseDefaults(prettyPrint())) (2)
	.build();
1Foo という名前のヘッダーを削除するリクエストプリプロセッサーを適用します。
2 コンテンツをきれいに出力するレスポンスプリプロセッサーを適用します。
REST Assured
this.spec = new RequestSpecBuilder()
	.addFilter(documentationConfiguration(this.restDocumentation).operationPreprocessors()
		.withRequestDefaults(modifyHeaders().remove("Foo")) (1)
		.withResponseDefaults(prettyPrint())) (2)
	.build();
1Foo という名前のヘッダーを削除するリクエストプリプロセッサーを適用します。
2 コンテンツをきれいに出力するレスポンスプリプロセッサーを適用します。

Asciidoctor での作業

このセクションでは、特に Spring REST Docs に関連する Asciidoctor の操作の特徴について説明します。

Asciidoc はドキュメント形式です。Asciidoctor は、Asciidoc ファイル (末尾が .adoc) からコンテンツ (通常は HTML) を生成するツールです。

スニペットを含める

このセクションでは、Asciidoc スニペットを含める方法について説明します。

オペレーションに複数のスニペットを含める

operation という名前のマクロを使用して、特定の操作用に生成されたすべてまたは一部のスニペットをインポートできます。プロジェクトのビルド構成に spring-restdocs-asciidoctor を含めることで利用可能になります。

マクロのターゲットは操作の名前です。最も単純な形式では、次の例に示すように、マクロを使用して操作のすべてのスニペットを含めることができます。

operation::index[]

snippets 属性をサポートする操作マクロも使用できます。含めるスニペットを選択するための snippets 属性。属性の値はカンマ区切りのリストです。リスト内の各エントリは、含めるスニペットファイルの名前 (.adoc サフィックスを除いたもの) にする必要があります。例: 次の例に示すように、curl、HTTP リクエスト、HTTP レスポンススニペットのみを含めることができます。

operation::index[snippets='curl-request,http-request,http-response']

前の例は、次と同等です。

[[example_curl_request]]
== Curl request

include::{snippets}/index/curl-request.adoc[]

[[example_http_request]]
== HTTP request

include::{snippets}/index/http-request.adoc[]

[[example_http_response]]
== HTTP response

include::{snippets}/index/http-response.adoc[]
セクションのタイトル

operation マクロを使用して組み込まれるスニペットごとに、タイトル付きのセクションが作成されます。次の組み込みスニペットには、デフォルトのタイトルが用意されています。

スニペット タイトル

curl-request

Curl リクエスト

http-request

HTTP リクエスト

http-response

HTTP レスポンス

httpie-request

HTTPie リクエスト

links

リンク

request-body

リクエストボディー

request-fields

リクエストフィールド

response-body

レスポンスボディ

response-fields

レスポンスフィールド

上記の表に記載されていないスニペットの場合、- 文字をスペースに置き換え、最初の文字を大文字にすることで、デフォルトのタイトルが生成されます。例: custom-snippetwill be 「カスタムスニペット」という名前のスニペットのタイトル。

ドキュメント属性を使用して、デフォルトのタイトルをカスタマイズできます。属性の名前は operation-{snippet}-title である必要があります。例: curl-request スニペットのタイトルを「サンプルリクエスト」にカスタマイズするには、次の属性を使用できます。

:operation-curl-request-title: Example request

個々のスニペットを含める

インクルードマクロ (英語) は、ドキュメントに個々のスニペットを含めるために使用されます。snippets 属性 ( ビルド構成で構成された spring-restdocs-asciidoctor によって自動的に設定される) を使用して、スニペットの出力ディレクトリを参照できます。次の例は、その方法を示しています。

include::{snippets}/index/curl-request.adoc[]

テーブルのカスタマイズ

スニペットの多くには、デフォルト構成のテーブルが含まれています。テーブルの外観は、スニペットが含まれている場合に追加の構成を提供するか、カスタムスニペットテンプレートを使用してカスタマイズできます。

列のフォーマット

Asciidoctor は、表の列の書式設定 (英語) を豊富にサポートしています。次の例に示すように、cols 属性を使用してテーブルの列の幅を指定できます。

[cols="1,3"] (1)
include::{snippets}/index/links.adoc[]
1 表の幅は 2 つの列に分割され、2 番目の列は最初の列の 3 倍の幅になっています。

タイトルの設定

. を前に付けた行を使用して、テーブルのタイトルを指定できます。次の例は、その方法を示しています。

.Links (1)
include::{snippets}/index/links.adoc[]
1 テーブルのタイトルは Links になります。

表の書式設定の問題を回避する

Asciidoctor は、| 文字を使用してテーブル内のセルを区切ります。これは、| をセルの内容に表示したい場合に問題を引き起こす可能性があります。| をバックスラッシュでエスケープすることで、この問題を回避できます。つまり、| ではなく \| を使用します。

デフォルトの Asciidoctor スニペットテンプレートはすべて、tableCellContent という名前の Mustache ラムバを使用して、このエスケープを自動的に実行します。独自のカスタムテンプレートを作成する場合は、このラムバを使用することをお勧めします。次の例は、description 属性の値を含むセルで | 文字をエスケープする方法を示しています。

| {{#tableCellContent}}{{description}}{{/tableCellContent}}

参考文献

テーブルのカスタマイズの詳細については、Asciidoctor ユーザーマニュアルのテーブルセクション (英語) を参照してください。

Markdown での作業

このセクションでは、特に Spring REST Docs に関連する Markdown の操作の特徴について説明します。

制限

Markdown はもともと、Web 用に作成する人向けに設計されたものであり、Asciidoctor ほどドキュメントを作成するのには適していません。通常、これらの制限は、Markdown 上に構築された別のツールを使用することによって克服されます。

Markdown はテーブルを公式にサポートしていません。Spring REST Docs のデフォルトの Markdown スニペットテンプレートは Markdown Extra のテーブル形式 (英語) を使用します。

スニペットを含める

Markdown には、ある Markdown ファイルを別のファイルに含めるためのサポートが組み込まれていません。生成された Markdown のスニペットをドキュメントに含めるには、この機能をサポートする追加のツールを使用する必要があります。API のドキュメント化に特に適している例の 1 つはスレート [GitHub] (英語) です。

コントリビュートする

Spring REST Docs は、RESTful サービス用の高品質のドキュメントを簡単に作成できるようにすることを目的としています。しかし、皆様の貢献がなければ、そのゴールを達成することはできません。

質問

spring-restdocs タグを使用して、Stack Overflow (英語) で Spring REST Docs に関する質問をすることができます。同様に、質問に答えて仲間の Spring REST Docs ユーザーを手助けすることをお勧めします。

バグ

バグを見つけたと思われる場合は、既存の課題 [GitHub] (英語) を検索してください。誰も課題を報告していない場合は、課題を詳細に説明し、理想的にはそれを再現するテストを含む新しい課題を開いて [GitHub] (英語) ください。

機能強化

Spring REST Docs の機能強化が必要な場合は、プルリクエストを大歓迎します。ソースコードは GitHub (英語) にあります。既存の課題 [GitHub] (英語) プルリクエスト [GitHub] (英語) を検索して、機能強化がすでに提案されているかどうかを確認することをお勧めします。作業を開始する前に、新しい課題 [GitHub] (英語) を開いて、機能強化の可能性について話し合うこともできます。