Spring RESTドキュメントの紹介

1概要

Spring REST Docs は、正確で読みやすいRESTfulサービスのドキュメントを生成します。

手書きのドキュメントと、Springテストで作成された自動生成されたドキュメントスニペットを組み合わせたものです。

2メリット

プロジェクトの背後にある1つの主要な哲学は、ドキュメントを作成するためのテストの使用です。これにより、生成されたドキュメントが常にAPIの実際の動作と正確に一致するようになります。さらに、出力は、AsciiDoc構文を中心とした発行ツールチェーンであるhttp://asciidoctor.org/[Asciidoctor]によって処理される準備ができています。これはSpring Frameworkのドキュメントを生成するために使用されるのと同じツールです。

これらのアプローチは他のフレームワークによって課される制限を減らします。

Spring REST Docsは、正確、簡潔、そして構造化された文書を作成します。このドキュメンテーションによって、Webサービスの利用者は必要な情報を最小限の手間で取得できます。

このツールには他にも次のような利点があります。

  • curlとhttpリクエストの断片が生成される

  • プロジェクトのjarファイルにドキュメントを簡単にパッケージ化

スニペットに追加情報を追加するのが簡単

  • JSONとXMLの両方をサポート

スニペットを生成するテストは、Spring MVC Testサポート、Spring Webfluxの WebTestClient 、またはREST-Assuredのいずれかを使って書くことができます。

この例では、Spring MVCテストを使用しますが、他のフレームワークの使用方法も非常に似ています。

3依存関係

プロジェクトでSpring RESTドキュメントを使い始めるための理想的な方法は、依存関係管理システムを使うことです。ここでは、Mavenをビルドツールとして使用しているので、以下の依存関係をコピーしてPOMに貼り付けることができます。

<dependency>
    <groupId>org.springframework.restdocs</groupId>
    <artifactId>spring-restdocs-mockmvc</artifactId>
    <version>2.0.0.RELEASE</version>
</dependency>

また、依存関係の新しいバージョンについてMaven Centralを確認することもできます。 22spring-restdocs-mockmvc%22[ここ]。

この例では、Spring MVCテストサポートを使用してテストを作成しているので、 spring-restdocs-mockmvc 依存関係が必要です。

WebTestClientまたはREST Assuredを使ってテストを書きたい場合は、https://search.maven.org/classic/#search%7Cga%7C1%7Ca%3A%22spring-restdocs-webtestclient%22[spring-が必要です。 restdocs-webtestclient]とhttps://search.maven.org/classic/#search%7Cga%7C1%7Ca%3A%22spring-restdocs-restassured%22[spring-restdocs-restassured]の依存関係。

4構成

前述したように、文書化されるRESTサービスに対してリクエストを行うためにSpring MVC Testフレームワークを使用します。テストを実行すると、リクエストと結果のレスポンスに関するドキュメントスニペットが生成されます。

このライブラリはJUnit 4とJUnit 5の両方のテストで使用できます。それぞれに必要な設定を見てみましょう。

4.1. JUnit 4の設定

JUnit 4テスト用のドキュメントスニペットを生成する最初のステップは、 JUnit @ Rule としてアノテーションが付けられたpublic JUnitRestDocumentation フィールドを宣言することです。

JUnitRestDocumentation ルールは、生成されたスニペットが保存されるべき出力ディレクトリで設定されます。たとえば、このディレクトリはMavenのビルドアウトディレクトリにすることができます。

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

次に、 MockMvc コンテキストを設定してドキュメントを生成するように設定します。

@Autowired
private WebApplicationContext context;

private MockMvc mockMvc;

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

MockMvc オブジェクトはMockMvc __RestDocumentationConfigurer を使用して設定されます。このクラスのインスタンスは、 org.springframework.restdocs.mockmvc.MockMvcRestDocumentation のstatic documentationConfiguration()__メソッドから取得できます。

4.2. JUnit 5の設定

  • JUnit 5のテストで作業するには、 RestDocumentationExtension クラスでテストを拡張する必要があります。

@ExtendWith({RestDocumentationExtension.class, SpringExtension.class})
@SpringBootTest
public class ApiDocumentationJUnit5IntegrationTest {//... }

このクラスは、Mavenを使用する場合は /target/generated-snippets 出力ディレクトリ、Gradleの場合は /build/generate-snippets を使用して自動的に構成されます。

次に、 @ BeforeEach メソッドで MockMvc インスタンスを設定する必要があります。

@BeforeEach
public void setUp(WebApplicationContext webApplicationContext,
  RestDocumentationContextProvider restDocumentation) {
    this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
      .apply(documentationConfiguration(restDocumentation)).build();
}
  • テストにJUnitを使用していない場合は、 ManualRestDocumentation クラスを使用する必要があります。**

5 RESTfulサービス

文書化できるCRUD RESTfulサービスを作成しましょう。

@RestController
@RequestMapping("/crud")
public class CRUDController {

