요구 사항

프로젝트를 개발할 때, API 명세를 정하는 과정에서 모든 REST 응답에 대한 기본 형태를 다음과 같이 정의했다.

{
    "code": int
    "message": string
    "response": object
}

문제 정의

모든 REST 응답은 공통적인 형태를 갖기 때문에 기본적으로 응답을 감싸는 객체를 생각해 볼 수 있다.

@Getter
@RequiredArgsConstructor(access = PRIVATE)
public class ResponseWrapper<T> {

	private final int code;
	private final String message;
	private final T response;
	
	public static <T> ResponseWrapper<T> from(T response, int code, String message) {
		return new ResponseWrapper<>(code, message, response);
	}
}

ResponseWrapper를 사용하여 모든 RestController의 메서드에 다음과 같이 적용하여 사용하면 된다.

@RestController
public class SomeRestController {

	@PostMapping
	@ResponseStatus(OK)
	public ResponseWrapper<SomeResponse> doSomething() {
	  ...
		SomeResponse response ...;
		int code = 2000;
		String message = "OK";
		...
		return ResponseWrapper.from(response, code, message);
	}
}

보기만 해도 벌써 이건 아니다 싶다. 왜냐하면

  1. 메서드 리턴 타입에 매번 ResponseWrapper<…>반복되는 것은
    1. 유지보수를 어렵게 한다.
    2. 가독성을 떨어트려 한 눈에 메서드에 대한 정보를 알기 어렵게 한다.
  2. return 할 때도 역시 같은 작업이 반복된다.
  3. 메서드 내부에서 code와 message를 하드코딩한다.
  4. 1개의 메서드 안에서 공통 응답 객체 생성과 실제 응답 데이터 생성이라는 2개의 책임을 갖고 있다.

개선해보자.