[Spring] Spring Rest Docs 도입기

stanley.·2024년 3월 30일

Spring

목록 보기
4/4
post-thumbnail

개요


클라이언트 - 서버, 서버 - 서버 간 통신을 통해 프로그램이 동작하기 위해 필요한 것이 바로 API(Application Programming Interface)다.
API 스펙을 통해 필요한 요청 데이터와 응답 데이터를 정의하고 문서화를 통해 API 정보를 규격화 해둬야 한다.
그러나, 프로그램의 규모가 커지게 되면 문서화를 위한 비용이 그만큼 커지게 된다.
또한, 정확한 API 정보가 업데이트가 되어 있지 않아 잘못된 API 스펙으로 구현이 될 수도 있다.
위와 같은 문제를 방지하고자, API 문서의 자동화가 필요함을 느꼈고 Spring Rest Docs를 개인 프로젝트에 도입하게 되었다.

Spring Rest Docs 란?

  • 스프링 프레임워크에서 제공하는 API 문서화 자동 지원 도구
  • 자동화 과정에서 테스트 코드가 필수적으로 작성되어야 하여 코드의 강건성 보장
  • 정확한 API 문서를 보장함으로써 문서화 할 때 발생하는 휴먼 에러를 줄임
  • 프로덕션 코드에 API 문서화를 위한 별도의 코드를 추가하지 않아도 된다.
    (또 다른 API 명세화 자동화 도구인 Swagger는 api 문서화를 위해 프로덕션 코드에 어노테이션을 명시한다.)

실습 - 적용하기

build.gradle

   id 'java'
    id 'org.springframework.boot' version '3.1.1'
    id 'io.spring.dependency-management' version '1.1.4'
    id "org.asciidoctor.jvm.convert" version "3.3.2" //(1)
}

group = 'gpt.service'
version = '0.0.1-SNAPSHOT'

java {
    sourceCompatibility = '17'
}

configurations {
    asciidoctorExtensions //(2)
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

ext {
    snippetsDir = file('build/generated-snippets') // (3)
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    compileOnly 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    runtimeOnly 'com.mysql:mysql-connector-j'
    annotationProcessor 'org.projectlombok:lombok'

    asciidoctorExtensions 'org.springframework.restdocs:spring-restdocs-asciidoctor' //(4)
    testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc' //(5)
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

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

asciidoctor { //(7)
    configurations 'asciidoctorExtensions' //(7)-(1)
    baseDirFollowsSourceFile() //(7)-(2)
    inputs.dir snippetsDir //(7)-(3)
    dependsOn test //(7)-(4)
}

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

bootJar { (9)
    dependsOn copyDocument
}
  1. asciidoctor 플러그인을 적용한다.
  2. asciidoctor를 확장하는 asciidoctorExtensions 에 대한 종속성을 설정한다.
  3. 생성되는 스니펫들에 대한 디렉토리를 설정한다.
  4. spring-restdocs-asciidoctor 의존성을 추가한다. 이는 build/snippets 하위의 .adoc 파일을 읽어와 html 파일로 변환해준다.
  5. mockmvc를 사용하기 위한 의존성을 추가한다.
  6. 테스트 시에 스니펫을 snippetsDir로 생성하도록 태스크를 삽입한다.
  7. asciidocter에 대한 태스크를 설정한다.
    7-1. asciidoctor 확장에 대한 설정을 한다.
    7-2. include() 연산 시 base 디렉터리를 지정한다.
    7-3. 불러올 스니펫 위치를 snippetsDir로 설정한다.
    7-4. test 태스크 이후에 asciidoctor가 실행되도록 설정한다.
  8. asciidoctor 태스크 실행 이후 생성된 asciidoc 하위의 .adoc 파일들을 "src/main/resource/static" 하위의 경로로 가져오도록 한다.
  9. jar 파일 생성 시 위 copyDocument 태스크가 실행되도록 한다.

asciidoctor는 adoc 파일을 html로 변환해주는 역할을 한다.

테스트 실행 및 adoc 스니펫 생성

  • 위와 같이 테스트 코드가 정상적으로 통과된 뒤 gradle clean build를 진행하면 build > generated-snippets 하위에 아래와 같이 adoc 파일이 생성된 것을 볼 수 있다.

asciidoc 문서 생성

  • API 별로 생성된 adoc 스니펫을 모아 완전한 API 명세화를 위해 보통 "src/docs/asciidoc"의 경로로 디렉토리를 생성하여, asciidoc 문서를 작성한다.
  • include를 사용하여 생성된 adoc 스니펫들을 asciidoc 문서로 불러온다.
= GPT Service API 문서
:doctype: book
:source-highlighter: highlightjs
:toc: left
:toclevels: 2
:seclinks:

include::test.adoc[]

html 문서 생성

./gradlew asciidoctor
  • asciidoctor 태스크를 실행하여 html 문서를 생성한다.
  • 위 명령어를 실행하면 "src/docs/asciidoc" 하위에 작성한 adoc 파일과 이름이 동일한 html 파일이 생성된다.

bootJar를 한 html 파일 복사하기

  • 위의 과정을 통해 adoc 스니펫을 생성하고 이를 바탕으로 asciidoc 문서를 작성하여 html 파일까지 생성했다.
  • 이후, 아래 명령어를 통해 jar 파일 생성 시 asciidoctor를 기반으로 생성된 html 파일이 "src/main/resource/static" 하위로 옮겨지도록 한다.
  • 위 과정을 통해 패키징 된 jar 파일의 static 하위에 asciidoctor를 기반으로 만들어진 API 정보 html 파일도 포함되게 된다.

위의 모든 과정을 마치면 http://localhost:8080/index.html로 접근 시 API 정보 페이지를 볼 수 있게 된다.

레퍼런스

https://docs.spring.io/spring-restdocs/docs/current/reference/htmlsingle/
https://hudi.blog/spring-rest-docs/
https://maily.so/grabnews/posts/b2341a

profile
🖥 Junior Developer.

0개의 댓글