개인 공부 (23.07~

ResponseEntity 사용이유, 개념, 예시

Song쏭 2023. 8. 28. 00:25
ResponseEntity 사용이유

@RestController는 별도의 View를 제공하지 않은 채 데이터를 전달한다.

따라서, 전달 과정에서 예외가 발생할 수 있다.

이 예외에 대해 좀 더 세밀한 제어가 필요한 경우 ResponseEntity 클래스를 사용한다.

이 클래스 타입을 반환값으로 사용하여 HTTP 응답을 세밀하게 제어하는 것이다.

 

덧붙이자면,

기본적인 SpringMVC의 컨트롤러 메서드에서는 단순히 객체나 데이터만을 반환하면, 

Spring이 이를 HTTP 응답으로 자동 변환해주지만, 이 경우에는 HTTP 상태 코드가 항상 200 OK로 설정되고

헤더 설정이나 다른 HTTP 응답 관련 세밀한 제어가 어렵기 때문에 ResponseEntity를 사용하는 것이다.

 

ResponseEntity를 사용하면 HTTP 상태코드, 헤더, 응답 본문을

한번에 체인 형식으로 또는 생성자를 통해 설정할 수 있어서, HTTP 응답을 상세하게 제어할 수 있다.

 

ResponseEntity 개념

Spring Framework에서 사용되며, HTTP 응답의 전체를 표현한다.

 

HTTP 응답에 대해 세밀한 제어를 할 수 있게 해주는 클래스이다.

이 클래스를 이용하면 HTTP 상태코드, 헤더, 응답 본문을 명시적으로 설정할 수 있다.

(

HTTP 상태코드 (Status Code) : 응답의 성공, 실패, 리다이렉션 등을 나타내는 상태 코드를 설정한다.

ex) 200 OK, 404 Not Found 등

HTTP 헤더 (Headers) : 응답과 관련된 메타데이터를 설정할 수 있다.

ex) 캐싱 설정, 쿠키, 위치, 콘텐츠 유형, 커스텀 헤더 등

HTTP 응답 본문 (Body) : 클라이언트에게 반환할 (응답에 포함될) 실제 데이터를 포함한다. 보통 JSON, XML 같은 형식으로 직렬화되어 전달된다.

ex) { "name" : "John", "age" : 20 }

)

 

서버 측에서 클라이언트에게 보내는 응답을 구성할 때 사용된다. 

이를 통해 개발자는 HTTP 프로토콜의 다양한 응답 유형을 쉽고 정확하게 표현할 수 있다.

 

ResponseEntity 사용예시

이 코드에서 User 객체를 HTTP 응답 본문으로 반환하고,

상태코드를 200 OK 또는 404 Not Found로 설정합니다.

@GetMapping("/users/{id}")
public ResponseEntity<User> getUserById(@PathVariable int id) {
	User user = userService.findUserById(id);
    if(user == null){
    	return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }
        return new ResponseEntity<>(user, HttpStatus.OK);
	}

 

 

만약 상태 코드 외에 HTTP헤더를 추가하거나 다른 설정을 하고 싶다면,

ResponseEntity 클래스가 제공하는 빌더 패턴을 사용할 수 있다.

@GetMapping("/users/{id}")
public ResponseEntity<User> getUserByIdWithHeader(@PathVariable int id) {
    User user = userService.findUserById(id);
    HttpHeaders headers = new HttpHeaders();
    headers.add("Custom-Header", "some-value");

    if (user == null) {
        return new ResponseEntity<>(headers, HttpStatus.NOT_FOUND);
    }

    return new ResponseEntity<>(user, headers, HttpStatus.OK);
}

 

캐싱과 관련된 헤더나 쿠키 등도 마찬가지로 HttpHeaders 객체에 설정하여 ResponseEntity로 반환할 수 있다.

캐싱과 관련된 헤더를 설정하려면 다음과 같이 할 수 있다.

아래와 같이 설정하면 Cache-Control 헤더가 응답에 포함되어 클라이언트 측에서 캐싱을 제어할 수 있게 된다.

