Sitemap
Gyumin Bae

Gyumin Bae

documentify : 선언형 REST Docs DSL 제작기

8 min readJan 31, 2025

--

API 문서 작성은 웹 서비스를 제작하는데 있어서 중요한 과정 중 하나 입니다.
잘 작성된 문서는 개발자가 API를 올바르게 통합하고 사용하는데 드는 시행착오를 줄여줄 수 있는데요, 이러한 API 문서 작성을 편리하게 도와주는 기술은 스프링 진영에서 크게 Swagger, Spring REST Docs 이렇게 두 가지를 꼽을 수 있습니다.

두 기술 스택 모두 각자의 장단점이 존재하지만, 이러한 단점들을 보완하고 장점을 통합하는 솔루션은 좀처럼 찾아보기 힘든 것 같았습니다. 이러한 상황 속에서, 우선 기존 문서화 툴의 이점과 문제점을 살펴보고 이를 기반으로 문제를 개선할 수 있는 방안을 소개해드리려 합니다.

Swagger

Swagger는 애노테이션 기반 문서화를 통해 문서화가 쉽고, 문서 최신화에 드는 비용도 낮다는 장점이 있습니다. 또한 확장성 면에서도 뛰어난데요, OAS (OpenAPI Specification) 규격 문서화를 제공함으로써 SwaggerUI가 아닌 third-party UI로도 API 문서를 볼 수 있는 확장성을 챙길 수 있습니다. UI에서 바로 테스트가 가능한 인터랙션까지 존재하여 가시적인 면과 생산성 측면에서 RestDocs에 비해 큰 이점을 지닐 수 있습니다. 하지만 동시에 문서화 스펙을 위한 코드가 프로덕션 코드에 강결합하게 되고, 검증되지 않은 스펙이 존재할 수 있으므로 안정성과 가독성 면에서는 단점으로 작용하게 됩니다.

REST Docs

테스트 기반 문서화 방식을 통해 문서 작성 단계부터 API에 대한 통합 테스트가 가능하고, API 변경 시 테스트에 실패하며 변경을 자동으로 감지할 수 있습니다. 프로덕션 코드와 문서화를 위한 코드를 분리하기도 쉽습니다. 하지만 RestDocs에서 제공하는 아스키닥은 시각적인 부분에서 Swagger에 비해 부족한 부분이 많고, 문서화를 위해 반복적이고 지루한 테스트 코드 작성을 반복해야 합니다. 문서화를 위해 Swagger보다 고려해야할 사항도 많다는 단점도 있습니다. (자세한 내용은 이 글을 살펴보셔도 좋습니다.)

Swagger와 Rest Docs 중 어떤 것을 선택할지는 다양한 상황과 조건에 따라 달라질 수 있지만, 결국 핵심은 각자의 단점을 얼마나 효과적으로 완화하거나 해결할 수 있는지에 달려 있습니다.

Swagger는 특히 개인이나 소규모 팀에서 사용할 경우, 기존 방식대로 유지하면서 단점을 극복하기 어렵습니다. 오히려 이를 보완해보려다 생산성을 저하시켜 Swagger의 사용 이유 자체를 무색하게 만들 수 있습니다. 반면, Rest Docs는 기존 도구들을 조합하여 Swagger의 장점을 어느 정도 활용하면서도 Rest Docs의 단점을 보완할 수 있습니다. 이러한 가능성에 주목하여, Rest Docs를 보다 편리하게 사용할 수 있도록 돕는 오픈소스 documentify를 개발하게 되었습니다.

documentify는 두 가지 핵심 기능을 제공합니다.

  1. Rest Docs를 쉽고 간편하게 활용할 수 있는 DSL 제공
  2. 문서화 과정에서 생성된 Asciidoc 파일을 OAS로 변환

이를 통해 RestAssured나 Rest Docs에 대한 깊은 이해 없이도 선언형 코드만으로 문서화 비용을 크게 낮출 수 있으며, 보다 세련된 디자인의 API 문서를 생성할 수 있습니다. 또한, OAS가 사실상 RESTful API 설계의 표준 역할을 한다는 점에서 documentify는 큰 강점을 갖습니다.

먼저 기존 작성법과 documentify DSL를 활용한 작성법을 비교해보겠습니다.

AS-IS

Press enter or click to view image in full size

TO-BE

Press enter or click to view image in full size

한 눈에 봐도 코드가 많이 간결해진 것을 확인할 수 있습니다.

기존 Rest Docs에서 가장 먼저 눈에 띄는 문제는 preprocessRequest(), preprocessResponse() 등의 보일러플레이트 코드입니다. 이는 문서 내용과 직접적인 관련이 없음에도 불필요하게 반복되고 있는 것을 확인할 수 있습니다. API 스펙을 정의하는 코드 또한 산재해있는데요, 이로 인해 payload, path variable, query parameter 등의 변경이 있을 때마다 문서화 코드도 함께 수정해야 하며, 이는 생산성을 저하시킵니다.