    @GetMapping
    public List<CrudInput> read(@RequestBody CrudInput crudInput) {
        List<CrudInput> returnList = new ArrayList<CrudInput>();
        returnList.add(crudInput);
        return returnList;
    }

    @ResponseStatus(HttpStatus.CREATED)
    @PostMapping
    public HttpHeaders save(@RequestBody CrudInput crudInput) {
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setLocation(
          linkTo(CRUDController.class).slash(crudInput.getTitle()).toUri());
        return httpHeaders;
    }

    @DeleteMapping("/{id}")
    public void delete(@PathVariable("id") long id) {
       //delete
    }
}

次に、 CRUDController ベースエンドポイントへのリンクを含むページを返す IndexController を追加しましょう。

@RestController
public class IndexController {

    @GetMapping("/")
    public ResourceSupport index() {
        ResourceSupport index = new ResourceSupport();
        index.add(linkTo(CRUDController.class).withRel("crud"));
        return index;
    }
}

6. JUnitテスト

テストに戻り、 MockMvc インスタンスを使用してサービスを呼び出し、要求と応答を文書化します。

まず、** すべての MockMvc 呼び出しが他の設定なしで自動的に文書化されるようにするために、 alwaysDo() メソッドを使用できます。

this.mockMvc = MockMvcBuilders
 //...
  .alwaysDo(document("{method-name}",
    preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint())))
  .build();

この設定により、すべての MockMvc 呼び出しについて、デフォルトのスニペットがテストメソッドの名前の付いたフォルダーに作成されます。また、 prettyPrint() プリプロセッサを適用すると、スニペットが読みやすくなります。

電話のカスタマイズを続けましょう。

  • リンクを含むインデックスページを文書化するために、静的な links() メソッドを使うことができます。

@Test
public void indexExample() throws Exception {
    this.mockMvc.perform(get("/")).andExpect(status().isOk())
      .andDo(document("index",
        links(linkWithRel("crud").description("The CRUD resource")),
        responseFields(subsectionWithPath("__links")
          .description("Links to other resources"))
        responseHeaders(headerWithName("Content-Type")
          .description("The Content-Type of the payload"))));
}

ここでは、 linkWithRel()メソッドを使用して /crud.__へのリンクを文書化しています。

Content-Type ヘッダーをレスポンスに追加するには、 headerWithName() メソッドを使用してそれをドキュメント化し、それを responseHeaders() メソッドに追加します。

  • また、 responseFields() メソッドを使用してレスポンスペイロードをドキュメント化しています** subsectionWithPath()またはfieldWithPath()メソッドを使用してレスポンスのより複雑なサブセクションまたは単一フィールドをドキュメント化するために使用できます。

応答ペイロードと同様に、__requestPayload()を使用して要求ペイロードを文書化することもできます。

@Test
public void crudCreateExample() throws Exception {
    Map<String, Object> crud = new HashMap<>();
    crud.put("title", "Sample Model");
    crud.put("body", "http://www.baeldung.com/");

    this.mockMvc.perform(post("/crud").contentType(MediaTypes.HAL__JSON)
      .content(this.objectMapper.writeValueAsString(crud)))
      .andExpect(status().isCreated())
      .andDo(document("create-crud-example",
        requestFields(fieldWithPath("id").description("The id of the input"),
          fieldWithPath("title").description("The title of the input"),
          fieldWithPath("body").description("The body of the input"),
        ))));
}

この例では、titleフィールドとbodyフィールドを含む CrudInput モデルを受け取り、CREATEDステータスを送信するPOSTリクエストを文書化しました。

  • 各フィールドは fieldWithPath() メソッドを使って文書化されています。

  • リクエストとパスのパラメータを文書化するために、 requestParameters() pathParameters() メソッドを使用することができます。

@Test
public void crudDeleteExample() throws Exception {
    this.mockMvc.perform(delete("/crud/{id}", 10)).andExpect(status().isOk())
      .andDo(document("crud-delete-example",
      pathParameters(
        parameterWithName("id").description("The id of the input to delete")
      )));
}

ここでは、 id pathパラメータを受け取る削除エンドポイントについて説明しました。

Spring REST Docsプロジェクトには、https://docs.spring.io/spring-restdocs/docs/current/reference/html5/[documentation]にあるフィールド制約や要求部分など、さらに強力な文書機能が含まれています。 。

