01_Swagger
📍 Swagger
코드의 어노테이션을 기반으로 API 문서 자동 생성하고 웹 화면에서 API를 직접 호출해볼 수 있는 도구
Spring Boot 3.x에서는 Springdoc OpenAPI 라이브러리 사용해 자동으로 OpenAPI 문서 생성
동작 방식
- 브라우저가 /swagger-ui/index.html을 요청한다.
- Swagger UI 페이지가 로드되면서 내부적으로 /v3/api-docs를 호출해 OpenAPI 명세를 가져온다.
- 명세를 기반으로 API 목록을 화면에 그린다.
02_SpringBoot에 Swagger 적용
📍 의존성 추가
Spring Boot 3.x에서는 springdoc-openapi-starter-webmvc-ui 를 사용
build.gradle
dependencies {
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.17'
}
의존성을 추가하기만 해도 swagger로 접속 가능
- Swagger UI: http://localhost:8080/swagger-ui/index.html
application.yml
springdoc:
swagger-ui:
path: /swagger-ui.html # 기본 경로 커스텀
operations-sorter: method # API를 HTTP 메서드 순으로 정렬
tags-sorter: alpha # 태그를 알파벳 순으로 정렬
display-request-duration: true # 요청 처리 시간 표시
api-docs:
path: /v3/api-docs
default-consumes-media-type: application/json
default-produces-media-type: application/json
운영 환경에서는 보안상 Swagger UI를 노출하지 않는 것이 안전하다.
yamlspringdoc:
api-docs:
enabled: false
swagger-ui:
enabled: false
📍 SwaggerConfig
API 문서의 제목, 설명, 버전 등의 메타 정보를 설정하기 위해 OpenAPI Bean 구성
@Configuration
public class SwaggerConfig {
@Bean
public OpenAPI openAPI() {
Info info = new Info()
.title("Test API")
.description("Test API 명세서입니다.")
.version("v1")
.contact(new Contact()
.name("홍길동")
.email("hong@example.com"));
Server localServer = new Server()
.url("")
.description("로컬 개발 서버");
Server prodServer = new Server()
.url("<https://api.example.com>")
.description("운영 서버");
return new OpenAPI()
.info(info)
.servers(List.of(localServer, prodServer));
}
}
JWT 인증
SecurityScheme 설정하면 Swagger에서 Authorization 헤더에 JWT 토큰을 자동으로 포함시킬 수 있음
보안 스킴은 API가 어떤 인증 방식을 사용하는지 설명하는 설정
@Configuration
public class SwaggerConfig {
private static final String SECURITY_SCHEME_NAME = "BearerAuth";
@Bean
public OpenAPI openAPI() {
SecurityScheme securityScheme = new SecurityScheme()
.type(SecurityScheme.Type.HTTP)
.scheme("bearer")
.bearerFormat("JWT")
.in(SecurityScheme.In.HEADER)
.name("Authorization");
SecurityRequirement securityRequirement = new SecurityRequirement()
.addList(SECURITY_SCHEME_NAME);
return new OpenAPI()
.info(new Info()
.title("Test API")
.description("Test API 명세서입니다."))
.components(new Components()
.addSecuritySchemes(SECURITY_SCHEME_NAME, securityScheme))
.addSecurityItem(securityRequirement);
}
}
🔍 코드 설명
- SecurityScheme
- 인증 타입: HTTP
- 인증 방식: Bearer
- 토큰 형식: JWT
- 전달 위치: Header
- 헤더 이름: Authorization
- addSecuritySchemes(SECURITY_SCHEME_NAME, securityScheme): "BearerAuth"라는 이름으로 보안 스킴 등록
→ Swagger UI 우측 상단의 자물쇠 버튼을 누르고 JWT 토큰을 입력하면, 이후 모든 API 호출에 Authorization: Bearer {token} 헤더가 자동으로 포함
📍 API 문서화 어노테이션
| 어노테이션 | 용도 | 적용 위치 |
| @Tag | API 그룹 묶기 | 클래스/인터페이스 |
| @Operation | 개별 API의 요약과 설명 | 메서드 |
| @ApiResponses | 여러 응답 코드 정의 | 메서드 |
| @ApiResponse | 단일 응답 코드 정의 | @ApiResponses 내부 |
| @Parameter | 파라미터 설명 | 파라미터 |
| @Schema | DTO 필드 설명 | DTO 필드 |
| @RequestBody | 요청 본문 설명 | 파라미터 |
API 명세 인터페이스
컨트롤러에 Swagger 어노테이션을 직접 붙이면 코드 복잡
API 명세를 인터페이스로 분리하면 컨트롤러는 비즈니스 로직에만 집중 가능
@Tag(name = "User", description = "사용자 관련 API")
public interface UserApi {
@Operation(
summary = "사용자 단건 조회",
description = "ID를 기준으로 사용자 정보를 조회한다."
)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "조회 성공"),
@ApiResponse(responseCode = "404", description = "사용자를 찾을 수 없음")
})
BaseResponse<UserDto> getUser(
@Parameter(description = "사용자 ID", example = "1") Long id
);
}
🔍 코드 설명
- @Tag: 같은 태그를 가진 API들이 하나의 그룹으로 묶임
- @Operation(summary, description): API의 요약과 상세 설명 제공
- @ApiResponses: 발생 가능한 응답 코드들을 명시
- @Parameter: 파라미터의 의미와 예시 제공
Controller
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/users")
public class UserController implements UserApi {
private final UserService userService;
@Override
@GetMapping("/{id}")
public BaseResponse<UserDto> getUser(@PathVariable Long id) {
return BaseResponse.ok(userService.findById(id));
}
}
DTO
import io.swagger.v3.oas.annotations.media.Schema;
@Schema(description = "사용자 생성 요청")
public record UserCreateDto(
@Schema(description = "사용자 이름", example = "홍길동")
String name,
@Schema(description = "이메일", example = "hong@example.com")
String email,
@Schema(description = "나이", example = "23", minimum = "0")
Integer age
) { }
🔍 코드 설명
- @Schema: DTO의 필드 설명
- example: Swagger UI의 "Try it out" 기능에서 예시 값이 자동으로 채워짐
03_트러블슈팅
📍 Spring Security 적용 시 Swagger UI가 안 뜸
회원가입 기능 구현 도중에 Spring Security 의존성을 추가했더니 Swagger UI에서 401 Unauthorized가 뜨는 문제가 발생했다.
원인
Spring Security를 추가하면 모든 HTTP 요청에 인증을 요구하는 것이 기본
별도로 설정하지 않으면 Swagger 관련 경로도 모두 인증 대상이 됨
→ Swagger 관련 경로를 인증 예외 처리
해결 방법
- SecurityFilterChain에서 경로 허용
SecurityFilterChain Bean 구성할 때 Swagger 관련 경로를 permitAll()로 처리한다.
@Configuration
@EnableWebSecurity
public class SecurityConfig {
private static final String[] SWAGGER_WHITELIST = {
"/swagger-ui/**",
"/v3/api-docs/**"
};
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(auth -> auth
.requestMatchers(SWAGGER_WHITELIST).permitAll()
.requestMatchers("/health-check").permitAll()
.anyRequest().authenticated()
);
return http.build();
}
}
🔍 코드 설명
- /swagger-ui/**: Swagger UI 정적 리소스 (HTML, JS, CSS)
- /v3/api-docs/**: OpenAPI 명세 JSON
- requestMatchers(...).permitAll(): 이 경로들은 인증 없이 접근 허용
'Back-end > SpringBoot' 카테고리의 다른 글
| [Spring Boot] Redis 설치 및 연동 (1) | 2026.06.29 |
|---|---|
| [Spring Boot] 헬스 체크(Health Check) 구현 (0) | 2026.06.26 |
| [Spring Boot] 공통 응답 처리 구현 (0) | 2026.06.26 |
| [Spring Boot] 공통 예외처리 구현 - CustomException, GlobalExceptionHandler (0) | 2026.06.25 |
| [Spring Boot] JPA Auditing으로 BaseTimeEntity 구현 (0) | 2026.06.25 |