문제 상황
Swagger 도입 전 기존 상황은 다음과 같다:
- FE와의 협업을 위한 API 명세서 필요함
- API 개발 전 Mocking 툴로 Postman을 사용 중
- Postman은 동시 작업이 어렵고 휴먼 에러가 발생할 가능성이 높음
이로 인해 API 문서 작성 툴 변경이 필요했고, 이를 위한 고려 사항은 다음과 같았다:
- 실제 작성된 API 기반으로 자동 업데이트가 가능한 명세서가 필요함
제안
Swagger
- API 작성 시, 의존성 및 관련 Annotation을 추가해 Swagger 문서로 API 명세서 제공
장단점
장점
- 자동화된 문서화 API문서를 자동으로 생성해주기 때문에 개발자가 일일이 문서를 작성할 필요 없음
- 시각적 인터페이스 Swagger UI를 통해 API를 시각적으로 테스트하고 탐색이 가능함
- 표준화 OpenAPI Specification(OAS)을 사용하여 API 문서화를 표준화
- → 다른 팀이나 회사에서도 쉽게 이해하고 사용 가능
- API 테스트 Swagger UI를 통해 API를 직접 호출하고 테스트 할 수 있음
단점
- 추가 리소스
- Swagger를 사용하기 위해 추가적으로 해야할 설정이 있음
- 오버헤드 Swagger를 사용하면 API 문서화와 관련된 추가 코드와 설정이 필요해지기 때문에 프로젝트 규모가 커질수록 관리가 복잡해질 수 있음
대안
- 대안1: Postman 사용 유지
- 대안2: Mockoon [Mockoon](https://www.notion.so/Mockoon-1db3550b7b5581ebb2c9d27e0f4c7ac3?pvs=21)
- 대안3: Mock Service Worker(MSW) (잘 사용되지 않음) [Mock Service Worker(MSW)](https://www.notion.so/Mock-Service-Worker-MSW-1db3550b7b55818699b0cdc990f29292?pvs=21)
- 대안4: Spring으로 직접 구현하기 (잘 사용되지 않음) Spring으로 직접 구현하기
최종 채택 및 차후 과제
- 채택 - Swagger 설정 및 사용법
- 의존성 추가 (3.0.0버전을 사용할겁니다. 참고로 예전에는 springfox를 사용했는데, 유지보수가 중단돼서 잘 안쓴다고 합니다!) OpenAPI 3.x 명세를 사용할 예정입니다.문법에 따라 Swagger을 어떻게 사용할건지 달라지므로 참고해주세요
- springdoc-openapi-starter-webmvc-ui: Spring MVC 환경에서 OpenAPI 명세 생성 기능과 Swagger UI 포함. springdoc-openapi-starter-webmvc-api: Spring MVC 환경에서 OpenAPI 명세 생성 기능만 (Swagger UI 제외). springdoc-openapi-starter-webflux-ui: Spring WebFlux 환경에서 OpenAPI 명세 생성 기능과 Swagger UI 포함.
- dependencies { // SpringDoc OpenAPI Starter (Swagger UI 포함) implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.5' // Spring Boot 2.x 이하 버전에서는 // implementation 'org.springdoc:springdoc-openapi-ui:1.x.x' // 형태의 의존성을 사용할 수 있습니다. // 만약 Kotlin이나 WebFlux를 사용한다면 의존성 이름이 다를 수 있습니다. }
- 기본 설정 세팅 (SwaggerConfig.java 파일 생성) SwaggerConfig.java에서 작성하거나 application.yml에 작성하는 방법이 있는데, 보통은 전자를 많이 사용하더라구요. 두가지 버전을 따로 분리해서 쓰겠습니다.2.1. application.yml에서 기본 설정 세팅 (선택 사항)
- # application.yml # Swagger UI 접속 경로 설정 (기본값: /swagger-ui/index.html) # springdoc.swagger-ui.path=/swagger-ui.html # 다른 경로로 바꾸고 싶다면 설정 (예시) # OpenAPI 명세 파일 경로 설정 (기본값: /v3/api-docs) # springdoc.api-docs.path=/v3/api-docs # 다른 경로로 바꾸고 싶다면 설정 (예시) # API 정보 설정 (Swagger UI 상단에 표시됨) springdoc.info.title="Swagger 연습용 Board API Document" springdoc.info.version="0.0.1" springdoc.info.description="Swagger 연습용 게시판 API 명세서입니다." # 연락처 정보 등 추가 가능: # springdoc.info.contact.name=팀 이름 # springdoc.info.contact.email=팀 이메일
- import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.info.Info; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class SwaggerConfig { @Bean public OpenAPI openAPI() { Info info = new Info() .title("Swagger 연습용 Board API Document") .version("v0.0.1") .description("Swagger 연습용 게시판 API 명세서입니다."); return new OpenAPI() .components(new Components()) .info(info); } }
- Controller에서 예시 작성 (Dto도 넣어 설명하겠습니다.)*** 주요 어노테이션 설명**
- @Tag API 엔드포인트를 그룹화하는데 사용합니다.
- @Operation API 메서드에 대한 문서화 정보를 제공합니다. 메서드의 설명, 요청/응답 모델, 파라미터 등을 지정할 수 있습니다.
- @ApiResponses Swagger에서 API 메서드의 응답 정보를 문서화하는 데 사용되는 주석(Annotation)입니다.
- @Schema API 모델의 속성(property)에 대한 상세한 정보를 제공해줌
- @Hidden API 요소를 Swagger UI에 표시하지 않게 만들어줌 (API 문서에서 제외 됨)
- import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.parameters.RequestBody; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/api/v1/example") @Tag(name = "예시 API", description = "Swagger UI 예시를 위한 API") // Tag 추가 public class ExampleController { @Operation( summary = "사용자 정보 조회", // API 요약 description = "주어진 사용자 ID에 해당하는 사용자 정보를 조회합니다.", // 상세 설명 responses = { // 응답 정의 @ApiResponse(responseCode = "200", description = "사용자 정보 조회 성공", content = @Content(schema = @Schema(implementation = UserResponseDto.class))), // 성공 응답 (200) @ApiResponse(responseCode = "404", description = "사용자를 찾을 수 없음") // 실패 응답 (404) } ) @GetMapping("/{userId}") public ResponseEntity<UserResponseDto> getUserByUserId( @Parameter(description = "조회할 사용자의 ID", required = true, example = "1") // 파라미터 설명 및 예시 @PathVariable Long userId) { // ... 사용자 조회 로직 if (userId == 1L) { return ResponseEntity.ok(new UserResponseDto("user1", "User One")); } else { return ResponseEntity.notFound().build(); } } @Operation( summary = "새 사용자 생성", description = "새로운 사용자 정보를 생성합니다.", responses = { @ApiResponse(responseCode = "201", description = "사용자 생성 성공"), // 201 Created @ApiResponse(responseCode = "400", description = "잘못된 요청 본문") // 400 Bad Request } ) @PostMapping public ResponseEntity<Void> createUser( @RequestBody(description = "생성할 사용자 정보 (JSON)", required = true) // 요청 본문 설명 CreateUserRequestDto request) { // ... 사용자 생성 로직 System.out.println("Received user: " + request.getUsername()); return ResponseEntity.status(201).build(); // 201 상태 코드 반환 } } // 요청 DTO 예시 @Schema(description = "새 사용자 생성 요청 DTO") // DTO에 Schema 추가 class CreateUserRequestDto { @Schema(description = "사용자 이름", example = "testuser", required = true) // 필드 설명, 예시, 필수 여부 private String username; @Schema(description = "닉네임", example = "테스터") private String nickname; // Getter, Setter public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getNickname() { return nickname; } public void setNickname(String nickname) { this.nickname = nickname; } } // 응답 DTO 예시 @Schema(description = "사용자 정보 응답 DTO") // DTO에 Schema 추가 class UserResponseDto { @Schema(description = "사용자 ID", example = "user123") private String userId; @Schema(description = "사용자 닉네임", example = "테스터") private String nickname; // Constructor, Getter public UserResponseDto(String userId, String nickname) { this.userId = userId; this.nickname = nickname; } public String getUserId() { return userId; } public String getNickname() { return nickname; } }
- Swagger Ui에서 직접 확인하기 애플리케이션 실행 후 http://localhost:8080/swagger-ui.html에서 확인하면 아래와 같이 API 명세서를 확인해보실 수 있습니다. (예시 이미지)
출처
https://www.youtube.com/watch?v=akbdsrOpQ60
https://www.youtube.com/watch?v=ARi-cXdIIj8
https://www.youtube.com/watch?v=Q27PGBYmHNA
https://velog.io/@wjd15sheep/Swagger-설정-및-사용방법
https://kim-jong-hyun.tistory.com/49
https://sharplee7.tistory.com/48
https://baby9235.tistory.com/133
https://baby9235.tistory.com/138
- 차후 과제
- 실제 API를 테스트해볼 수 있도록 개발 서버 배포
'kkokkio - 프로젝트 > ADR(의사결정문서)' 카테고리의 다른 글
Airflow (0) | 2025.06.11 |
---|---|
Flyway (1) | 2025.06.11 |
MySQL (0) | 2025.06.11 |
Spring Security + JWT (0) | 2025.06.11 |
Terraform 도입 (0) | 2025.06.02 |