좋은 API 문서에 대한 고찰 (Swagger, Springdoc, Rest Docs)

 

개요

좋은 API 문서란

백엔드 개발자에게 좋은 API를 설계하는 일은 매우 중요하다. 백엔드 개발자에게 있어서는 API의 사용자가 곧 고객이나 다름 없기 때문이다. 그렇기 때문에, 좋은 API를 설계하고 이를 더 빠르게, 저렴하게, 일관적이며 언제든 이용 가능하도록 제공하는 일은 백엔드 개발자의 중요한 사명이라고 할 수 있다.

그러나 백엔드 개발자에게는 좋은 API를 설계하는 것만큼 중요한 일이 하나 더 있다. 바로 좋은 API 문서를 작성하는 일이다. API 문서는 API를 사용하기 위해 사용자가 알아야 할 필수적인 정보들로, (미래의 나를 포함한) 나와 협업하는 모든 동료들에게 중요한 정보 제공처가 된다.

그렇다면 좋은 API 문서란 무엇일까? 각자가 생각하는 바가 다르겠지만, 나는 “신뢰 가능한” API 문서가 좋은 API 문서라고 생각한다. 반대로 말하자면, API 스펙을 업데이트했음에도 이를 문서에 제대로 반영하지 않아 API 사용자가 (문서를 잘 읽었음에도) 원하는 바를 달성하지 못했다면 이는 좋지 않은 문서라고 생각한다.

그렇다면, 신뢰 가능한 API 문서를 작성하는 방법에는 어떤 것이 있을까?

신뢰 가능한 API 문서 작성하기 - API의 변경 사항을 실시간으로 반영

API 스펙의 변경 사항이 문서에 제대로 반영되지 않는 것은, 문서의 관리자가 이를 까먹었기 때문이다. 여기에는 바빠서든, 관리자가 퇴사하며 인수인계가 누락된 것이든, 다양한 원인이 있을 수 있다.

핵심은, 사람은 언제든 할 일을 까먹을 수 있고, 까먹지 않더라도 우선순위에서 밀리며 실제 API의 변경 시점과 문서의 업데이트 시점이 맞지 않을 수 있기 때문에 수동 업데이트는 신뢰할 수 없다는 것이다. 그렇기 때문에 가장 신뢰할 수 있는 문서 작성 방법은 코드 베이스를 기반으로 문서가 생성될 수 있도록 문서 생성을 자동화하는 것이다.

Spring 기반의 애플리케이션 서버를 구축할 때에는 API 문서 자동화를 위해 Swagger 기반의 라이브러리인 Springdoc, 테스트 코드 기반의 라이브러리인 Spring Rest Docs 등을 이용할 수 있다.

이번 글에서는 이러한 문서화 라이브러리들의 특징과 장단점에 대해 정리해보고자 한다.

 

 

Springdoc vs Spring Rest Docs

1. Springdoc

 

OpenAPI 3 Library for spring-boot

Library for OpenAPI 3 with spring boot projects. Is based on swagger-ui, to display the OpenAPI description.Generates automatically the OpenAPI file.

springdoc.org

Springdoc은 어노테이션 기반의 문서 자동화 라이브러리로, OpenAPI(Swagger) 사양에 맞춘 API 문서를 생성하고 Swagger UI를 통해 만들어진 문서를 쉽게 브라우저로 확인할 수 있도록 돕는다.

해당 도구의 장/단점은 아래와 같다.

  • 장점
    • 작성이 매우 간단하고 직관적이다.
    • Swagger 기반의 라이브러리로, 함께 사용되는 Swagger UI는 브라우저 기반으로 API 테스트를 해볼 수 있는 기능까지 제공해 API에 대한 이해도를 갖추기에 좋은 도구이다.
  • 단점
    • 문서화를 위한 코드가 운영 코드에 침투한다.
    • API가 실제로 우리가 의도한대로 동작함까지는 보장해주지 못한다. 개발자의 실수로 문서의 신뢰가 깨질 위험은 존재한다.

2. Spring Rest Docs

 

Spring REST Docs

Spring REST Docs helps you to document RESTful services. It combines hand-written documentation written with Asciidoctor and auto-generated snippets produced with Spring MVC Test. This approach frees you from the limitations of the documentation produced b

spring.io

Spring Rest Docs는 테스트 코드 기반의 문서 자동화 도구로, Spring 테스트 환경과 연동되어 Spring 테스트가 성공했을 때 이 테스트를 기반으로 스니펫(snippet, 조각) 단위의 API 문서를 생성한다.

