Swagger 알아보고 제대로 써보기

백엔드와 프론트엔드 사이의 원활한 협업을 위해서는 API 명세에 대한 문서화가 필수적이다. 노션 등의 툴을 이용해 직접 API 문서를 작성할 수도 있지만 항상 API 문서를 수정하는 일은 번거롭다. 그래서 우리는 API 문서화 자동화 도구를 이용한다.

자바 진영에서 가장 많이 사용되는 API 문서화 자동화 도구는 대표적으로 두가지가 존재한다.

위 두 도구의 특성과 장단점을 알아보자.

Swagger VS Spring REST Docs

결론부터 말하자면 Swagger는 Spring REST Docs보다 작성하기 쉽지만, 두 가지 단점이 있다.

[Swagger의 단점]

  1. 코드 상에 API 관련한 애노테이션을 추가해야 해서 코드 가독성이 떨어진다.
  2. API 스펙 변경이 일어날 때, 애노테이션 변경이 필요하다. 즉, 문서와 API 스펙이 일치함을 보장해주지 않는다.

장점은 다음과 같다.

[Swagger의 장점]

  1. API 문서에서 동적으로 API를 조작할 수 있다.
  2. Spring REST Docs를 테스트를 통해 API 스펙과 문서가 일치하도록 강제한다. 하지만 Swagger는 애노테이션만 추가하면 되므로 API 문서를 위해 작성해야 하는 코드양이 적다. (하지만 테스트 작성을 강제하는 것이 오히려 품질에 좋은 결과를 낳는다.)

장단점을 살펴보면 Spring REST Docs가 코드의 품질 면에서 뛰어난 것은 사실이다. 하지만 현재 우리의 프로젝트는 남은 시간이 많지 않고 프론트엔드의 빠른 작업이 우선되어야 하기 때문에 Swagger를 선택하고 추후 Spring REST Docs로 마이그레이션하기로 결정했다.

OAS란?

OAS란 OpenAPI Specification의 약자로 REST API의 명세에 대한 표준이다. OAS의 표준은 REST API 명세를 yml형식을 이용해 표현한다. 다음 공식 문서를 통해 실제 REST API의 명세가 어떻게 yml형식으로 표현되는지 확인할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
openapi: 3.0.0
info:
  version: 1.0.0
  title: Sample API
  description: A sample API to illustrate OpenAPI concepts
paths:
  /list:
    get:
      description: Returns a list of stuff              
      responses:
        '200':
          description: Successful response

위와 같은 형식으로 yml파일을 작성할 수 있다.

이를 Swagger Editor에서 Try Swagger Editor를 눌러 확인해보면 yml형식을 어떻게 Swagger가 문서화 시키는지 볼 수 있다.

결국 OpenAPI Spec으로 작성된 문서를 Swagger가 보기 좋게 뿌려주는 것이다.

Swagger의 구성

Swagger는 세 가지 툴로 구성되어있다.

  • Swagger Codegen : OpenAPI spec 에 맞게 Server 나 Client 의 stub code 를 생성해 준다. 개발자는 생성된 코드에 비즈니스 로직에 집중해서 구현하면 된다.
  • Swagger Editor : 브라우저 기반의 편집기로 OpenAPI spec 을 쉽게 작성할 수 있도록 도와준다.
  • Swagger UI : OpenAPI Spec으로 작성된 yml문서를 브라우저에서 보기 좋게 html로 표시할 수 있게 해준다.

결국 우리는 OpenAPI spec으로 yml파일을 쉽게 작성해주고 Swagger UI를 통해 API 문서를 보기좋게 표시하고 싶다. 그리고 Swagger는 swagger-core를 통해 자바의 애노테이션을 쉽게 OpenAPI Spec 형식의 yml로 변환할 수 있도록 지원하고 있다.

이 과정을 손쉽게 할 수 있도록 개발자들은 이미 툴을 개발해 놓았다.

위의 두 라이브러리이다. 하지만 springfox는 2020년 이후로 업데이트를 중지한 상태이다. springdoc을 사용하는 것이 나은 선택이라고 보인다. 또한 springdoc이 OpenAPI 3를 잘 지원하고 있다.

springdoc-openapi 공식문서를 살펴보면 swagger-core와 swagger-ui가 적용된 것을 볼 수 있다.

이제 springdoc-openapi를 실제로 프로젝트에 적용해 보자.

Swagger 프로젝트 만들기

프로젝트 생성

가장 먼저 spring security와 MVC를 포함한 간단한 springboot 프로젝트를 만들어 보자.

