스프링에서의 응답(response)값 반환에 대해 우선 내가 기존에 알고 있는 것은 다음과 같다.

 

1. @ResponseBody 어노테이션이 있으면 viewResolver를 거치지 않고 Http Response의 BODY에 데이터를 담게 된다

2. 문자열은 그대로 담고, 객체는 JSON으로 바꿔서 담는다!

 

이 때 클라이언트가 API를 원활하게 이용하기 위해선 API resonse 형식이 통일돼있든게 좋다고 한다! 생각해보면 나도 저번 학기에 팀플할 때 백엔드 하시는 분이 response 형식을 딱 정해서 줘서 편하게 API를 사용했던 기억이 있다.

 

암튼 클라이언트로부터 Request를 받고 그에 대한 응답(Response)를 반환할 때,  ResonseEntity라는 놈을 활용할 수 있고 이 놈을 통해 response형식을 통일하는 식으로 활용하는 게 가능하다. ResponseEntity의 장점은 우리가 담고 싶은 데이터 뿐만 아니라 HTTP 헤더나 상태 코드 등을 함께 지정해서 response를 보낼 수가 있다는 것이다. 

 

ResponseEitity?

클라이언트가 보내는 http request에 대한 응답을 포함하는 클래스. 스프링에서 기본으로 제공하는 HttpEntity라는 놈을 상속받는 녀석이다(구현이 아니라 상속!). HttpEntity의 생김새는 다음과 같다.

 

public class HttpEntity<T> {
	private final HttpHeaders headers;

	@Nullable
	private final T body;
}

 

헤더와 바디를 갖는 모습을 살펴볼 수 있다. 앞서 말했듯 ResponseEitity는 이 놈을 상속받으면서 request에 대한 응답을 포함하는 녀석이기 때문에,

 

 

요로코롬 status도 추가적으로 갖는 모습을 살펴볼 수 있다. 요놈은 뜯어보면 여러 개의 생성자가 존재하는데, 이 녀석들을 통해 헤더, 응답코드, 바디 등을 여러 방법을 통해 세팅할 수 있다. 헤더랑 바디는 null이 될 수 있지만 응답코드는 항상 세팅해줘야 한다. (참고로 생성자뿐만이 아닌 static 메서드로 만드는 방법들도 있음)

 

암튼 그럼 이 놈을 통해서 내가 저번에 만들었던 로그인 응답을 꾸며보기로(?) 했다. 

 

우선 토큰을 담을 DTO클래스를 만들었다. 참고로 Response에 쓰일 DTO클래스도 정의하는게 좋다고 하는데, 그 이유는 저번에 작성했던 request내용을 Entity로 받는게 아니라 DTO로 받는 이유와 동일. 결국 역할의 분리를 위해서라는 것. 

 

@AllArgsConstructor
@Data
public class LoginResponseDTO {
    private String accessToken;
}

 

(음..생각해보니까 refresh token도 만들고 access token만료될 때마다 다시 갱신하는 부분도 만들어야 하구나..갈 길이 멀다)

암튼 이걸 ResponseEntity에 담아 반환하고자 한다. 다음과 같이 컨트롤러의 코드를 수정해줬다.

 

    @PostMapping("/login")
    public ResponseEntity<LoginResponseDTO> login(@RequestBody LoginDTO loginInfo) {
        String loginEmail = loginInfo.getEmail();
        String loginRawPassword = loginInfo.getPassword();
        if (!memberService.login(loginEmail, loginRawPassword)) {
            throw new IllegalStateException("로그인에 실패했습니다.");
        }
        
        String accessToken = tokenProvider.createToken(loginEmail, jwtSecretKey, EXPIRED_MS);
        LoginResponseDTO loginResponseDTO = new LoginResponseDTO(accessToken);
        
        return new ResponseEntity<>(loginResponseDTO, HttpStatus.OK);
    }

 

자! 이제 response의 모습을 보면..

 

 

짠~

...사실 여기까지만 놓고 보면,

 

"어차피 객체를 리턴하면 JSON으로 바꿔서 전달해주니까 ResponseEntity가 아니라 LoginResponseDTO를 리턴하도록 해도 되잖아요!"

 

라고 할 수 있다. (사실 나도 순간 그렇게 생각함). 그러나 단순 객체를 리턴할 때와 비교해 ResponseEntity의 장점은 앞서 언급했듯이  바로 헤더와 응답코드를 내 맘대로 꾸며줄 수 있다는 점에 있다.

 

 

내 입맛대로 헤더 설정하기

@PostMapping("/login")
public ResponseEntity<LoginResponseDTO> login(@RequestBody LoginDTO loginInfo) {
    String loginEmail = loginInfo.getEmail();
    String loginRawPassword = loginInfo.getPassword();
    if (!memberService.login(loginEmail, loginRawPassword)) {
        throw new IllegalStateException("로그인에 실패했습니다.");
    }

    String accessToken = tokenProvider.createToken(loginEmail, jwtSecretKey, EXPIRED_MS);
    LoginResponseDTO loginResponseDTO = new LoginResponseDTO(accessToken);

    HttpHeaders httpHeaders = new HttpHeaders();
    httpHeaders.add("myFavoriteFood", "pizza");
    httpHeaders.setContentType(new MediaType("application", "json", Charset.forName("utf-8")));

    return new ResponseEntity<>(loginResponseDTO, httpHeaders, HttpStatus.OK);
}

 

이렇게 할 수 있다는 얘기다. 실제 response header를 뜯어보면,

 

 

이렇게 내가 설정한 정보들이 반영된 모습을 볼 수 있다!

 

 

내 입맛대로 응답코드 설정하기

이건 뭐..사진으로 대체. 

 

 

이미지에 보이는 것처럼 여러 응답코드가 있다. 

+ Recent posts