문제 상황
프로젝트를 진행하면서 응답 통일을 위해 생성해두었던 코드에 대하여 중복 코드로 인한 불편함을 느꼈었다.
다음과 같이 성공시의 응답과 ErrorResponse에 대한 처리 방식이 불필요하게 중복되는 것이 많아 불편하였다.
(나의 경우 ApiResponse로 응답 코드를 통일 한 것이 아니라 RestResponse라는 이름으로 따로 공통 응답 클래스를 만들어두어서 사용하였으니 참고해주세요)
return ResponseEntity.ok(
RestResponse.ok(
memberService.getMyinfo()
)
);
...
return ResponseEntity.ok(
RestResponse.ok(
memberService.find()
)
);
당장 Controller만 해도 이런 코드로 작성된 것들이 많은데,
불필요하다고 생각하였으며
Controller 내에서의 처리이니까 이에 대하여 한 번에 처리할 수 있는게 없을지 고민을 하던 도중
ResponseBodyAdvice 기능에 대하여 발견하였다.
ResponseBodyAdvice
ResponseBodyAdvice (Spring Framework 6.2.6 API)
Allows customizing the response after the execution of an @ResponseBody or a ResponseEntity controller method but before the body is written with an HttpMessageConverter. Implementations may be registered directly with RequestMappingHandlerAdapter and Exce
docs.spring.io
supports
boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType)
공식 문서에 따르면 supports는
return Type이 컨트롤러 메소드에서 지정한 타입과 동일하다면 true를 반환하는 메소드다.
또한 이 True를 바탕으로 HttpMessageConverter가 작업을 통해 json 형식으로 응답을 커스터마이징 해주는 것이다.
즉, 우리가 RESTful 통신을 하려면 json 기반의 응답 양식들이 필요한데,
HttpMessageConverter가 Controller에서 반환되는 HttpResponseWrapper에 대하여 다음과 같은 변환 작업을 해주는 것이다.
beforeBodyWrite
@Nullable
T beforeBodyWrite(@Nullable T body,
MethodParameter returnType,
MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType,
ServerHttpRequest request,
ServerHttpResponse response)
beforeBodyWrite는
응답에 대하여 Body 작성 이전에
Controller 메소드의 결과에 대한 응답을
우리가 성공 시 지정한 클래스에 담아서 처리해주는 것이다.

위의 내용이 우리의 스프링 컨테이너라면
필터를 거친 이후에 HttpServletRequest와 HttpServletResponse 객체가 생성될 것이고
Controller는 서비스를 호출한 이후에 응답을 만들어낼 것이다
이 때 ResponseBodyAdvice를 통하여 우리는 해당 Controller의 응답 객체를 우리가 지정한 양식으로 정할 수 있다.

Controller는 이제 RestControllerAdvice를 거쳐서 응답을 반환하는 것이다.
그러면 해당 ResponseBodyAdvice는 우리의 응답을 Json 객체에 맞게 바꿔준다
주의할 내용
아쉽게도 지정한 객체가 아니라 String이 응답 타입일 경우에는 제대로 적용이 안된다.
변환해야하는 객체 대상으로 인지를 못하고 이미 String 타입이므로 JsonString과 구분을 못해주기 때문이다.
시도한 내용
Spring Boot에서 컨트롤러 응답을 공통 포맷으로 감싸기 위해 ResponseBodyAdvice를 이용해서 자동 가공하는 구조를 만든 것이다.
특히, 정상 응답과 예외 응답 모두 하나의 통일된 형식으로 감싸서 API 응답 포맷을 일관성 있게 만들었다.
주요 흐름
- Controller 메서드 실행
- @ResponseBody 또는 ResponseEntity로 리턴된 값이 있음
- HttpMessageConverter로 변환되기 전에
- ResponseBodyAdvice가 개입
- 응답 객체를 가공(wrap) 가능
- 가공한 객체를 JSON으로 변환해 클라이언트에게 보냄
결과
중복된 코드를 없앰
REF