Spring Rest Docs를 Gradle에 추가한다.

plugins, configurations, dependencies에 각각 작성한다.

plugins {
        ...
    id 'org.asciidoctor.jvm.convert' version '3.3.2'
}

...
    
configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
    asciidoctorExt
}

...
    
dependencies {
    //rest docs
    asciidoctorExt 'org.springframework.restdocs:spring-restdocs-asciidoctor'
    testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
}

그리고 asciidoctor를 사용하기 위한 task를 작성한다. asciidoctor은 문서 모델로 구문을 분석해서 HTML형식으로 출력해주는 일종의 텍스트 처리기이다.

//rest docs
ext {
    set('snippetsDir', file("build/generated-snippets"))
}

asciidoctor {
    dependsOn test
    inputs.dir snippetsDir
}


tasks.named('test') {
    outputs.dir snippetsDir
    useJUnitPlatform()
}

tasks.named('asciidoctor') {
    inputs.dir snippetsDir
    dependsOn test
}


test {
    outputs.dir snippetsDir
}

asciidoctor {
    configurations 'asciidoctorExt'
    baseDirFollowsSourceFile()
    inputs.dir snippetsDir
    dependsOn test
}

asciidoctor.doFirst {
    delete file('src/main/resources/static/docs')
}

task copyDocument(type: Copy) {
    dependsOn asciidoctor
    from file("build/docs/asciidoc")
    into file("src/main/resources/static/docs")
}

build {
    dependsOn copyDocument
}

이것으로 설정 작업은 끝이 났고, 실제 테스트 코딩을 작성해 보자.

    @DisplayName("Save item")
    @Test
    void testSaveItem() throws Exception {
        //given
        ItemRequestDto requestDto = ItemRequestDto.builder()
                .itemName("testItem")
                .itemType(ItemType.FOOD)
                .price(10L)
                .build();

        //when
        ResultActions result = mockMvc.perform(post(prefixUrl)
                .contextPath(contextPath)
                .contentType(MediaType.APPLICATION_JSON)
                .header(testToken.AUTHORIZATION,
                        String.format("%s%s", testToken.BEARER, getAccessToken()))
                .content(objectMapper.writeValueAsString(requestDto)));

        //then
        result.andExpect(status().isOk())
                .andExpect(jsonPath("$.itemName").value("testItem"))
                .andReturn();

        //docs
        result.andDo(document("save-item",
                preprocessRequest(prettyPrint()),
                preprocessResponse(prettyPrint()),
                requestFields(
                        fieldWithPath("itemName").description("ITEM NAME"),
                        fieldWithPath("itemType").description("ITEM TYPE(FOOD, BOOK, CLOTHES"),
                        fieldWithPath("price").description("ITEM PRICE")
                ),
                responseFields(
                        fieldWithPath("id").description("ID"),
                        fieldWithPath("itemName").description("ITEM NAME"),
                        fieldWithPath("itemType").description("ITEM TYPE(FOOD, BOOK, CLOTHES"),
                        fieldWithPath("price").description("ITEM PRICE")
                )
        ));

    }

아이템을 저장하는 테스트 코드이다. given > when > then 에 이어서 docs에서 Spring Rest Docs를 작업을 처리하는 것이다. 이름에서 알수 있듯이 requestFields에 전달 하는 파라미터를 정의하고 responseFields에 리턴되는 값을 정의하면 된다.

다음은 AsciiDoc를 작성해 보자.

saveItem를 지정해서 adoc파일(AsciiDoc로 만들어진 파일)을 저장할 경로를 지정한다. 그렇게 하면 빌드할때 해당 파일이 생성된다. 먼저 src/doc/asiidoc 라는 디렉토리를 생성한다. 여기에서 index.adoc를 만들어준다. 이 파일에서 각 adocs파일을 취합하도록 한다.

만약 Intelij를 사용한다면 AsciiDoc이라는 플러그인을 설치하면 adoc파일을 작성 및 미리보기 기능이 제공된다.

아래는 작성한 index.adoc 파일이다

= TEST API
notification-api-docs
:doctype: book
:icons: font
:source-highlighter: highlightjs
:toc: left
:toclevels: 4
:sectlinks:

ifndef::snippets[]
:snippets: ./build/generated-snippets
endif::[]

include::Member-API.adoc[]
include::Item-API.adoc[]
include::Order-API.adoc[]

include에 각 adoc파일을 만든다. 여기서는 Member관련 API, Item 관련 API, Order 관련 API에 대한 각각의 adoc파일을 include해준다.

예제로 Item 관련 API가 정의된 Item-API.adoc를 만든다.

== Item-API

=== Save-Item

==== Request Sample
include::{snippets}/save-item/http-request.adoc[]

==== Request Field
include::{snippets}/save-item/request-fields.adoc[]

==== Response Sample
include::{snippets}/save-item/http-response.adoc[]

==== Response Fields
include::{snippets}/save-item/response-fields.adoc[]



=== Update-Item

==== Request Sample
include::{snippets}/update-item/http-request.adoc[]

==== Request Field
include::{snippets}/update-item/request-fields.adoc[]

==== Response Sample
include::{snippets}/update-item/http-response.adoc[]

==== Response Fields
include::{snippets}/update-item/response-fields.adoc[]


=== View-Item

==== Request Sample
include::{snippets}/get-item/http-request.adoc[]

==== Request Field
include::{snippets}/get-item/path-parameters.adoc[]

==== Response Sample
include::{snippets}/get-item/http-response.adoc[]

==== Response Fields
include::{snippets}/get-item/response-fields.adoc[]


=== List-Item

==== Request Sample
include::{snippets}/list-item/http-request.adoc[]

==== Request Field
include::{snippets}/list-item/query-parameters.adoc[]

==== Response Sample
include::{snippets}/list-item/http-response.adoc[]

==== Response Fields
include::{snippets}/list-item/response-fields.adoc[]

Item에 필요한 Save-Item, Update-Item, View-Item, List-Item에 대한 api에 대한 내용을 기술한다.

문서에 include::{snippets}/save-item/http-request.adoc[] 부분에 대한 문서 저장은 build/generated-snippets 에 저장되어있는 위치이다. *

src/main/resources/static/doc 디렉토리를 생성하면 adoc파일에 해당 경로의 html로 변환되어 저장된다. 그래서 최종 빌드를 하게 되면 index.html, Item-API.html, Member-API.html, Order-API.html 파일이 만들어지고 index.html에서 확인 할 수가 있다.

마지막으로 jar로 배포하고 실행하면 아래 경로에서 확인이 가능하다.

*http://localhost:8080/docs/index.html*.

erd