7. 出力

ビルドが正常に実行されると、RESTドキュメントのスニペットの出力が生成され、 target/generated-snippets フォルダーに保存されます。

リンク:/uploads/Screen-Shot-2016-04-04-at-11.48.52-PM-300x270.png[]

生成された出力には、サービスに関する情報、「curl」呼び出しなどのRESTサービスの呼び出し方法、RESTサービスからのHTTP要求と応答、およびサービスへのリンク/エンドポイントが含まれます。

<strong> CURLコマンド</strong>

$ curl 'http://localhost:8080/' -i


<strong> HTTP - RESTレスポンス</strong>

----[source,http,options="nowrap"]----

HTTP/1.1 200 OKコンテンツタイプ:application/hal json;文字セット= UTF-8コンテンツ長:93

{   "__links":{     "crud":{       "href": "http://localhost:8080/crud"     }   } }


8スニペットを使用してドキュメントを作成する

より大きなドキュメントでスニペットを使用するには、Asciidoc includes. を使用してそれらを参照できます。ここでは api-guide.adoc という名前のドキュメントを src/docs に作成しました。

その文書で、リンクスニペットを参照したい場合は、文書を処理するときにMavenに置き換えられるプレースホルダー \ {snippets} を使用して含めることができます。

==== Links

include::{snippets}/index-example/links.adoc[]----

[[asciidocs]]

===  **  9 Asciidocs Mavenプラグイン**

APIガイドをAsciidocから読みやすい形式に変換するために、ビルドライフサイクルにMavenプラグインを追加できます。これを有効にするにはいくつかの手順があります。

.  Asciidoctorプラグインを__pom.xml__に適用します.

.  __testCompile__に__spring-restdocs-mockmvc__への依存関係を追加します.

依存関係セクションに記載されている構成
。生成する出力場所を定義するためのプロパティを設定します。

スニペット
。スニペットディレクトリを出力として追加するように__test__タスクを設定します。

.  __asciidoctor__タスクを設定します

. 含めるときに使用できる__snippets__という名前の属性を定義します.

あなたのドキュメントで生成されたスニペット
。テストが実行されるようにタスクを__test__タスクに依存させる

ドキュメントが作成される前
。 __snippets__ディレクトリを入力として設定します。生成されたすべて

このディレクトリの下にスニペットが作成されます

Aspidoctorプラグインがこのパスを使用してこのフォルダーの下にスニペットを生成できるように、スニペットディレクトリを__pom.xml__ ** ** のプロパティとして追加します。

[source,xml,gutter:,true]

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

ビルドからAsciidocスニペットを生成するための__pom.xml__内のMavenプラグイン構成は以下のとおりです。

[source,xml,gutter:,true]

<plugin> <groupId>org.asciidoctor</groupId> <artifactId>asciidoctor-maven-plugin</artifactId> <version>1.5.6</version> <executions> <execution> <id>generate-docs</id> <phase>package</phase> <goals> <goal>process-asciidoc</goal> </goals> <configuration> <backend>html</backend> <doctype>book</doctype> <attributes> <snippets>${snippetsDirectory}</snippets> </attributes> <sourceDirectory>src/docs/asciidocs</sourceDirectory> <outputDirectory>target/generated-docs</outputDirectory> </configuration> </execution> </executions> </plugin>

[[generation]]

===  **  10 APIドキュメント生成プロセス**

Mavenビルドが実行されテストが実行されると、設定された__target/generated-snippets__ディレクトリの下のsnippetsフォルダーにすべてのスニペットが生成されます。スニペットが生成されると、ビルドプロセスはHTML出力を生成します。

リンク:/uploads/Screen-Shot-2016-05-08-at-11.32.25-PM.png[]

生成されたHTMLファイルはフォーマットされていて読み取り可能なので、REST文書はすぐに使用できます。 Mavenビルドが実行されるたびに、ドキュメントも最新のアップデートで生成されます。

リンク:/uploads/docs-768x527.png%20768w[]

===  **  11結論**

ドキュメントがないことは間違ったドキュメントよりも優れていますが、Spring RESTドキュメントはRESTfulサービスの正確なドキュメントを生成するのに役立ちます。

公式のSpringプロジェクトとして、Spring MVC Test、WebTestClient、およびREST Assuredの3つのテストライブラリを使用して目的を達成しています。このような文書生成方法は、RESTful APIの開発および文書化に対するテスト主導のアプローチを支援するのに役立ちます。

https://github.com/eugenp/tutorials/tree/master/spring-5[リンクされたGitHubレポジトリ]で、この記事のコードに基づいたサンプルプロジェクトを見つけることができます。