1. Swagger vs Spring Rest Docs
[1] Swagger
- 장점
- UI 가 깔끔하고 문서화를 사용하기 편리하다.
- 테스트 해볼 수 있는 기능과 같은 편리한 기능을 제공한다.
- 단점
- 테스트없이 문서화가 가능해 로직에 대한 신뢰성을 보장하지 않는다.
- 운영 코드에 문서화 관련 코드가 침투하여 가독성이 떨어진다.
[2] Spring REST DOCS
- 장점
- 테스트를 기반한 문서화이므로 로직의 신뢰성을 보장한다.
- 비즈니스 코드와 문서화 코드를 분리시켜 주기 때문에 코드 가독성을 향상시킬 수 있다.
- 단점
- 커스터마이징에 한계가 있고 문서화에서 제공하는 기능이 제한적이다.
2. Swagger vs Spring Rest Docs
Spring REST Docs 기반하여 Swagger 의 장점을 활용하고 단점을 보완하여 사용할 수 있는 방법을 제공한다. OAS(OpenApi Specification) 을 해석하여 API 문서를 Swager-UI 로 시각화해야 하는데, 독일 기업인 epages 에서 Spring REST Docs 와 연동에 OAS 파일을 생성하는 오픈 소스를 제공한다.
3. 설치 및 적용
[1] restdocs-api-spec library 설정 및 OAS 출력
plugins {
id 'java'
id 'org.springframework.boot' version '3.4.0'
id 'io.spring.dependency-management' version '1.1.6'
id 'org.asciidoctor.jvm.convert' version '3.3.2'
id 'com.epages.restdocs-api-spec' version '0.18.2'
}
group = 'com.cooper'
version = '0.0.1-SNAPSHOT'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
configurations {
asciidoctorExtensions
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
ext {
set('snippetsDir', file("build/generated-snippets"))
}
dependencies {
testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
asciidoctorExtensions 'org.springframework.restdocs:spring-restdocs-asciidoctor'
testImplementation 'com.epages:restdocs-api-spec-mockmvc:0.19.2'
implementation 'org.springdoc:springdoc-openapi-ui:1.8.0'
}
openapi3 {
server = 'http://localhost:8080' // 설정할 서버 URL
title = 'Cooper API' // 문서화 제목
description = 'Cooper API description' // 문서화 설명
version = '0.1.0'
format = 'yaml'
}
tasks.named('test') {
outputs.dir snippetsDir
useJUnitPlatform()
}
tasks.named('asciidoctor') {
configurations 'asciidoctorExtensions'
baseDirFollowsSourceFile()
inputs.dir snippetsDir
dependsOn test
}
bootJar {
from("${asciidoctor.outputDir}") {
into "BOOT-INF/classes/static/docs"
}
from("swagger-ui") {
into "BOOT-INF/classes/static/swagger"
}
from("build/api-spec") {
into "BOOT-INF/classes/static/swagger"
}
dependsOn('openapi3') // openapi3 실행하고 이후에 bootJar 실행
}
[2] Swagger-UI 정적 파일 설치 및 라우팅 설정
(1) 제거 파일

(2) 생성 파일
- 설정된 html swagger-ui.html 파일 (출처 : kurly tech blog)
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI for Spring REST Docs 작성 가이드</title>
<link rel="stylesheet" type="text/css" href="/swagger-ui/swagger-ui.css">
<link rel="icon" type="image/png" href="/swagger-ui/favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="/swagger-ui/favicon-16x16.png" sizes="16x16" />
<style>
html {
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
body {
margin: 0;
background: #fafafa;
}
</style>
</head>
<body>
<div id="swagger-ui"></div>
<script src="/swagger-ui/swagger-ui-bundle.js" charset="UTF-8"> </script>
<script src="/swagger-ui/swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
<script>
window.onload = function () {
// Begin Swagger UI call region
const ui = SwaggerUIBundle({
url: "/swagger/openapi3.yaml",
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
})
// End Swagger UI call region
window.ui = ui
}
</script>
</body>
</html>
(3) 정적 파일 path 설정(Spring Web)
생성/제거한 swagger-ui 관련 파일을 static 디렉토리 하위에 추가한 파일 정적 파일을 라우팅이 가능하도록 설정해야 한다.
ResourceHandlerRegistry 에 기본 정적 파일 경로에 맞게 addResourceHandlers() 를 작성하도록 하자.

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/static/swagger-ui/");
}
}
[3] 테스트 작성하기
MockMvc 환경에서 Spring REST Docs 를 적용하기 위한 공통 코드를 위한 클래스를 작성한다.
@AutoConfigureMockMvc
@AutoConfigureRestDocs
@ExtendWith(RestDocumentationExtension.class)
@SpringBootTest
public class RestDocsDocumentation {
@Autowired
protected MockMvc mockMvc;
@Autowired
protected ObjectMapper objectMapper;
@Autowired
protected WebApplicationContext context;
@BeforeEach
public void setUp(RestDocumentationContextProvider restDocumentation) {
this.mockMvc = MockMvcBuilders
.webAppContextSetup(this.context)
.addFilters(new CharacterEncodingFilter("UTF-8", true))
.apply(documentationConfiguration(restDocumentation)
.operationPreprocessors()
.withRequestDefaults(modifyUris().removePort(), prettyPrint())
.withResponseDefaults(modifyUris().removePort(), prettyPrint()))
.alwaysDo(print())
.build();
}
}
테스트를 기반한 문서화 위한 코드를 작성하도록 한다. 자세하게 봐야할 부분은 coffeeMenuApiResource() 이다. 해당 코드를 살펴보면 swagger 에서 사용하는 tag, summary, description 를 제공한다. 테스트가 성공하면 asciidoc 를 변환한 내용을 bootJar 시점에 컴파일 클래스 파일이 존재하는 BOOT_INF/classes 하위에 swagger-ui 정적 파일과 asciidoc 파일을 이동시켜 API 문서화에 사용된다.
@Sql(value = {"classpath:sql/coffee-menu.sql"})
public class CoffeeDocumentation extends RestDocsDocumentation {
@DisplayName("[성공] 커피 메뉴 조회 문서화")
@Test
void getCoffeeMenuList() throws Exception {
// given, when, then
mockMvc.perform(get("/api/v1/coffee-menu")
.contentType(MediaType.APPLICATION_JSON))
.andExpectAll(
status().is2xxSuccessful(),
jsonPath("$.result").value(ResultType.SUCCESS.name()),
jsonPath("$.data").exists(),
jsonPath("$.error").doesNotExist()
)
.andDo(document("coffee-menu-success", coffeeMenuApiResource()));
}
private ResourceSnippet coffeeMenuApiResource() {
return resource(
ResourceSnippetParameters.builder()
.tag("coffee api")
.summary("커피 메뉴 조회 API")
.description("커피 메뉴 조회 DESCRIPTION")
.requestHeaders(
headerWithName(HttpHeaders.CONTENT_TYPE).description("컨텐츠 타입"))
.responseFields(
fieldWithPath("result").type(JsonFieldType.STRING).description("응답 결과"),
fieldWithPath("data[0].id").type(JsonFieldType.NUMBER).description("커피 메뉴 아이디"),
fieldWithPath("data[0].name").type(JsonFieldType.STRING).description("커피 메뉴 이름"),
fieldWithPath("data[0].price").type(JsonFieldType.NUMBER).description("커피 메뉴 가격"),
fieldWithPath("error").type(JsonFieldType.NULL).description("에러 정보"))
.build());
}
}
[4] 실행 화면 확인하기
swagger 문서화는 build 를 한 bootJar 파일을 실행시킬 때만 동작한다. build task 로 등록한 openapi3 task 가 작업이 완료되면 openapi3.yaml 을 생성하는데 bootJar 파일에 추가되기 때문이다. 그러므로 꼭 java -jar 명령어를 통해서 실행하도록 하자.
java -jar build/libs/cafe-order-0.0.1-SNAPSHOT.jar
실행된 결과를 이전에 설정한 URL 을 통해서 결과를 확인해보면 정상적으로 출력한 것을 확인할 수 있다.
http://localhost:8080/swagger-ui.html

