[프로젝트] Spring Rest Docs 문서 분리하기

공부하는 감자·2024년 2월 23일
0

F-Lab 프로젝트

목록 보기
11/11

들어가는 말

Spring REST Docs는 기본적으로 Asciidoctor를 사용한다.

프로젝트에서 특정 경로에 adoc 확장자를 가진 파일을 생성하면, 빌드 시 HTML 파일을 만들어준다.

빌드 도구adoc 파일 경로생성된 파일 경로
Mavensrc/main/asciidoc/*.adoctarget/generated-docs/*.html
Gradlesrc/docs/asciidoc/*.adocbuild/asciidoc/html5/*.html

나는 지금껏 index.adoc 이라는 기본 파일만 생성하여 사용하고 있었는데, API가 늘어나고, 기능 별로 브랜치를 따로 따서 관리하다 보니 파일을 분리할 필요성을 느꼈다.

Spring Rest Docs 문서 분리하기

분리의 필요성

adoc을 하나만 썼을 때 문제점을 생각하게 된 건 기능 별로 브랜치를 분리하여 작업하면서였다.

예상 시나리오는 다음과 같다.

  1. feature/member_api 브랜치에서 API 생성 후 index.adoc에 추가한다.
  2. feature/funding_api 브랜치에서 API 생성 후 index.adoc에 추가한다.
  3. 이후 develop 브랜치에서 merge할 때 index.adoc에서 충돌이 일어난다!

즉, 여러 브랜치에서 하나의 adoc에 추가하고 삭제하다 보니 충돌이 생길 거란 걸 뒤늦게 생각한 것이다.

그러한 이유로 목표는 다음과 같다.

  • index.adoc 은 메인 페이지로 사용할 것
    • 기능 별로 분리한 adoc을 가져와서 보여준다.
  • 기능 별로 adoc을 만든다.

분리하기

방법은 간단하다.

  1. adoc 파일을 하나 더 만든다.
  2. index.adoc에서 해당 파일을 참조하게 한다.

처음엔 다음과 같이 하나의 파일로 있었다. 여기에서 펀딩 관련 API만 따로 funding.adoc 파일로 분리한다.

# 기존 index.adoc
= API 명세
:doctype: book
:source-highlighter: highlightjs
:toc: left
:toc-title: 목차
:toclevels: 2
:sectlinks:
:sectnums:
:docinfo: shared-head

== 회원
=== 회원가입
operation::member-service-test/register-member[snippets='http-request,http-response,request-fields,response-fields']

=== 회원탈퇴
operation::member-service-test/deregister-member[snippets='http-request,http-response,request-fields,response-fields']

=== 회원 정보 조회
operation::member-service-test/get-member[snippets='http-request,http-response,request-fields,response-fields']

== 펀딩
=== 펀딩 등록
operation::funding-rest-adapter-test/register-funding[snippets='http-request,http-response,request-fields,response-fields']

=== 펀딩 취소
operation::funding-rest-adapter-test/cancel-funding[snippets='http-request,http-response,path-parameters,response-fields']
# 분리한 funding.adoc

== 펀딩
=== 펀딩 등록
operation::funding-rest-adapter-test/register-funding[snippets='http-request,http-response,request-fields,response-fields']

=== 펀딩 취소
operation::funding-rest-adapter-test/cancel-funding[snippets='http-request,http-response,path-parameters,response-fields']

그리고, 메인 화면으로 삼을 index.adoc 에서 include 로 분리한 파일을 가져오게 한다.

include::funding.adoc[]

오류도 나지 않고, 오른쪽에 미리보기 화면에서도 잘 불러온 것을 볼 수 있다.

Unresolved directive 오류

그런데 실제로 빌드를 해보니 adoc을 불러올 수 없다는 오류가 발생했다.

Unresolved directive in index.adoc - include::funding.adoc[]

자세한 오류를 보기 위해 터미널을 확인했다. (사실 이 이전엔 오류를 제대로 못 보고 헤매서 시간이 소요된 후에 보게 되었다)

여기서 잘 보면, 다음 오류 문구를 확인할 수 있다.

include file not found: 프로젝트-경로/funding.adoc :: index.adoc

즉, 지정된 경로에서 파일을 읽을 수가 없다는 것이 문제였다. 분명 IntelliJ 상에선 경로 지정도 올바르게 되어있고, 잘 불러왔는데!

해결

경로가 문제라면 하드 코딩으로 맞춰주면 된다.

Asciidoctor 문서에 보면, 디렉토리 경로를 의미하는 {docdir} 속성이 있다.

이걸 이용해서 다음과 같이 작성했다.

  • IntelliJ에서는 {docdir} 이 asciidoc 폴더까지 경로로 잡혀 있었는데, 실제로 빌드해서 문서를 생성했을 땐 프로젝트 루트로 잡혀 있어서 하드 코딩했다.
include::{docdir}/src/docs/asciidoc/funding.adoc[]

그러면 IntelliJ에선 다음과 같이 오류가 나지만, 빌드해보면 문서는 제대로 생성되는 걸 볼 수 있다.

근본적인 해결

2024.04.09 추가

프로젝트를 리팩토링하면서 이 문제를 수정할 수 있을지 한 번 더 살펴 봤다. 그리고 'docdir'에 대한 설명을 발견했다.

docdir 설명

여기서 내가 주목한 것은 'Default value'이다. 기본 경로가 '현재 폴더'였다!

Values만 보고 docs 경로로 자동으로 잡힌 줄 알고 왜 안될까? 하고 생각했던게 패인이었다.

그리고, 찾아보니 baseDirFollowsSourceFile() 옵션이 있다는 것도 알게 되었다.

build.gradle에서 해당 옵션을 설정하면 특정 .adoc에서 다른 adoc 파일을 include해오고 싶을 경우 경로를 baseDir로 맞춰준다고 한다.

따라서 build.gradle의 설정을 아래와 같이 변경했다. (하는 김에 index.adoc만 html로 변환하도록 설정도 해줬다)

asciidoctor {
	inputs.dir snippetsDir
	configurations 'asciidoctorExt'
	dependsOn test
    // source를 지정하면 특정 adoc만 HTML로 만든다.
	sources {
		include("**/index.adoc")
	}
    // 경로를 baseDir로 맞춰준다!
	baseDirFollowsSourceFile()
}