start.spring.io에서 다음과 같이 간단히 프로젝트를 생성한다.

springdoc-openapi 공식문서를 보면 spring-boot v3 이상을 사용하는 경우 springdoc-openapi-starter-webmvc-ui 를 사용해야 한다고 한다.

따라서 springdoc-openapi-starter-webmvc-ui 디펜던시를 build.gradle에 추가한다. dependency 버전 확인은 mvnrepository에서 확인하면 된다. 나는 작성일 기준 가장 최신 버전인 2.1.0버전을 추가했다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
plugins {  
   id 'java'  
   id 'org.springframework.boot' version '3.1.1'  
   id 'io.spring.dependency-management' version '1.1.0'  
}  
  
group = 'com.dukcode'  
version = '0.0.1-SNAPSHOT'  
  
java {  
   sourceCompatibility = '17'  
}  
  
repositories {  
   mavenCentral()  
}  
  
dependencies {  
   implementation 'org.springframework.boot:spring-boot-starter-security'  
   implementation 'org.springframework.boot:spring-boot-starter-web'
   
   // dependency 추가
   implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.1.0'
   
   testImplementation 'org.springframework.boot:spring-boot-starter-test'  
   testImplementation 'org.springframework.security:spring-security-test'  
}  
  
tasks.named('test') {  
   useJUnitPlatform()  
}

위와 같이 간단히 추가할 수 있다.

Spring Security 설정

Spring Security를 추가한 이유는 우리가 프로젝트를 진행하며 Spring Security를 자주 사용하기 때문이다. Spring Security는 default 값으로 모든 요청에 대해 인증을 요구한다. 따라서 Swagger 관련한 URL에 대한 요청에 대해 인증 절차를 요구하지 않도록 변경해주어야 Swagger 관련 URL에 접근할 수 있게 된다.

먼저 SecurityConfig 클래스를 다음과 같이 만들어 준다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

        http
            .authorizeHttpRequests((auth) -> auth
            .requestMatchers("/error").permitAll()
            .requestMatchers("/swagger-ui.html", "/swagger-ui/**", "/v3/api-docs/**").permitAll()
            .anyRequest().authenticated());

        return http.build();
    }
}

Spring Security의 권한 설정 클래스이다. /swagger-ui.html, /swagger-ui/**, /v3/api-docs의 세가지 Swagger 관련 URL들을 permitAll() 설정해준다.

프로젝트를 다시 실행시키고 /swagger-ui.html로 접근하면 /swagger-ui/index.html로 리다이렉트되며 다음과 같은 화면을 볼 수 있게 된다.

실제로 /swagger-ui/index.html의 코드를 확인해 보면 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Swagger UI</title>
    <link rel="stylesheet" type="text/css" href="./swagger-ui.css" />
    <link rel="stylesheet" type="text/css" href="index.css" />
    <link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
    <link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
  </head>

  <body>
    <div id="swagger-ui"></div>
    <script src="./swagger-ui-bundle.js" charset="UTF-8"> </script>
    <script src="./swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
    <script src="./swagger-initializer.js" charset="UTF-8"> </script>
  </body>
</html>

css, ico, png, js등의 다양한 파일을 요청한다. 따라서 /swagger-ui/ 하위의 URL에 대한 처리를 해준 것이다.

또한 Swagger 화면에서 /v3/api-docs/의 하위 URL에 대한 정보도 요청해야 하므로 하위 URL에 대한 처리도 해주었다.

Controller 추가

이제 간단한 컨트롤러를 추가해보자.

1
2
3
4
5
6
7
8
9
@RestController
public class HelloController {

	@GetMapping("/hello")
	public String hello() {
		return "hello";
	}
}

이제 프로젝트를 다시 빌드하고 /swagger-ui.html로 접근하면 다음과 같은 화면을 볼 수 있다.

이제 API를 추가할 때 마다 Swagger가 인식해서 보여준다. 하지만 아직 추가적인 설명이 부족하다. 애노테이션을 추가해 좀 더 풍성한 API 문서를 만들어보자.

Swagger 2.X Annotation

Swagger 애노테이션을 추가해 API 문서에 추가적인 설명을 추가할 수 있다. Swagger 2.X Annotation에서 어떤 애노테이션을 사용할 수 있는지 확인할 수 있다. 예시와 함께 정리되어 있으니 쉽게 익힐 수 있다. 추후 API 문서를 작성하면서 예시를 작성해 볼 예정이다.

댓글남기기