4. Reference
'spring > summary' 카테고리의 다른 글
ShedLock 으로 하나의 스케줄링만 실행하기 (0) | 2025.01.16 |
---|---|
비관적 락 vs 낙관적 락(In JPA) (0) | 2024.11.28 |
MessageSourceAutoConfiguration 코드 검토하기 (0) | 2024.11.28 |
[kurly tech blog] Redisson, Spring AOP 기반 분산락 적용 방법 summary (0) | 2024.11.26 |
Spring Batch 기반 회원 삭제 배치 삽질 기록 (0) | 2024.09.03 |
1. Swagger vs Spring Rest Docs
[1] Swagger
- 장점
- UI 가 깔끔하고 문서화를 사용하기 편리하다.
- 테스트 해볼 수 있는 기능과 같은 편리한 기능을 제공한다.
- 단점
- 테스트없이 문서화가 가능해 로직에 대한 신뢰성을 보장하지 않는다.
- 운영 코드에 문서화 관련 코드가 침투하여 가독성이 떨어진다.
[2] Spring REST DOCS
- 장점
- 테스트를 기반한 문서화이므로 로직의 신뢰성을 보장한다.
- 비즈니스 코드와 문서화 코드를 분리시켜 주기 때문에 코드 가독성을 향상시킬 수 있다.
- 단점
- 커스터마이징에 한계가 있고 문서화에서 제공하는 기능이 제한적이다.
2. Swagger vs Spring Rest Docs
Spring REST Docs 기반하여 Swagger 의 장점을 활용하고 단점을 보완하여 사용할 수 있는 방법을 제공한다. OAS(OpenApi Specification) 을 해석하여 API 문서를 Swager-UI 로 시각화해야 하는데, 독일 기업인 epages 에서 Spring REST Docs 와 연동에 OAS 파일을 생성하는 오픈 소스를 제공한다.
3. 설치 및 적용
[1] restdocs-api-spec library 설정 및 OAS 출력
plugins {
id 'java'
id 'org.springframework.boot' version '3.4.0'
id 'io.spring.dependency-management' version '1.1.6'
id 'org.asciidoctor.jvm.convert' version '3.3.2'
id 'com.epages.restdocs-api-spec' version '0.18.2'
}
group = 'com.cooper'
version = '0.0.1-SNAPSHOT'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
configurations {
asciidoctorExtensions
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
ext {
set('snippetsDir', file("build/generated-snippets"))
}
dependencies {
testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
asciidoctorExtensions 'org.springframework.restdocs:spring-restdocs-asciidoctor'
testImplementation 'com.epages:restdocs-api-spec-mockmvc:0.19.2'
implementation 'org.springdoc:springdoc-openapi-ui:1.8.0'
}
openapi3 {
server = 'http://localhost:8080' // 설정할 서버 URL
title = 'Cooper API' // 문서화 제목
description = 'Cooper API description' // 문서화 설명
version = '0.1.0'
format = 'yaml'
}
tasks.named('test') {
outputs.dir snippetsDir
useJUnitPlatform()
}
tasks.named('asciidoctor') {
configurations 'asciidoctorExtensions'
baseDirFollowsSourceFile()
inputs.dir snippetsDir
dependsOn test
}
bootJar {
from("${asciidoctor.outputDir}") {
into "BOOT-INF/classes/static/docs"
}
from("swagger-ui") {
into "BOOT-INF/classes/static/swagger"
}
from("build/api-spec") {
into "BOOT-INF/classes/static/swagger"
}
dependsOn('openapi3') // openapi3 실행하고 이후에 bootJar 실행
}
[2] Swagger-UI 정적 파일 설치 및 라우팅 설정
(1) 제거 파일

(2) 생성 파일
- 설정된 html swagger-ui.html 파일 (출처 : kurly tech blog)
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI for Spring REST Docs 작성 가이드</title>
<link rel="stylesheet" type="text/css" href="/swagger-ui/swagger-ui.css">
<link rel="icon" type="image/png" href="/swagger-ui/favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="/swagger-ui/favicon-16x16.png" sizes="16x16" />
<style>
html {
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
body {
margin: 0;
background: #fafafa;
}
</style>
</head>
<body>
<div id="swagger-ui"></div>
<script src="/swagger-ui/swagger-ui-bundle.js" charset="UTF-8"> </script>
<script src="/swagger-ui/swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
<script>
window.onload = function () {
// Begin Swagger UI call region
const ui = SwaggerUIBundle({
url: "/swagger/openapi3.yaml",
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
})
// End Swagger UI call region
window.ui = ui
}
</script>
</body>
</html>
(3) 정적 파일 path 설정(Spring Web)
생성/제거한 swagger-ui 관련 파일을 static 디렉토리 하위에 추가한 파일 정적 파일을 라우팅이 가능하도록 설정해야 한다.
ResourceHandlerRegistry 에 기본 정적 파일 경로에 맞게 addResourceHandlers() 를 작성하도록 하자.

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/static/swagger-ui/");
}
}
[3] 테스트 작성하기
MockMvc 환경에서 Spring REST Docs 를 적용하기 위한 공통 코드를 위한 클래스를 작성한다.
@AutoConfigureMockMvc
@AutoConfigureRestDocs
@ExtendWith(RestDocumentationExtension.class)
@SpringBootTest
public class RestDocsDocumentation {
@Autowired
protected MockMvc mockMvc;
@Autowired
protected ObjectMapper objectMapper;
@Autowired
protected WebApplicationContext context;
@BeforeEach
public void setUp(RestDocumentationContextProvider restDocumentation) {
this.mockMvc = MockMvcBuilders
.webAppContextSetup(this.context)
.addFilters(new CharacterEncodingFilter("UTF-8", true))
.apply(documentationConfiguration(restDocumentation)
.operationPreprocessors()
.withRequestDefaults(modifyUris().removePort(), prettyPrint())
.withResponseDefaults(modifyUris().removePort(), prettyPrint()))
.alwaysDo(print())
.build();
}
}
테스트를 기반한 문서화 위한 코드를 작성하도록 한다. 자세하게 봐야할 부분은 coffeeMenuApiResource() 이다. 해당 코드를 살펴보면 swagger 에서 사용하는 tag, summary, description 를 제공한다. 테스트가 성공하면 asciidoc 를 변환한 내용을 bootJar 시점에 컴파일 클래스 파일이 존재하는 BOOT_INF/classes 하위에 swagger-ui 정적 파일과 asciidoc 파일을 이동시켜 API 문서화에 사용된다.
@Sql(value = {"classpath:sql/coffee-menu.sql"})
public class CoffeeDocumentation extends RestDocsDocumentation {
@DisplayName("[성공] 커피 메뉴 조회 문서화")
@Test
void getCoffeeMenuList() throws Exception {
// given, when, then
mockMvc.perform(get("/api/v1/coffee-menu")
.contentType(MediaType.APPLICATION_JSON))
.andExpectAll(
status().is2xxSuccessful(),
jsonPath("$.result").value(ResultType.SUCCESS.name()),
jsonPath("$.data").exists(),
jsonPath("$.error").doesNotExist()
)
.andDo(document("coffee-menu-success", coffeeMenuApiResource()));
}
private ResourceSnippet coffeeMenuApiResource() {
return resource(
ResourceSnippetParameters.builder()
.tag("coffee api")
.summary("커피 메뉴 조회 API")
.description("커피 메뉴 조회 DESCRIPTION")
.requestHeaders(
headerWithName(HttpHeaders.CONTENT_TYPE).description("컨텐츠 타입"))
.responseFields(
fieldWithPath("result").type(JsonFieldType.STRING).description("응답 결과"),
fieldWithPath("data[0].id").type(JsonFieldType.NUMBER).description("커피 메뉴 아이디"),
fieldWithPath("data[0].name").type(JsonFieldType.STRING).description("커피 메뉴 이름"),
fieldWithPath("data[0].price").type(JsonFieldType.NUMBER).description("커피 메뉴 가격"),
fieldWithPath("error").type(JsonFieldType.NULL).description("에러 정보"))
.build());
}
}
[4] 실행 화면 확인하기
swagger 문서화는 build 를 한 bootJar 파일을 실행시킬 때만 동작한다. build task 로 등록한 openapi3 task 가 작업이 완료되면 openapi3.yaml 을 생성하는데 bootJar 파일에 추가되기 때문이다. 그러므로 꼭 java -jar 명령어를 통해서 실행하도록 하자.
java -jar build/libs/cafe-order-0.0.1-SNAPSHOT.jar
실행된 결과를 이전에 설정한 URL 을 통해서 결과를 확인해보면 정상적으로 출력한 것을 확인할 수 있다.
http://localhost:8080/swagger-ui.html

4. Reference
'spring > summary' 카테고리의 다른 글
ShedLock 으로 하나의 스케줄링만 실행하기 (0) | 2025.01.16 |
---|---|
비관적 락 vs 낙관적 락(In JPA) (0) | 2024.11.28 |
MessageSourceAutoConfiguration 코드 검토하기 (0) | 2024.11.28 |
[kurly tech blog] Redisson, Spring AOP 기반 분산락 적용 방법 summary (0) | 2024.11.26 |
Spring Batch 기반 회원 삭제 배치 삽질 기록 (0) | 2024.09.03 |