@GetMapping("/users/{id}")
public ResponseEntity<User> getUserByIdWithCacheHeader(@PathVariable int id) {
    User user = userService.findUserById(id);
    HttpHeaders headers = new HttpHeaders();
    headers.add("Cache-Control", "max-age=3600");

    if (user == null) {
        return new ResponseEntity<>(headers, HttpStatus.NOT_FOUND);
    }

    return new ResponseEntity<>(user, headers, HttpStatus.OK);
}

이렇게 각 HTTP 구조에 대해 사용예시를 ResponseEntity 직접 생성해서 해보았다.

 

 

ResponseEntity를 사용하여 HTTP 상태코드, 헤더, 본문을 조작하는 방법은
위의 예시들처럼 ResponseEntity 직접 생성 외에 여러가지가 있다.
그 중 4가지 방법과 예시는 아래와 같다.

 

1. ResponseEntity 직접 생성하기

new ResponseEntity<>() 생성자를 사용하여 직접 ResponseEntity 객체를 만들 수 있다.

@GetMapping("/hotels")
public ResponseEntity<List<HotelResponseDto>> getAllHotels() {
	List<HotelResponseDto> hotels = hotelService.getAllHotels();
    HttpHeaders headers = new HttpHeaders();
    headers.add("Custom-Header", "foo");
    return new ResponseEntity<>(hotels, headers, HttpStatus.OK);
}

cf) Q : HTTP 헤더에 사용하는 key, value들은 개발자가 임의로 String 값을 정해서 사용하는 것이 아니고, 이미 정해진 값들을 활용하는 것인가?

A : HTTP헤더에 사용하는 키와 값은 일반적으로 표준화된 키를 사용한다. 예를들어 "Content-Type", "Authorization", "Accept"등은 모두 표준 HTTP 헤더 필드이다. 이러한 표준 헤더 필드는 RFC 문서나 다른 표준 문서에서 정의되어 있으며, 

개발자들은 이러한 표준을 따라야 HTTP를 제대로 활용할 수 있다.

그러나 개발자가 피룡에 따라 커스텀 헤더를 생성할 수도 있다. 커스텀 헤더는 일반적으로 'X-"접두사를 붙여 구분한다.

 

 

2. ResponseEntity 빌더 사용하기

ResponseEntity.ok()는 정적 팩토리 메서드이다. 메서드 체이닝으로 연결한 빌더 패턴을 사용하는 것이 의미가 직관적이고 유지보수에 좋다.

@GetMapping("/hotels")
public ResponseEntity<List<HotelResponseDto>> getAllHotels() {
	List<HotelResponseDto> hotels = hotelService.getAllHotels();
    return ResponseEntity.ok()
    		.header("Custon-Header", "foo")
                .body(hotels);
}

 

3. ResponseEntity.BodyBuilder 사용하기

상태 코드와 헤더를 설정한 뒤, 본문을 설정한다.

헤더나 상태 코드를 다양하게 조작하려 할 때 유용하다.

@GetMapping("/hotels")
public ResponseEntity<List<HotelResponseDto>> getAllHotels() {
	List<HotelResponseDto> hotels = hotelService.getAllHotels();
    return ResponseEntity.status(HttpStatus.OK)
    		.header("Custom-Header", "foo")
                .body(hotels);
}

 

4. HttpEntity를 상속받는 클래스 사용하기

HttpHeaders를 설정한 다음 HttpEntity 객체를 생성하여

ResponseEntity에 전달할 수도 있다.

@GetMapping("/hotels")
public ResponseEntity<List<HotelResponseDto>> getAllHotels() {
	List<HotelResponseDto> hotels = hotelService.getAllHotels();
    HttpHeaders headers = new HttpHeaders();
    headers.add("Custom-Header", "foo");
    HttpEntity<List<HotelResponseDto>> httpEntity = new HttpEntity<>(hotels, headers);
    return new ResponseEntity<>(httpEntity.getBody(), httpEntity.getHeaders(), HttpStatus.OK);
}