[Spring Rest Doc] Spring Rest Doc을 채택한 이유
이전 프로젝트에서 프론트와 API를 소통하기 위해 Swagger에 open API ui를 활용해서 사용했습니다.
이것이 편한건줄만 알았는데 편하지만 몇 가지 아쉬운 부분이 있었다.
- Swagger문서에서 요청되는 Httprequest가 실제 서비스 서버로 요청되면서 서비스용 데이터베이스에 반영이 되어 짧은 기간 프로젝트에는 적합하나 서비스를 운영하기 위해서는 테스트 서버와 서비스 서버가 분리되어야 했습니다.
- Controller만 구현되어도 문서에 명시되기 때문에 신뢰성 있는 API가 공유되지 않는다는 것입니다. 즉 에러가 나는 API도 공유가 됩니다.
- API문서가 수정될 때마다 노션의 문서를 수정했어야 했습니다. 문서를 수정하는 과정을 팀웜들이 굉장히 번거로워했습니다.
이러한 이유가 있었기 때문에 Spring Rest Doc을 공부해서 프로젝트에 적용해 보기로 했습니다.
우선 Spring Rest Doc은 테스트 코드가 성공이 되어야 문서가 작성되가 때문에 테스트 코드를 작성해야 합니다.
전체적인 흐름은 다음과 같습니다.
- 테스트 코드를 작성합니다. API가 요청되었을 때 정확한 값이 리턴이 되는지 목적 가지고 테스트 코드를 짜기 때문에 Controller단위로 테스트 코드를 작성해야 했고 Mockmvc와 Junit을 활용해서 테스트 코드를 작성했다.
- Mockmvc은 실제 서블릿 콘텍스트가 아닌 Mock 컨테이너를 사용하기 때문에 실제 서비스에 반영이 안 된다. 그리고 RestController로 명시된 어노테이션만 Bean으로 등록되기 때문에 빌드될 때 테스트 과정을 최적화할 수 있습니다. 단 테스트 코드 작성 할 때 @Component를 써야 할 때 @MockBean을 써줘야 합니다.
- 테스트 코드가 완성되면 snippet이라고 불리는 문서 조각이. adoc이 만들어집니다. snippet이 만들어지는 설정은 build.gradle에서 해줘야 합니다. 설정하는 과정이 어려웠었는데 gradle이 Groovy라는 문법으로 쓰이기 때문에 추가적으로 공부하면 도움이 될꺼같다.
- index.adoc에서 snippet들의 문서조각들을 모아서 하나의 index.adoc 파일로 만듭니다.
- index.adoc 파일을 배포가능 하게 정적 디렉터리 아래로 복사해야 한다.
아래에는 위의 흐름의 build.gradle이다.
plugins {
id "org.asciidoctor.jvm.convert" version "3.3.2"
}
configurations {
asciidoctorExt
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.projectlombok:lombok:1.18.22'
testImplementation 'junit:junit:4.13.1'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
annotationProcessor 'org.projectlombok:lombok:1.18.22'
// rest Doc
asciidoctorExt 'org.springframework.restdocs:spring-restdocs-asciidoctor'
testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
// asertJ
testImplementation 'org.junit.jupiter:junit-jupiter:5.8.2'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
testCompileOnly 'org.projectlombok:lombok:1.18.22'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.22'
}
ext {
snippetsDir = file('build/generated-snippets')
}
tasks.named ('test') {
outputs.dir snippetsDir
}
asciidoctor {
configurations 'asciidoctorExt'
baseDirFollowsSourceFile()
inputs.dir snippetsDir
dependsOn test
}
asciidoctor.doFirst {
delete file('src/main/resources/static')
}
task copyDocument(type: Copy) {
dependsOn asciidoctor
from file("build/docs/asciidoc")
into file("src/main/resources/static")
}
build {
dependsOn copyDocument
}
bootJar {
dependsOn asciidoctor
from("${asciidoctor.outputDir}") {
into "static/docs"
}
}
ASCIIDOC
Gradle 버전 7.6을 쓰고 있기 때문에 org.asciidoctor.jvm.convert를 설치해줍니다.
asciidoc은 문서를 만드는 도구이다. 공식문서에 문법과 사용법이 잘 나와있으니 참고하면 된다.
= Danim Rest Docs 문서
부제목(부제)
:doctype: book
:icons: font
:source-highlighter: highlightjs // 문서에 표기되는 코드들의 하이라이팅을 highlightjs를 사용
:toc: left // toc (Table Of Contents)를 문서의 좌측에 두기
:toclevels: 2
:sectlinks:
[[Member-API]]
== Member API
[[Member-회원추가]]
=== 회원추가
operation::user[snippets='curl-request,request-fields']
의 설정의 화면인 이렇게 보인다.

현재 회원 추가 api의 operation::user [snippets='curl=request, resquest-fields']는 build/generated-snippets/user 아래에 만들어진 Curl-reqeust.adoc, Request-fields를 참조하고 있는데 현재 존재하지 않아서 나는 오류이다.
위의 설정으로 로컬에서 빌드했을 때 정말 완벽하게 구현되었다. 하지만 배포했을 때 generated-snippets가 안 만들어졌고 프로젝트 중이라 더 이상 시간을 소비할 수 없어서 해결을 못했는데
ext {
snippetsDir = file('build/generated-snippets')
}
여기에서 snippetDir = file('./build/generated-snippets')로 수정하면 해결 될꺼같다. 로컬에서는 현재 경로가 프로젝트 아래로 잡히지만 배포환경에서는 그게 아닌 거 같다. 프로젝트가 끝나고 빨리 테스트해보겠다.