해당 도구의 장/단점은 아래와 같다.

  • 장점
    • API 문서화를 위한 코드가 테스트 코드 내에만 존재하며, 운영 코드에 침투하지는 않는다.
    • 테스트가 성공했을 때에만 문서가 생성되기 때문에, 테스트를 잘 작성했다면 API 문서가 제공될 시 해당 API가 의도한대로 동작할 것을 보장할 수 있다.
  • 단점
    • 문서화를 위한 코드가 길고, 중복되는 내용이 많다.
    • Swagger UI 기반의 API 문서와 같은 테스트 기능을 이용할 수 없다.

3. Spring Rest Docs + Swagger UI

1번과 2번 모두 각자의 장단점이 있음에 따라, Rest Docs의 안정성과 Swagger UI의 편안함을 모두 누리기 위해 등장한 방법이다.

Rest Docs로 스니펫을 만들고 이 스니펫들을 기반으로 Swagger UI가 읽을 수 있는 OpenAPI specification 문서를 생성한다면, Rest Docs처럼 문서에 담을 API spec을 테스트 코드 기반으로 생성하고 Springdoc처럼 Swagger UI 기반의 문서를 확인해볼 수 있다는 것이다.

스니펫을 OpenAPI 문서로 변환하는 것을 돕는 extension인 restdocs-api-spec을 이용하면 이를 쉽게 달성할 수 있다.

 

GitHub - ePages-de/restdocs-api-spec: Adds API specification support to Spring REST Docs

Adds API specification support to Spring REST Docs - ePages-de/restdocs-api-spec

github.com

 

해당 방식의 장/단점은 아래와 같다.

  • 장점
    • Rest Docs의 안정성, Swagger UI의 테스트 가능 환경 제공이라는 이점을 모두 누릴 수 있다.
  • 단점
    • (2024.10월 기준) restdocs-api-spec 라이브러리에 개선점이 꽤 있다. 대표적인 예시로는, 이미지와 같은 multipart 요청을 처리하는 API의 경우 정상적으로 문서화가 되지 않는다. 이렇게 스니펫 → OpenAPI 문서 생성 단계에서 제대로 반영되지 않는 부분은 커스터마이징을 통해 직접 반영해 주어야 하는데, 이 방법이 상당히 어렵다…

참고로 해당 방법을 처음 도입할 때에는 컬리 기술 블로그에 올라온 글을 많이 참고했었는데, gradle 작성 방식이 Spring Boot 버전에 따라 많이 달라질 수 있기 때문에 자신의 버전에 맞는 설정 방식을 잘 찾아서 적용해보자.

 

 

어떤 방법을 사용하는 것이 좋을까?

아마도 정답은 없다. 실제로 기업마다 사용하는 방식이 다 다르고 표준이 없는 것으로 보아 지금까지는 마땅히 표준삼을 best-practice가 없지 않았나 싶다. (아니라면 제발 저에게도 알려주세요)

나는 개인적으로 springdoc을 사용하되 문서를 위한 어노테이션을 최대한 별도 클래스로 분리하는 방식을 제일 선호한다. 아래와 같이 PostController가 있을 때 Post API의 Spec을 명시할 별도의 인터페이스를 선언하고 이를 구현하는 방식을 이용하면 실제 Controller에서는 Swagger 관련 코드를 덜어낼 수 있다.

@RestController
public class PostController {

	public ResponseEntity<CreatePostResponse> create(@RequestBody CreatePostRequest request) implements PostApiSpecification {
		// ...
	}
	
}
@Tag(name = "Post")
public interface PostApiSpcification {

	@Operation(summary = "포스트 생성")
	@ApiResponses({
		@ApiResponse(...)
		@ApiResponse(...)
	})
	ResponseEntity<CreatePostResponse> create(
		@Parameter(description = "파라미터 설명") String param
	);

}

DTO에 담기는 Swagger 관련 어노테이션 또한 Request/Response 객체에만 명시하고 컨트롤러 계층 이하에서 사용되는 비즈니스 로직과 밀접한 객체들에서는 사용하지 않음으로서 비즈니스 로직과 문서화 코드의 혼재를 최소화할 수 있다.

이렇게 해서 운영 코드 침투를 최소화하며 Springdoc을 사용하는 이유는, 개인적으로는 Springdoc이 가장 직관적이라고 생각하기 때문이다. 어노테이션들 모두 제 역할을 잘 반영한 이름을 가지고 있고, 이들을 잘 사용하기만 해도 별도의 복잡한 커스터마이징 로직 없이 OpenAPI 문서를 생성할 수 있다.

하지만 이 방식을 사용할시, API 테스트 코드는 반드시 작성하기를 권장한다. Rest Docs의 가장 큰 이점인 “테스트가 성공해야 문서가 생성됨”을 누릴 수 없기 때문이다.