// Jar 만들 때 문서 생성하는 코드
bootJar {
	dependsOn asciidoctor
	from ("${asciidoctor.outputDir}/html5") {
		into 'static/docs'
	}
}

// HTML 파일을 찾아보는게 불편해서,
// build할 때 문서 생성 후 HTML 문서를 특정 경로로 이동하도록 설정했다.
tasks.register('copyDocument', Copy) {
	dependsOn asciidoctor
	delete('src/main/resources/static/docs')
	from("${asciidoctor.outputDir}") {
		include("**/index.html")
	}
	into('src/main/resources/static/docs')
}

build {
	dependsOn copyDocument
}

그리고 adoc도 변경해주면 된다!

include::{docdir}/member.adoc[]

include::{docdir}/login.adoc[]

include::{docdir}/funding.adoc[]

include::{docdir}/support.adoc[]

접는 말

IntelliJ와 실제 경로가 어긋나는 이유는 아직 찾지 못했다.

Spring REST Docs를 연동할 때 경로에 손 댄 것이 없으니 기본 경로로 잡혀있을 거라고 생각했는데, IDE 상에서만 제대로 잡혀있으니 어디서 틀어진 건지 모르겠다.

이 부분은 좀 더 찾아보고, 저렇게 경로를 하드코딩하지 않고 깔끔하게 지정할 수 있는 방법이 있으면 그걸 적용해봐야겠다.

공식 문서에서는 찾아볼 수 없길래 가볍게 넘겼던 옵션이었는데, 좀 더 자세히 찾아볼 걸 그랬다.

어쨌거나 계속 신경쓰였는데 해결하고 나니 코드도 깔끔하고(오류 표시도 안나고) 마음이 편해졌다!

Reference

참고 사이트

Spring REST Docs

AsciiDoc - Document Attributes Reference

Asciidoctor Gradle Plugin Suite

[속닥속닥] 🚀 우당탕탕 Spring REST Docs 적용기

profile
책을 읽거나 강의를 들으며 공부한 내용을 정리합니다. 가끔 개발하는데 있었던 이슈도 올립니다.

0개의 댓글

관련 채용 정보