2023. 3. 22. 00:37ㆍCheatSheet
일일이 읽으면서 파악하기 귀찮으신 분들은 바로 맨 아래 '5. restDocs Gradle cheatSheet'를 참고하세요.
SpringBoot는 편리함을 목적으로 Spring initializer를 활용한다.
2.x.x 시절에 Java/Spring 환경에서 작업할 때는 별 문제가 없었다. 그런데, SpringBoot 3.0.0+Kotlin으로 갈아타는 순간부터, Spring initializer가 기본적으로 해주는 설정에 뭔가 하나씩 문제가 생기고 있었다.
Rest Docs도 그 중 하나였고 삽질을 너무 중구난방으로 하여, 한번 정리할 목적으로 이 글을 작성해 본다.
1. gradle의 plugins 정리하기
시작부터 build.gradle.kts에 빨간 줄이 그어진다... 왜냐면, 이니셜라이져가 설정해 주는 기본 플러그인 설정이 호환이 안되기 때문이다.
plugins 블록 항목을 다음과 같이 고쳐주자.
plugins {
id("org.springframework.boot") version "3.0.4"
id("io.spring.dependency-management") version "1.1.0"
id("org.asciidoctor.jvm.convert") version "3.3.2"
kotlin("jvm") version "1.7.22"
kotlin("plugin.spring") version "1.7.22"
kotlin("plugin.jpa") version "1.7.22"
kotlin("kapt") version "1.7.22"
idea
}
스프링 이니셜라이저가 설정해주는 플러그인은 groovy 기반의 gradle에서 지원하는 플러그인을 섞어서 선언하기에 위에서 처럼 코틀린 기반의 gradle에서 지원하는 플러그인을 선언해서 고쳐줘야 한다.
2. gradle의 dependency 정리하기
val asciidoctorExtensions: Configuration by configurations.creating
dependencies {
/** rest docs */
testImplementation("org.springframework.restdocs:spring-restdocs-mockmvc")
testImplementation("org.springframework.restdocs:spring-restdocs-asciidoctor")
asciidoctorExtensions("org.springframework.restdocs:spring-restdocs-asciidoctor")
}
마찬가지다. 스프링 이니셜라이저가 rest docs를 작성해 주는데 필요한 asciidoctor 확장자 선언을 groovy 기준으로 선언해 주었기 때문에 코틀린 그래들이 빌드 스크립트를 읽지 못하고 있다.
코틀린 문법에 맞게 고쳐주자.
3. gradle의 task 정리
이제 tasks 정리하여, 테스트&빌드와 동시에 api 문서를 만들 수 있는 환경을 구성하자.
먼저 gradle의 기존 task를 약간 커스터마이징 해야 한다.
우선, 코드부터 보자
tasks {
val snippetsDir = file("$buildDir/generated-snippets")
clean {
delete("src/main/resources/static")
}
test {
useJUnitPlatform()
systemProperty("org.springframework.restdocs.outputDir", snippetsDir)
outputs.dir(snippetsDir)
}
build {
dependsOn("copyDocument")
}
asciidoctor {
dependsOn(test)
attributes(
mapOf("snippets" to snippetsDir)
)
inputs.dir(snippetsDir)
doFirst {
delete("src/main/resources/static")
}
}
register<Copy>("copyDocument") {
dependsOn(asciidoctor)
destinationDir = file(".")
from(asciidoctor.get().outputDir) {
into("src/main/resources/static")
}
}
bootJar {
dependsOn(asciidoctor)
from(asciidoctor.get().outputDir) {
into("BOOT-INF/classes/static")
}
}
}
대충 gradle에서 build를 수행하면, 무조건 test -> asciidoctor -> copyDocument -> build를 수행하여, jar를 말아주면서, 웰컴 페이지에 restDocs 기반의 api 문서를 준다는 뜻이다.
물론, 무분별한(?) 삽질로 다소 정리가 안된 건 사실이지만, 우선은 동작하고 있으니, 이대로 두겠다. 하지만, index.html 형태의 페이지를 자동으로 얻고 싶으면 여기서 끝내면 안 된다.
4. index.adoc 작성하기
'프로젝트경로/src/docs/asciidoc'에 index.adoc을 작성해두어야 한다.
당연히 지금은 구현한 api가 없으니, 우선 helloWorld가 적인 아스키 문서를 작성해 보자
ifndef::snippets[]
:snippets: ../../../build/generated-snippets
endif::[]
= api 문서 제목
// 왼쪽에 제목별 메뉴 생성
:toc: left
:toclevels: 4
:sectlinks:
== hello
이렇게 작성해 보고 프로젝트 경로에서 `./gradlew clean build`를 하거나, IDE를 활용하여 gradle의 task를 수동으로 실행시켜 보고, 로컬에 띄워서 해당 서버의 웰컴 페이지로 이동 하면, 동작 여부를 확인해 볼 수 있다.
5. restDocs Gradle CheatSheet
이 글을 보면서 1-4까지 보는 게 귀찮은 사람 혹은, restDocs를 오랜만에 다뤄서 기억이 안나는 나 자신을 위한 문단이다.
1. build.gradle
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
id("org.springframework.boot") version "3.0.4"
id("io.spring.dependency-management") version "1.1.0"
id("org.asciidoctor.jvm.convert") version "3.3.2"
kotlin("jvm") version "1.7.22"
kotlin("plugin.spring") version "1.7.22"
kotlin("plugin.jpa") version "1.7.22"
kotlin("kapt") version "1.7.22"
}
...
repositories {
mavenCentral()
}
val asciidoctorExtensions: Configuration by configurations.creating
dependencies {
/** rest docs */
testImplementation("org.springframework.restdocs:spring-restdocs-mockmvc")
testImplementation("org.springframework.restdocs:spring-restdocs-asciidoctor")
asciidoctorExtensions("org.springframework.restdocs:spring-restdocs-asciidoctor")
}
tasks {
val snippetsDir = file("$buildDir/generated-snippets")
clean {
delete("src/main/resources/static")
}
test {
useJUnitPlatform()
systemProperty("org.springframework.restdocs.outputDir", snippetsDir)
outputs.dir(snippetsDir)
}
build {
dependsOn("copyDocument")
}
asciidoctor {
dependsOn(test)
attributes(
mapOf("snippets" to snippetsDir)
)
inputs.dir(snippetsDir)
doFirst {
delete("src/main/resources/static")
}
}
register<Copy>("copyDocument") {
dependsOn(asciidoctor)
destinationDir = file(".")
from(asciidoctor.get().outputDir) {
into("src/main/resources/static")
}
}
bootJar {
dependsOn(asciidoctor)
from(asciidoctor.get().outputDir) {
into("BOOT-INF/classes/static")
}
}
}
tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs = listOf("-Xjsr305=strict")
jvmTarget = "17"
}
}
tasks.withType<Test> {
useJUnitPlatform()
}
2. projectDir/src/docs/asciidoc/index.adoc
ifndef::snippets[]
:snippets: ../../../build/generated-snippets
endif::[]
= api docs name
:toc: left
:toclevels: 4
:sectlinks:
== hello
3. asciidoc 작성법 참고
여기에 일일이 작성할 이유가 없을 정도로 잘 정리된 사이트이다. (심지어 한국어)
https://narusas.github.io/2018/03/21/Asciidoc-basic.html#asciidoctor
'CheatSheet' 카테고리의 다른 글
NCP Global DNS: 도메인 구매 및 SSL 적용 (0) | 2023.12.07 |
---|---|
오픈소스 라이센스의 종류과 적용범위 (0) | 2023.05.15 |
Spring Boot + Keycloak server (0) | 2022.10.24 |