Spring RESTドキュメントの紹介

Spring RESTドキュメントの概要

1. 概要

Spring REST Docsは、正確で読みやすいRESTfulサービスのドキュメントを生成します。 手書きのドキュメントと、Springテストで生成された自動生成されたドキュメントスニペットを組み合わせます。

2. 利点

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

これらのアプローチは、他のフレームワークによって課される制限を軽減します。 Spring REST Docsは、正確で簡潔で適切に構造化されたドキュメントを作成します。 このドキュメントにより、Webサービスの消費者は必要な情報を最小限の手間で取得できます。

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

  • curlおよびhttpリクエストスニペットが生成されます

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

  • スニペットに簡単に追加情報を追加できます

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

スニペットを生成するテストは、Spring MVCテストサポート、Spring WebfluxのWebTestClient、またはREST-Assuredのいずれかを使用して記述できます。

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

3. 依存関係

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


    org.springframework.restdocs
    spring-restdocs-mockmvc
    2.0.0.RELEASE

Maven Centralで依存関係hereの新しいバージョンを確認することもできます。

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

WebTestClientまたはRESTAssuredを使用してテストを作成する場合は、spring-restdocs-webtestclientspring-restdocs-restassuredの依存関係が必要になります。

4. 設定

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

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

4.1. JUnit4構成

JUnit 4テストのドキュメントスニペットを生成する最初のステップは、declare a public JUnitRestDocumentation field that is annotated as a JUnit @Ruleです。

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オブジェクトは、MockMvcRestDocumentationConfigurerを使用して構成されます。 このクラスのインスタンスは、org.springframework.restdocs.mockmvc.MockMvcRestDocumentationの静的documentationConfiguration()メソッドから取得できます。

4.2. JUnit5構成

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サービス

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

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

    @GetMapping
    public List read(@RequestBody CrudInput crudInput) {
        List returnList = new ArrayList();
        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インスタンスを使用してサービスを呼び出し、要求と応答を文書化できます。

まず、to make sure every MockMvc call is automatically documented without any further configuration we can use the alwaysDo() method

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()メソッドに追加します。

We’re also documenting the response payload using the responseFields() method.これは、subsectionWithPath()またはfieldWithPath()メソッドを使用して、応答のより複雑なサブセクションまたは単一のフィールドを文書化するために使用できます。

応答ペイロードと同様に、we can also document the request payload using requestPayload():

@Test
public void crudCreateExample() throws Exception {
    Map crud = new HashMap<>();
    crud.put("title", "Sample Model");
    crud.put("body", "http://www.example.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"),
        ))));
}

この例では、タイトルフィールドと本文フィールドを持つCrudInputモデルを受信し、CREATEDステータスを送信するPOSTリクエストを文書化しました。 Each field is documented using the fieldWithPath() method.

To document request and path parameter, we can use the requestParameters() and pathParameters() methods.どちらの方法も、parameterWithName()メソッドを使用して各パラメーターを記述します。

@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パスパラメータを受け取る削除エンドポイントについて説明しました。

Spring REST Docsプロジェクトには、フィールド制約やdocumentationにあるリクエストパーツなど、さらに強力なドキュメント機能が含まれています。

7. 出力

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

Screen Shot 2016-04-04 at 11.48.52 PM

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

CURLコマンド

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


HTTP – RESTレスポンス

[source,http,options="nowrap"]

HTTP/1.1 200 OK Content-Type: application/hal+json;charset=UTF-8 Content-Length: 93

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


8. スニペットを使用したドキュメントの作成

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

Screen Shot 2016-05-01 at 8.51.48 PM

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

==== Links

Unresolved directive in spring-rest-docs.adoc - include::{snippets}/index-example/links.adoc[]

9. AsciidocsMavenプラグイン

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

  1. Asciidoctorプラグインをpom.xmlに適用します

  2. 依存関係のセクションで説明されているように、testCompile構成のspring-restdocs-mockmvcへの依存関係を追加します

  3. 生成されたスニペットの出力場所を定義するプロパティを構成します

  4. testタスクを構成して、スニペットディレクトリを出力として追加します

  5. asciidoctorタスクを構成します

  6. 生成されたスニペットをドキュメントに含めるときに使用できるsnippetsという名前の属性を定義します

  7. ドキュメントが作成される前にテストが実行されるように、タスクをtestタスクに依存させます

  8. snippetsディレクトリを入力として設定します。 生成されたすべてのスニペットは、このディレクトリの下に作成されます

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


    ${project.build.directory}/generated-snippets

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


    org.asciidoctor
    asciidoctor-maven-plugin
    1.5.6
    
        
            generate-docs
            package
            
                process-asciidoc
            
            
                html
                book
                
                    ${snippetsDirectory}
                
                src/docs/asciidocs
                target/generated-docs
             
     
    

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

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

Screen Shot 2016-05-08 at 11.32.25 PM

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

image

11. 結論

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

Springの公式プロジェクトとして、Spring MVC Test、WebTestClient、RESTAssuredの3つのテストライブラリを使用して目標を達成します。 ドキュメントを生成するこの方法は、RESTful APIの開発とドキュメント化のためのテスト駆動型アプローチのサポートに役立ちます。

この記事のコードに基づくサンプルプロジェクトは、linked GitHub repositoryにあります。