PPAK

Spring Rest Docs 본문

spring

Spring Rest Docs

PPakSang 2023. 12. 11. 09:47

Spring Rest Docs 는 API 인터페이스를 손쉽게 만들기 위해서 사용하는데, Spring MVC Test 혹은 WebTestClient를 통해 생성된 파일(adoc 파일, snippets)을 조합하는 방식으로 수행한다. 비슷한 목적으로 Swagger를 사용하곤 한다.

 

Swagger의 경우 프로덕션 코드에 Swagger 코드가 섞여 들어가는게 다소 부담됐고 변화하는 API 스펙에 맞춰 Swagger 코드 또한 수정해야 했었는데, Rest Docs는 테스트 코드를 바탕으로 문서가 생성되기 때문에 이러한 문제가 해결 된다. 즉, 테스트를 통과한 코드에 대해서 문서를 생성하기 때문에 잘못된 문서를 제공할 일이 줄어든다.

 

물론, Swagger를 사용하면 웹에서 API 호출 테스트를 손쉽게 수행할 수 있기 때문에 기호에 맞게 섞어 사용해도 무방하다고 생각한다. 또한, Rest Docc의 경우 adoc 파일을 개발자가 직접 조합해서 완성된 문서를 생성해야 하는 등 조금은 더 공수가 들어간다고 볼 수 있다.

 

이미 Spring Rest Docs 를 프로젝트에 도입하는 것과 관련해 많은 글들이 있지만, 이해가 되지 않는 부분에 대해서는 공식 문서를 참고하는 것도 좋을 것 같다.

https://docs.spring.io/spring-restdocs/docs/current/reference/htmlsingle/

 

Spring REST Docs

Document RESTful services by combining hand-written documentation with auto-generated snippets produced with Spring MVC Test or WebTestClient.

docs.spring.io

 

Rest Docs 문서(html) 생성은 크게 세 가지 단계로 나누어 수행한다.

adoc 문서는 Spring Rest Docs 에서 생성하고 관리하는 문서 확장자 중 하나이다.

 

1. 테스트 코드 작성/실행 -> adoc 문서 생성

2. adoc 문서 조합 -> 완성된 문서를 위한 adoc 문서 생성

3. adoc 문서를 html 문서로 변환

 

위와 같은 작업을 위해서 관련 의존성 설정 및 Task Pipeline 을 작성해야 한다. (본문은 kotlin 8.5 기준)

 

requirements

Spring Rest Docs를 사용하기 위해 최소 Java17, Spring Framework 6 이상의 환경이 세팅되어 있어야 한다.

build.gradle.kts

adoc 문서를 html로 변환하기 위해 사용되는 플러그인을 추가한다 (gradle 7.x 이상)

id("org.asciidoctor.jvm.convert")

 

 

asciidoctorExt configuration에 asciidoctorExtensions 의존성을 주입해준다. 각종 자동 설정이 추가 되고, 대표적으로 adoc 파일이 build/generated-snippets 경로에 저장되도록 설정해준다.

 

Spring MVC Test를 할 때 Rest Docs에서 제공하는 메소드를 사용해야 하기 때문에 이를 위한 의존성도 같이 추가해 준다.

val asciidoctorExt by configurations.creating

dependencies {
    asciidoctorExt("org.springframework.restdocs:spring-restdocs-asciidoctor")
    testImplementation("org.springframework.restdocs:spring-restdocs-mockmvc")
}

 

 

전체적인 adoc 문서 생성 -> html 변환 -> 최종 빌드 결과물 산출의 파이프라인을 kotlin dsl을 활용해 설정했다.

 

1. test와 asciidoctor 에서의 output, input dir 설정은 incremental builds를 위해 설정

2. 위에서 주입 받은 asciidoctorExt configurations를 설정한다.

3. copyDocs는 프로젝트 빌드 결과물에 html 파일을 static 디렉토리 아래에 포함시키기 위해 별도로 추가한 task 이다 (팀의 정책에 따라 경로를 수정하면 된다. finalizedBy 를 통해 html 변환이 완료된 후 수행한다)

4. baseDirFollowsSourceFile 셋팅 시 baseDir 이 모듈 루트에서, null로 셋팅해 루트 외부에 존재하는 adoc 파일에도 접근 가능하게 한다.

5. 기존 빌드 작업에 추가(asciidoctor 수행 후 bootJar 수행)

 

tasks {
    val snippetsDir = file("build/generated-snippets")
    test {
        outputs.dir(snippetsDir)
        useJUnitPlatform()
    }

    val copyDocs by registering(Copy::class) {
        from("build/docs/asciidoc")
        into("build/resources/main/static/docs")
    }

    asciidoctor {
        dependsOn(test)
        configurations("asciidoctorExt")
        inputs.dir(snippetsDir)

        baseDirFollowsSourceFile()

        finalizedBy(copyDocs)
    }

    bootJar {
    	dependsOn(asciidoctor)
    }
}

 

Test 를 통한 Snippets 생성

처음에 언급했듯 Rest Docs는 Test 코드 실행 결과를 바탕으로 생성된 Snippets(.adoc) 을 바탕으로 완성된 Html 문서를 만든다고 했다.

 

간단한 MockMvc 테스트 코드를 작성해 보자 (본문에서 MockMvc 사용 및 테스트 코드 작성은 간단히 한다)

 

 

SpringBootTest 말고 WebMvcTest로 웹레이어만 테스트가 가능하기도 하다

RestDocs에서 제공하는 @AutoConfigureRestDocs 를 추가해 생성된 snippets이 사전 정의된 경로에 저장될 수 있도록 한다.

 

일반적인 mockMvcTest 와는 조금 다르게 RestDocs에서 제공하는 래핑된 RestDocumentationRequestBuilder 를 사용하고, 필요에 따라 RestDocumentationResultHandler 를 추가해 snippets 을 조작할 수 있다.

 

테스트 실행 결과 build 하위에 아래와 같은 snippets 이 생성된 것을 확인할 수 있다.

 

html 파일은 어떤 문서를 바탕으로 생성될까?

위 3번째 과정에서 build/docs/asciidoc 경로에 html 파일이 생성된다고 했다.

 

html 파일은 Rest Docs 에서 사전에 정의한 경로에 내가 작성한 adoc 문서를 바탕으로 생성해 준다.

(Gradle 기준 src/docs/asciidoc/*.adoc 경로에 있는 파일 전체를 대상으로 한다)

 

간단한 adoc 문서를 하나 작성해 보자

 

adoc 은 크게 include, operation 을 통해 외부에 있는 adoc 문서(e.g 위에서 생성된 snippets)를 불러올 수 있고

opertation 의 경우 include와 다르게 baseDir 이 snippets 경로로 설정돼 있고, 자동으로 제목이 붙는다.

 

이제 asciidoctor를 통해 html 문서를 생성할 수 있다.

 

공식 문서에서는 Gradle 기준 Generated files 경로가 아래와 같이 나와 있는데, (아마 converter 버전 차이 때문인지) 실행해보면 build/docs/asciidoc 하위에 생성되는 것을 확인할 수 있다.

 

 

 

Comments