Generic으로 커스텀 공통 응답폼 만들기

Do_It·2023년 11월 17일

오늘은 어디~?

목록 보기
4/9

공통 응답폼?

왜 공통 응답폼 만드는가?

프론트엔드 입장에서 어떤 API 테스트를 하던지 공통 응답을 받는다면, 응답 받은 내용을 좀 더 쉽게 이해할 수 있다고 생각하기 때문이다. 또한 백엔드끼리의 협업시에도 다른 API테스트를 할때도, 어디서 에러가 생긴건지도 쉽게 파악할 수 있게 하고 싶기 때문이다.
목적은 공통 응답폼으로 빠르게 응답을 이해하여 협업을 좀 더 쉽게하기 위함!

Generic으로 공통 응답폼 만들기

Generic?

제네릭은 클래스, 인터페이스, 메서드를 정의할 때 타입을 매개변수화하는 방법을 제공! 즉, 타입을 필요에 따라 바꿀 수 있다는 것.
제네릭을 사용하면 클래스나 메서드를 선언할 때 구체적인 타입을 지정하지 않고, 사용할 때 타입을 결정해 코드의 재사용성을 높이고, 컴파일 시 타입 안전성을 보장!
타입의 안전성은 언제나 중요하다! 자바스크립트의 장점이자 단점인 타입의 유연하다는 점..그래서 typescript가 있지 않는가! ㅎㅎ
무튼 Generic을 활용해 공통 응답폼을 만들것이다!

절차

  1. CommonResponse 만들기
@Getter
@RequiredArgsConstructor
public class CommonResponse<T> {
    private final Integer status;
    private final String message;
    private final T data;

    public static <T> CommonResponse<T> success(T data) {
        return new CommonResponse<>(200, "Success", data);
    }

    public static <T> CommonResponse<T> error(int status, String message) {
        return new CommonResponse<>(status, message, null);
    }

}
  1. 응답 성공은 success로 내려주고 data는 프론트엔드와 협의하여 상황에 맞는 데이터를 내려주기
    예를 들어 로그인 성공시 세션ID를 응답값에 포함하기로 했다면

컨트롤러

@PostMapping("/login")
    public CommonResponse<String> login(@RequestBody Login login , HttpSession session) {
        return CommonResponse.success(userService.login(login,session));
    }

서비스

@Transactional(readOnly = true)
    public String login(Login login, HttpSession session) {
        User user = userRepository.findByEmail(login.getEmail());
        if(user == null || !user.isPasswordMatch(passwordEncoder,login.getPassword()))
            throw new UserException(UserErrorCode.FAIL_TO_LOGIN);
        session.setAttribute("user",user);
        return session.getId();
    }

업로드중..

  1. 응답 실패 => 예외 처리는 모두 error로
@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(CommonException.class)
    public CommonResponse<String> handleCommonException(CommonException commonException) {
        return CommonResponse.error(commonException.getErrorCode(),commonException.getMessage());
    }

    @ExceptionHandler(UserException.class)
    public CommonResponse<String> handleUserException(UserException userException) {
        return CommonResponse.error(userException.getErrorCode(),userException.getErrorMessage());
    }
}

예를 들어 로그인시 이메일이나 비밀번호가 틀렸다면

 public String logout(HttpSession session,User user) {
        if(user == null) throw new UserException(UserErrorCode.NOT_EXIST_USER);
        log.info("로그아웃된 사용자 이메일 : {}", user.getEmail());
        session.invalidate();
        return "로그아웃 되었습니다.";
    }

업로드중..

이런식으로 깔끔하게 데이터들을 내려준다. 물론 서버의 응답은 항상 200이다. 하지만 응답 내용은 다르다는 것! 이렇게 하는 이유는 프론트 개발자 분들이 테스트할때, 첫번째로 서버에 요청을 보내면 API가 작동하는지 여부를 확실하게 알 수 있기 때문이다. 서버에 요청이 오는 것부터 확인 되어야 다음 작업을 할 수 있다고 생각했기 때문에 공통 응답폼을 만들어서 모든 응답을 200으로 내려주고 그 안에 에러 코드의 상태와 메세지를 넣는 방식을 택했다.

사소한(?) 트러블 슈팅 - 매개변수 인식 문제 -

 @ExceptionHandler(UserException.class)
    public CommonResponse<String> handleUserException(UserException userException) {
        return CommonResponse.error(userException.getErrorCode(),userException.getErrorMessage());
    }

런타입 에러가 나면 해당 ErrorMessage가 생성되어

 public static <T> CommonResponse<T> error(int status, String message) {
        return new CommonResponse<>(status, message, null);
    }

메세지를 매개변수로 받아서 응답하는건데, 메세지가 자꾸 null 이 생겼다. 즉 매개변수로 받지 못하는 상황이 생겼는데, getErrorMessage() 대신 순수하게 "테스트" 라고 넣고 다시 실행보니 되었다. 그 후 다시 "테스트" 삭제 후 getErrorMessage()을 넣으니 제대로 인식이 되었다. 이런 문제는 또 처음 겪어보는거라서, 신기하면서 당황했다..? 혹시라도 매개변수가 안되면 순수한 매개변수 자체를 넣어보고 다시 시도해보는 것도 어쩌면 해결책이 될수도 있을것 같다

profile
오늘의 노력이 내일의 성장으로 이어지고 있음을

0개의 댓글