ResponseEntity 클래스는 HTTP 응답(Response)을 나타내는 객체로, 반환된 HTTP 상태코드와 헤더, 응답 본문 등을 포함한다.
ResponseEntity는 밑의 사진에서 보이는 것처럼 HttpEntity
를 상속받았기 때문이다.
바로 위의 사진은 HTTP 클래스인데, 헤더와 바디를 멤버필드로 포함하고 있다.
즉 ResponseEntity는 HttpEntity 클래스의 멤버필드 headers, body와 자체적으로 갖고 있는 멤버필드 status(상태코드)를 포함하여 HttpStatus
, HttpHeaders
, HttpBody
를 변수로 갖게 된다.
일반적으로 @Controller
나 @RestController
, @RequestMapping
메소드를 사용하여 HTTP 요청에 대한 응답을 반환할 때 사용한다.
예를 들어 HTTP 상태코드가 200인 응답을 반환하려면 다음과 같이 ResponseEntity를 사용할 수 있다.
@GetMapping("/hello")
public ResponseEntity<String> hello() {
String message = "Hello, World!";
return ResponseEntity.ok(message);
}
위 코드에서 ResponseEntity.ok(message)
는 HTTP 상태코드 200과 "Hello, World!" 메세지를 가진 ResponseEntity 객체를 생성하여 반환한다.
@GetMapping("/users/{id}")
public ResponseEntity<User> getUserById(@PathVariable Long id) {
User user = userRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("User not found with id: " + id));
return ResponseEntity.ok(user);
}
@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message);
}
}
위 코드는 ReponseEntity를 사용하여 404 Not Found 에러를 반환하는 코드다.
맨 처음으로 데이터베이스에서 해당 id값을 가진 사용자 정보를 조회하는 메소드가 보이는데, 이 때 findById()
메소드는 Spring Data JPA에서 제공하는 메소드중 하나로 결과를 Optional
타입으로 반환 한다.
Optional
은 값이 없을 수도 있는 객체를 다룰 때 사용하는 클래스다. 이 타입을 사용하면 null 체크를 하지 않아도 되는 장점이 있다.
Optional.empty()
: 조회된 엔티티가 없는 경우 반환되는 객체
orElseThrow()
: 예외를 발생시키는 메소드
orElse()
: 기본값을 반환하는 메소드
따라서 위 코드에서는 userRepository.findById(id)를 호출하여 조회한 Optional 객체가 값이 없다면, orElseThrow
메소드가 ResourceNotFoundException
예외를 발생시킨다.
즉, "User not found with id: {id}"라는 메세지를 가진 ResourceNotFoundException
예외가 발생하여 HTTP 상태코드 404를 반환한다.
ResourceNotFoundException은 HTTP 요청에 대한 예외처리를 위한 사용자 정의 예외클래스다.
@ResponseStatus(HttpStatus.NOT_FOUND)
어노테이션은 해당 예외가 발생했을 때, HTTP 응답 상태코드를 404 NOT FOUND
로 설정해준다. 이는 REST API에서 자주 사용되는 응답 상태코드 중 하나로 클라이언트가 요청한 값이 존재하지 않는 경우에 사용된다.
ResponseEntity는 상태코드와 헤더, 바디 중 원하는 것만 선택해서 반환할 수 있다는 큰 장점이 있다.
몇가지 예시를 들어보자
1. 상태코드와 헤더는 그대로 유지, 본문만 변경하고자 할 때
// 원래의 ResponseEntity 객체
ResponseEntity<String> responseEntity = ResponseEntity
.status(HttpStatus.OK)
.header("My-Header", "value")
.body("original body");
// 상태 코드와 헤더는 그대로 유지하고, 본문만 변경한 새로운 ResponseEntity 객체
ResponseEntity<String> newResponseEntity = ResponseEntity
.status(responseEntity.getStatusCode())
.headers(responseEntity.getHeaders())
.body("new body");
위의 코드에서, newResponseEntity 객체는 responseEntity 객체와 상태코드와 헤더가 동일하고, 본문만 "new body"로 변경된 새로운 객체가 된다.
2. 바디만 반환하는 경우
@GetMapping("/body")
public ResponseEntity<String> getBody() {
return ResponseEntity.ok("response body");
}
위 코드에서 ResponseEntity 객체 생성 시, 생성자의 두번째 파라미터로 반환할 바디의 내용을 넘겨주면 된다.
3. 상태코드만 반환하는 경우
게시글의 삭제같은 경우처럼 반환타입이 따로 없는 경우가 있다.
이런 경우에는 상태코드만 반환해줄 수 있는데, 코드는 다음과 같다.
@DeleteMapping("/resources/{id}")
public ResponseEntity<Void> deleteResource(@PathVariable Long id) {
boolean success = resourceService.deleteResource(id);
if (success) {
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
} else {
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
}
}
위 코드는 게시글이 무사히 삭제된 경우와, 그렇지 않을 경우에 각각 다른 상태코드를 반환한다.
만약 삭제가 성공했다면 HttpStatus.NO_CONTENT
상태코드와 빈 바디를 가진 ResponseEntity를 반환한다.
반면 삭제에 실패했다면 HttpStatus.NOT_FOUND
상태코드와 함께 빈 바디를 가진 ResponseEntity를 반환한다.
ResponseEntity의 메소드들은 서버에서 생성된 HTTP 응답을 생성하기 위한 다양한 방법을 제공해준다. 그 중 자주 사용되는 몇가지 메소드들을 살펴보자
ok()
: HTTP 상태코드 200를 반환
notFound()
: HTTP 상태코드 404를 반환
getBody()
: HTTP 응답 바디에 대한 내용을 반환
getHeaders()
: HTTP 응답 헤더에 대한 내용을 반환
getStatusCode()
: HTTP 응답 상태코드를 반환한다. 200은 "OK", 404는 "Created", 404는 "Not Found" 등의 의미를 갖고 있다.`