リクエストとレスポンスのペイロード
前述のハイパーメディア固有のサポートに加えて、リクエストおよびレスポンスペイロードの一般的なドキュメントのサポートも提供されます。
デフォルトでは、Spring REST Docs はリクエストの本文とレスポンスの本文のスニペットを自動的に生成します。これらのスニペットには、それぞれ request-body.adoc および response-body.adoc という名前が付けられます。
リクエストとレスポンスのフィールド
リクエストまたはレスポンスペイロードのより詳細なドキュメントを提供するために、ペイロードのフィールドをドキュメント化するためのサポートが提供されています。
次のペイロードを検討してください。
{
"contact": {
"name": "Jane Doe",
"email": "[email protected] (英語) "
}
}前の例のフィールドを次のようにドキュメント化できます。
MockMvc
WebTestClient
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
class ResponseFields {
// Fields
private MockMvc mockMvc;
@Test
void test() throws Exception {
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)
}
}| 1 | Spring REST ドキュメントを構成して、レスポンスペイロードのフィールドを説明するスニペットを生成します。リクエストをドキュメント化するには、requestFields を使用できます。どちらも org.springframework.restdocs.payload.PayloadDocumentation の静的メソッドです。 |
| 2 | パスが contact.email のフィールドが必要です。org.springframework.restdocs.payload.PayloadDocumentation で静的 fieldWithPath メソッドを使用します。 |
| 3 | パスが contact.name のフィールドが必要です。 |
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.test.web.reactive.server.WebTestClient;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.document;
class ResponseFields {
// Fields
private WebTestClient webTestClient;
@Test
void test() {
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)
}
}| 1 | Spring 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
WebTestClient
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.restdocs.payload.PayloadDocumentation.subsectionWithPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
class Subsection {
// Fields
private MockMvc mockMvc;
@Test
void test() throws Exception {
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 メソッドを使用します。 |
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.test.web.reactive.server.WebTestClient;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.restdocs.payload.PayloadDocumentation.subsectionWithPath;
import static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.document;
class Subsection {
// Fields
private WebTestClient webTestClient;
@Test
void subsection() {
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 メソッドを使用します。 |
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 ペイロードには、次のパスがすべて存在します。
| パス | 値 |
|---|---|
|
|
| 3 つのオブジェクトを含む配列 |
| 3 つのオブジェクトを含む配列 |
| 3 つのオブジェクトを含む配列 |
| 3 つのオブジェクトを含む配列 |
| 3 つのオブジェクトを含む配列 |
| 文字列 |
| 文字列 |
| 文字列 |
| 文字列 |
ルートで配列を使用するペイロードをドキュメント化することもできます。パス [] は配列全体を指します。次に、括弧 またはドット表記を使用して、配列のエントリ内のフィールドを識別できます。例: [].id は、次の配列で見つかったすべてのオブジェクトの id フィールドに対応します。
[
{
"id":1
},
{
"id":2
}
]* をワイルドカードとして使用して、異なる名前のフィールドに一致させることができます。例: users.*.role を使用して、次の JSON ですべてのユーザーのロールをドキュメント化できます。
{
"users":{
"ab12cd34":{
"role": "Administrator"
},
"12ab34cd":{
"role": "Guest"
}
}
}JSON フィールドの種類
フィールドがドキュメント化されると、Spring REST Docs はペイロードを調べてその型を判別しようとします。7 つの異なる型がサポートされています。
| タイプ | 説明 |
|---|---|
| フィールドの各出現箇所の値は配列です。 |
| フィールドの各出現箇所の値はブール値 ( |
| フィールドの各出現箇所の値はオブジェクトです。 |
| フィールドの各出現箇所の値は数値です。 |
| フィールドの各出現箇所の値は |
| フィールドの各出現箇所の値は文字列です。 |
| このフィールドは、さまざまな型のペイロードで複数回発生します。 |
FieldDescriptor で type(Object) メソッドを使用して、型を明示的に設定することもできます。提供された Object の toString メソッドの結果は、ドキュメントで使用されます。通常、JsonFieldType によって列挙された値の 1 つが使用されます。次の例は、その方法を示しています。
MockMvc
WebTestClient
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.restdocs.payload.JsonFieldType;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
class ExplicitFieldType {
// Fields
private MockMvc mockMvc;
@Test
void test() throws Exception {
this.mockMvc.perform(get("/user/5").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(document("index", responseFields(fieldWithPath("contact.email").type(JsonFieldType.STRING) (1)
.description("The user's email address"))));
}
}| 1 | フィールドの型を String に設定します。 |
import org.springframework.http.MediaType;
import org.springframework.restdocs.payload.JsonFieldType;
import org.springframework.test.web.reactive.server.WebTestClient;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.document;
class ExplicitFieldType {
// Fields
private WebTestClient webTestClient;
void test() {
this.webTestClient.get()
.uri("user/5")
.accept(MediaType.APPLICATION_JSON)
.exchange()
.expectStatus()
.isOk()
.expectBody()
.consumeWith(document("user", responseFields(fieldWithPath("contact.email").type(JsonFieldType.STRING) (1)
.description("The user's email address"))));
}
}| 1 | フィールドの型を String に設定します。 |
フィールド記述子の再利用
スニペットの再利用の一般的なサポートに加えて、リクエストスニペットとレスポンススニペットでは、パスプレフィックスを使用して追加の記述子を構成できます。これにより、リクエストまたはレスポンスペイロードの繰り返し部分の記述子を一度作成してから再利用できます。
本を返すエンドポイントを考えてみましょう:
{
"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 です。単一のブックとブックの配列の唯一の違いは、フィールドのパスに []. プレフィックスが付いていることです。
ブックをドキュメント化する記述子は、次のように作成できます。
import org.springframework.restdocs.payload.FieldDescriptor;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
public final class BookPayload {
private BookPayload() {
}
public static FieldDescriptor[] bookDescription() {
return new FieldDescriptor[] { fieldWithPath("title").description("Title of the book"),
fieldWithPath("author").description("Author of the book") };
}
}次に、使用して、次のように 1 つのブックをドキュメント化できます。
MockMvc
WebTestClient
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.restdocs.docs.documentingyourapi.requestresponsepayloads.fields.reusingfielddescriptors.BookPayload;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
class DescriptorReuse {
// Fields
private MockMvc mockMvc;
@Test
void test() throws Exception {
this.mockMvc.perform(get("/books/1").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(document("book", responseFields(BookPayload.bookDescription()))); (1)
}
}| 1 | 既存の記述子を使用して title と author をドキュメント化する |
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.restdocs.docs.documentingyourapi.requestresponsepayloads.fields.reusingfielddescriptors.BookPayload;
import org.springframework.test.web.reactive.server.WebTestClient;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.document;
class DescriptorReuse {
// Fields
private WebTestClient webTestClient;
@Test
void test() {
this.webTestClient.get()
.uri("/books/1")
.accept(MediaType.APPLICATION_JSON)
.exchange()
.expectStatus()
.isOk()
.expectBody()
.consumeWith(document("book", responseFields(BookPayload.bookDescription()))); (1)
}
}| 1 | 既存の記述子を使用して title と author をドキュメント化する |
次のように、記述子を使用して書籍の配列をドキュメント化することもできます。
MockMvc
WebTestClient
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.restdocs.docs.documentingyourapi.requestresponsepayloads.fields.reusingfielddescriptors.BookPayload;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
class ArrayDescriptorReuse {
// Fields
private MockMvc mockMvc;
@Test
void test() throws Exception {
this.mockMvc.perform(get("/books").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(document("book", responseFields(fieldWithPath("[]").description("An array of books")) (1)
.andWithPrefix("[].", BookPayload.bookDescription()))); (2)
}
}| 1 | 配列をドキュメント化します。 |
| 2 | []. で始まる既存の記述子を使用して、[].title および [].author をドキュメント化します。 |
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.restdocs.docs.documentingyourapi.requestresponsepayloads.fields.reusingfielddescriptors.BookPayload;
import org.springframework.test.web.reactive.server.WebTestClient;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.document;
class ArrayDescriptorReuse {
// Fields
private WebTestClient webTestClient;
@Test
void test() {
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("[].", BookPayload.bookDescription()))); (2)
}
}| 1 | 配列をドキュメント化します。 |
| 2 | []. で始まる既存の記述子を使用して、[].title および [].author をドキュメント化します。 |
リクエストまたはレスポンスペイロードのサブセクションのドキュメント化
ペイロードが大きい場合や構造的に複雑な場合は、ペイロードの個々のセクションをドキュメント化すると便利です。REST ドキュメントを使用すると、ペイロードのサブセクションを抽出してドキュメント化することで、これを行うことができます。
リクエストまたはレスポンス本文のサブセクションのドキュメント化
次の JSON レスポンス本文を検討してください。
{
"weather": {
"wind": {
"speed": 15.3,
"direction": 287.0
},
"temperature": {
"high": 21.2,
"low": 14.8
}
}
} 次のように、temperature オブジェクトをドキュメント化するスニペットを作成できます。
MockMvc
WebTestClient
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.payload.PayloadDocumentation.beneathPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseBody;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
public class BodySubsection {
// Fields
private MockMvc mockMvc;
@Test
void test() throws Exception {
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 を使用できます。 |
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.test.web.reactive.server.WebTestClient;
import static org.springframework.restdocs.payload.PayloadDocumentation.beneathPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseBody;
import static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.document;
class BodySubsection {
// Fields
private WebTestClient webTestClient;
@Test
void test() {
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 を使用できます。 |
結果は、次の内容のスニペットです。
{
"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
WebTestClient
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.payload.PayloadDocumentation.beneathPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
class FieldsSubsection {
// Fields
private MockMvc mockMvc;
@Test
void test() throws Exception {
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 メソッドを使用します。 |
| 2 | high および low フィールドをドキュメント化します。 |
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.test.web.reactive.server.WebTestClient;
import static org.springframework.restdocs.payload.PayloadDocumentation.beneathPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.document;
class FieldsSubsection {
// Fields
private WebTestClient webTestClient;
@Test
void test() {
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 メソッドを使用します。 |
| 2 | high および low フィールドをドキュメント化します。 |
結果は、weather.temperature の high および low フィールドを説明するテーブルを含むスニペットです。スニペットの名前を区別するために、サブセクションの識別子が含まれています。デフォルトでは、この識別子は beneath-${path} です。例: 上記のコードは、response-fields-beneath-weather.temperature.adoc という名前のスニペットになります。