Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- programmers
- 알고리즘
- 이분탐색
- 브루트포스
- Network
- BFS
- switch
- Spring
- 구현
- 백준
- HashMap
- 네트워크
- 해시
- Backtracking
- DynamicProgramming
- 너비우선탐색
- 동적계획법
- 스프링
- broadcast
- DP
- greedy
- Algorithm
- boj
- dynamic programming
- DFS
- 그리디
- 해시맵
- 프로그래머스
- 백트래킹
- 깊이우선탐색
Archives
- Today
- Total
옌의 로그
[Spring] Swagger에서 ErrorCode Enum 자동화하기 본문
1. 구현 배경
client 개발자들과 협업하며, api 마다 발생할 수 있는 에러 응답에 대해 ui로 편하게 볼 수 있게 할 목적으로 작업하게 되었다.
Swagger config 빈이 생성될 때 OperationCustomizer가 동작해 자동으로 ErrorType enum을 읽어와 각 API에 해당하는 에러 코드 예시를 자동 등록하고, UI에서 보기 쉽게 표시하는 구조를 만들게 되었다.
2. 에러 코드는 관리
에러 코드는 다음과 같이 enum으로 정의했다.
public enum ErrorType {
INVALID_PARAMETER(HttpStatus.BAD_REQUEST, 1001, "잘못된 요청입니다."),
UNAUTHORIZED(HttpStatus.UNAUTHORIZED, 1002, "인증이 필요합니다."),
PRODUCT_NOT_FOUND(HttpStatus.NOT_FOUND, 2001, "상품을 찾을 수 없습니다."),
INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, 9999, "알 수 없는 서버 오류입니다.");
private final HttpStatus status;
private final int code;
private final String message;
// ... getter 생략
}
3. 각 API에서 발생 가능한 에러 지정
각 API 메서드에는 커스텀 애너테이션을 활용했다.
@ApiErrorCodeExample({ErrorType.INVALID_PARAMETER, ErrorType.PRODUCT_NOT_FOUND})
@GetMapping("/products/{id}")
public ResponseEntity<ProductResponse> getProduct(@PathVariable Long id) {
...
}
이렇게 하면 Swagger 설정 클래스에서 해당 애너테이션을 읽어 자동으로 해당 API의 에러 예시를 구성할 수 있다.
4. SwaggerConfig 설정
SwaggerConfig의 주요 흐름
- 모든 API 요청에 대해 Swagger Operation 커스터마이저가 동작
- @ApiErrorCodeExample에 지정된 에러 타입을 읽음
@Bean
public OperationCustomizer customize() {
return (Operation operation, HandlerMethod handlerMethod) -> {
ApiErrorCodeExample apiErrorCodeExample = handlerMethod.getMethodAnnotation(ApiErrorCodeExample.class);
if (apiErrorCodeExample != null) {
generateErrorCodeResponseExample(operation, apiErrorCodeExample.value());
}
return operation;
};
}
→ @ApiErrorCodeExample이 붙은 메서드만 골라서 ErrorType[]을 추출하고, 에러 응답을 만들어준다.
generateErrorCodeResponseExample
- 각 에러에 대해 응답 예시를 구성하고 Swagger에 추가
- INTERNAL_SERVER_ERROR는 항상 추가
private void generateErrorCodeResponseExample(Operation operation, ErrorType[] errorTypes) {
ApiResponses responses = operation.getResponses();
List<ErrorType> errorTypesList = Arrays.asList(errorTypes);
ErrorType[] filteredErrorTypes = Arrays.stream(ErrorType.values())
.filter(errorType -> errorTypesList.contains(errorType) ||
errorType.getStatus().equals(HttpStatus.INTERNAL_SERVER_ERROR))
.sorted(Comparator.comparing(ErrorType::getStatus))
.toArray(ErrorType[]::new);
Map<HttpStatus, List<ExampleHolder>> statusWithExampleHolders =
Arrays.stream(filteredErrorTypes)
.map(errorCode -> ExampleHolder.builder()
.statusCode(errorCode.getStatus())
.holder(getSwaggerExample(errorCode))
.errorCode(errorCode.getCode())
.errorMessage(errorCode.getMessage())
.build())
.collect(groupingBy(ExampleHolder::getStatusCode));
addExamplesToResponses(responses, statusWithExampleHolders);
}
→ 각 HttpStatus별로 에러 코드를 그룹핑하여, Swagger UI에서 구분해 보여줄 수 있도록 구성한다.
addExamplesToResponses
private void addExamplesToResponses(ApiResponses responses, Map<HttpStatus, List<ExampleHolder>> statusWithExampleHolders) {
statusWithExampleHolders.forEach((status, exampleHolders) -> {
Content content = new Content();
MediaType mediaType = new MediaType();
ApiResponse apiResponse = new ApiResponse();
exampleHolders.forEach(holder -> {
mediaType.addExamples(String.valueOf(holder.getErrorCode()), holder.getHolder());
});
content.addMediaType("application/json", mediaType);
apiResponse.setContent(content);
responses.addApiResponse(status.toString(), apiResponse);
});
}
결과 (Swagger UI)
API의 응답 예시 아래에, 아래와 같은 JSON이 상태코드별로 자동 표시된다
{
"title": "상품을 찾을 수 없습니다.",
"code": 4042001,
"message": "상품을 찾을 수 없습니다."
}
- 코드 계산 방식: HTTP 상태코드 * 10000 + 내부에러코드 → 예: 4042001
- 클라이언트에서는 이 코드 기반으로 분기 처리 가능
- Swagger UI에서도 에러코드 목록이 “example”로 자동 노출되어 확인 가능
마무리하며 . . .
이번 작업을 통해 얻은 가장 큰 이점은:
- 에러 코드를 관리하는 곳은 그대로 두되,
- Swagger 문서가 해당 코드를 자동으로 API마다 예시로 표시해준다는 점이다.
클라이언트에서는 Swagger를 파싱해서 select box로 표시하거나, 자동화된 에러 메시지 대응에도 사용할 수 있다.
무엇보다도, 매번 @ApiResponse를 일일이 적지 않아도 된다는 점에서 유지보수성이 매우 높아졌고, 에러 코드의 통일성도 확보할 수 있었다. -_-v
'스터디 > 스프링' 카테고리의 다른 글
[Spring] JPA 연관관계 매핑과 성능 최적화 (Fetch Join vs. Open-in-view) (5) | 2025.08.25 |
---|---|
[Spring] ApplicationEventPublisher에 대한 고찰 (feat. Fcm push) (1) | 2025.08.08 |
[Spring] 스프링 핵심 원리 기본편 | 1. 객체 지향 설계와 스프링 (0) | 2023.08.24 |
[Spring] 스프링 입문 | 5. 회원관리 예제 - 웹 MVC 개발 (0) | 2023.08.20 |
[Spring] 스프링 입문 | 4. 스프링 빈과 의존관계 (2) | 2023.07.06 |
Comments