안녕하세요. 오늘은 스프링부트에서 공통 응답 코드를 설정하는 방법을 알아보겠습니다.
공통 응답 코드란?
말그대로 동일한 형식을 가지는 응답 코드를 말합니다. api 호출 시에 endpoint마다 다른 응답 코드를 반환한다면 응답을 받는 쪽에서는 처리를 위해 여러가지 코드를 작성해야합니다. 이런 수고스러움을 줄이기 위해 모든 api의 응답을 같은 형식으로 반환해줍니다.
응답 형식 클래스 작성
@Getter
@NoArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class CommonResponse<T> {
private String code;
private String message;
private T result;
private boolean success = false;
@Builder
public CommonResponse(String code, String message, T result, boolean success) {
this.code = code;
this.message = message;
this.result = result;
this.success = success;
}
public CommonResponse(T result) {
this.result = result;
this.success = true;
apply(CommonResponseStatus.OK);
}
public CommonResponse(boolean success, T result) {
this.success = success;
this.result = result;
apply(success ? CommonResponseStatus.OK : CommonResponseStatus.INTERNAL_SERVER_ERROR);
}
public CommonResponse(String message) {
this.message = message;
this.success = false;
}
public static <T> CommonResponse<T> of(@Nullable T result) {
return new CommonResponse<>(result);
}
public static <T> CommonResponse<T> of(boolean success, @Nullable T result) {
return new CommonResponse<>(success, result);
}
private void apply(CommonHttpStatus status) {
this.code = Integer.toString(status.getCode());
this.message = status.getMessage();
}
}
먼저 api에서 응답하는 데이터의 형식이 일반적인 String일 수도 있고, Array형식일 수도 있기 때문에 유연하게 받을 수 있는
제네릭 클래스로 커스텀 응답클래스를 생성합니다. 저는 http 프로토콜의 응답 코드와 메시지, 그리고 api 호출 결과를 넣을 수 있는 멤버변수를 선언했습니다.
스프링부트 ReponseBodyAdvice 생성
다음으로는 스프링부트의 필터를 사용해서 응답을 가로채는 클래스를 생성해보겠습니다.
@RestControllerAdvice(annotations = RestController.class)
public class CommonResponseWrapperAdvice implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
return true;
}
@Override
public Object beforeBodyWrite(Object obj, MethodParameter methodParameter,
MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass,
ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
if ( obj instanceof ApiXmlResponse || obj instanceof ApiJsonResponse || obj instanceof OpenApiJsonResponse || obj instanceof OpenApiXmlResponse
|| obj instanceof OpenDataApiResponse ) {
return obj;
} else {
CommonResponse<?> commonResponse = CommonResponse.of(obj);
serverHttpResponse.setStatusCode(commonResponse.getHttpStatus());
return commonResponse;
}
}
}
ResponseBodyAdvice 인터페이스를 구현해보았습니다.
먼저 @RestControllerAdvice 어노테이션은 예외 처리나 응답 객체를 공통적으로 처리하는 데 사용됩니다. 어노테이션 안에 RestController.class를 선언해줌으로써 @RestController가 붙은 모든 클래스에서 반환하는 응답에 대해 특정 로직을 적용하게 합니다.
첫번째 메서드인 support는 API 응답을 가로채야 할지 여부를 결정합니다. 항상 true를 반환하도록 설정했으므로, 모든 응답을 이 클래스의 beforeBodyWrite 메서드에서 처리하게 됩니다.
beforeBodyWrite 메서드는 컨트롤러에서 반환한 객체(obj)를 가로채어 최종적으로 응답을 조작하는 역할을 합니다.
저는 구현한 Api Response 객체 중 공통 응답코드에서 사용하지 않고 그냥 반환해야 하는 클래스들이 있기 때문에 따로 명시해서 바로 obj 객체로 반환했습니다. 코드에서 예시로 넣어둔 ApiXmlResponse, ApiJsonResponse, OpenApiJsonResponse, OpenApiXmlResponse, OpenDataApiResponse 가 해당됩니다. 이 객체는 별도의 가공 없이 그대로 클라이언트에 전달됩니다.
위의 조건에 해당하지 않는 경우, 반환된 객체(obj)를 CommonResponse로 감쌉니다. CommonResponse.of(obj) 위에서 생성한 메서드로 객체를 커스텀한 공통 응답 클래스의 of 메서드 안에 넘겨줍니다.
그 후, HTTP 응답의 상태 코드도 CommonResponse 객체에 포함된 상태 코드로 설정합니다.
설정 후에 실제로 API 호출을 해보면 아래와 같은 결과를 얻을 수 있습니다.
{
"code": "200",
"message": "OK",
"result": {
"key1": "value1",
"key2": "value2"
},
"success": true
}
'프로그래밍' 카테고리의 다른 글
[SQL] 특정 문자 이후의 모든 문자열 제거 (1) | 2024.10.07 |
---|---|
[LLM] OpenAI API를 활용한 대화형 차트 생성기 (0) | 2024.08.04 |
[sts] Maven 업데이트 시 무한 로딩 (0) | 2024.07.18 |
[kubernetes] 스테이트풀셋(Statefulset) (0) | 2024.07.10 |
[kubernetes] 쿠버네티스 기본 용어 정리 (0) | 2024.06.19 |