이러한 문제들이 누적되면서 Rest Docs를 활용하는 데 드는 비용이 증가하고, 문서화 작업을 담당하는 개발자들의 피로도도 높아집니다.

이를 해결하기 위해 라이브러리 내부적으로 반복되는 보일러플레이트 코드를 자동 처리하고, parameter나 payload 정의 시 샘플 값을 포함하도록 설계했습니다. 이렇게 제공된 샘플 값을 기반으로 요청을 전송하고 응답을 검증하는 로직을 자동화하여, 문서화 과정에서 필요한 코드량을 대폭 줄일 수 있도록 구현했습니다.

DSL의 세부적인 기능도 살펴보도록 하겠습니다.

Press enter or click to view image in full size
개발 초기 nested 필드 document 방식

초기 documentify 개발 단계에서는 payload에 중첩 필드가 포함된 경우, 직접 JSON Field Path를 작성해야 했습니다. 이를 보다 직관적으로 개선하기 위해, DSL을 적극 활용하여 중첩 필드와 배열 필드도 간편하게 문서화할 수 있도록 다음과 같이 개선했습니다.

Press enter or click to view image in full size

API 문서를 작성할 때, 예외 응답을 추가로 정의해야 하는 경우가 종종 발생합니다. 하지만 Rest Docs에서는 이를 문서화하려면 별도의 테스트 코드를 작성해야 한다는 점이 불편한 요소 중 하나였습니다.

특히 예외적인 응답은 대부분 일관된 포맷을 정의해 재사용하는 경우가 많기 때문에, API마다 개별적으로 문서화하는 작업이 불필요할 수 있다고 판단했습니다.

이를 개선하기 위해, 예외 응답의 경우 라이브러리 내부에 전용 컨트롤러를 선언하여 별도의 검증 없이도 단순 선언만으로 자동 문서화되도록 구현했습니다.

Press enter or click to view image in full size

예외 응답은 응답 코드별로 여러 개 정의할 수 있도록 설계했으며, 별도의 검증 없이 선언만으로 자동 문서화되도록 구현했습니다. 다만 이 과정에서 발생할 수 있는 부작용을 인지하고 적절히 활용하는 것이 중요할 것 같습니다.

asciidoc 파일을 OAS 스펙으로 변환하기 위한 dsl 기능도 살펴보겠습니다.
사실 변환 과정 전체를 저 혼자 모두 구현하기에는 무리가 있었는데, 다행히 자료를 조사하던 중 카카오페이 테크에서 작성한 글을 보고 epages에서 제공하는 오픈소스를 알게 되어 이를 documentify에 적용할 수 있었습니다.

Press enter or click to view image in full size

위와 같은 방식으로 OAS 스펙을 정의할 수 있으며, 굳이 명시하지 않고 생략하여 기본 값을 사용하는 것도 가능합니다.

개발 초기에는 request와 response의 schema name이 자동 생성되도록 구현했으나, 개인 프로젝트에 적용하는 과정에서 동일한 응답 구조를 가지는 스키마가 중복될 경우 문서화가 제대로 이루어지지 않을 수 있다는 문제를 발견했습니다. 이를 해결하기 위해 랜덤 문자열을 추가하여 각 schema를 고유하게 식별할 수 있도록 개선하였습니다.

또한, documentify를 사용하더라도 Gradle에서 generated-snippets을 OAS 스펙 문서로 변환하려면 epages에서 제공하는 플러그인을 적용해야 했습니다. 하지만 별도의 플러그인을 수동으로 추가하는 과정이 번거로울 수 있다고 판단하여, epages 플러그인을 자동으로 포함하는 Gradle documentify 플러그인을 별도로 배포하였습니다.
(아래와 같이 사용할 수 있습니다.)

plugins {
id("io.github.bgmsound.documentify") version "${version}"
}
openapi3 {
title = "Sample API"
description = "This is a sample API documentation."
version = "0.0.1"
format = "yaml"
}

플러그인을 적용하고 openapi 문서에 필요한 몇가지 정보를 기입 후 task를 실행하게 되면 최종적으로 아래와 같은 문서를 보실 수 있게 됩니다.

Press enter or click to view image in full size
Press enter or click to view image in full size

지금까지 불필요한 코드를 줄여 문서화 비용을 낮추고, OAS 스펙을 통해 가시성을 올리는 documentify dsl 과 이를 제작하는 과정에 대해서 소개드렸습니다. 현재 MVC와 Reactive API를 모두 문서화할 수 있으며, 앞으로 MultiPart와 Stream API에 대한 지원도 이어갈 계획입니다.
(소스코드는 여기서 확인하실 수 있습니다.)

문서화는 협업 과정에서 비즈니스 코드 작성 못지 않게 정말 중요한 부분이라고 생각합니다. 때문에 문서의 신뢰도와 문서화를 위한 자동화 코드의 유지 보수 또한 항상 생각해봐야 할 문제인데요, 이런 점에서 문서화 자동화의 품질을 유지하면서도 개발자에게 부담을 최소화하는 균형을 찾는 것이 중요한 것 같습니다.

긴 글 읽어주셔서 감사합니다!

--

--