Spring/Spring 문법

ResponseEntity란 무엇일까?

열심히 해 2024. 10. 24. 11:23

ResponseEntity

 

HTTP 요청에 대한 응답을 제어하는 데 사용되는 클래스.

 

 

 

ResponseEntity는 Status, Headers, Body를 필드로 갖습니다. 이를 통해 세밀하게 응답을 관리할 수 있습니다. Body를 필드로 가지고 있기 때문에 @RestController 또는 @RequestBody와 함께 사용됩니다. 

 

ResponseEntity<T> responseEntity = new ResponseEntity<>(body, headers, status);

<예시1>

 

  • T: Response Body의 타입
  • body: 객체, String, List, Map 등
  • headers: HTTP Header
  • status: HTTP Response Status Code

 

 


 

ResponseEntity가 생겨난 이유

 

일반적으로 Controller에서 아래와 같이 객체를 Return 하는 경우 HTTP 응답을 세밀하게 제어할 수가 없습니다.

@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class MemoController {

    private final MemoService memoService;
    
    @PostMapping("/memos")
    public MemoResponseDto createMemo(@RequestBody MemoRequestDto requestDto) {
        return memoService.createMemo(requestDto);
    }
}

 

 

 

 

하지만 ResponseEntity를 사용하면 적절한 상태 코드와 응답 헤더 및 바디를 작성할 수 있습니다.

@PostMapping("/memos")
public ResponseEntity<MemoResponseDto> createMemo(@RequestBody MemoRequestDto requestDto) {
    MemoResponseDto memoResponseDto = memoService.createMemo(requestDto);
    return ResponseEntity.ok(memoResponseDto);
}

<예시2>

 

성공을 의미하는 OK(200 code)와 함께 memoResponseDto를 전달할 수 있습니다.

 

 

 

 


 

ResponseEntity 사용법

 

 

<예시1>과 <예시2>에서 보시다시피 ResponseEntity를 사용하는 방법은 두 가지입니다.

 

 

1. 생성자 패턴

@GetMapping("/example")
public ResponseEntity<String> getExampleResponse() {
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Type", "application/json");
    headers.add("Custom-Header", "CustomValue");

    String body = "{\"message\": \"코드에서 냄새가 나네요.(다시 짜세요.)\"}";

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

 

 

2. 빌더 패턴

 

빌더 패턴을 사용하는 것이 의미가 더 직관적이고 유지보수에 좋습니다.

 

header에는 (요청/응답)에 대한 요구사항이, body에는 그 내용이 들어갑니다.

 

@GetMapping("/example")
public ResponseEntity<String> getExampleResponse() {
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Type", "application/json");
    headers.add("Custom-Header", "CustomValue");

    String body = "{\"message\": \"코드에서 구린내가 나네요.(다시!)\"}";

    return ResponseEntity.status(HttpStatus.OK)
            .headers(headers)
            .body(body);
}

 

 

 

자주 쓰이는 status 값

상태값 status()의 인자값 설명
200 HttpStatus.OK 요청이 성공적으로 처리된 경우
201 HttpStatus.CREATED 새로운 리소스가 성공적으로 생성된 경우
202 HttpStatus.ACCEPTED 처리가 아직 완료되지 않았지만 시작되었음을
클라이언트에 알릴 경우
204 HttpStatus.NO_CONTENT 주로 삭제 요청이나 업데이트 후
body가 필요 없는 경우
300 HttpStatus.MULTIPLE_CHOICES 요청에 대해 하나 이상의 응답이 가능한 경우
302 HttpStatus.FOUND 요청한 리소스의 URI가 일시적으로 변경된 경우
400 HttpStatus.BAD_REQUEST 잘못된 문법으로 인해
서버가 요청을 이해할 수 없는 경우
401 UNAUTHORIZED  인증되지 않은 경우
404 HttpStatus.NOT_FOUND 요청(값)을 찾을 수 없는 경우
429 HttpStatus.TOO_MANY_REQUESTS 사용자로부터 너무 많은 요청이 발생한 경우
500 HttpStatus.INTERNAL_SERVER_ERROR 서버에서 에러가 발생한 경우

 

 

 

\": 문자열 안에서 큰따옴표(")를 사용하려면 이스케이프 문자(\)를 사용하여야 합니다.

 

 

 


 

와일드카드

 

 

ResponseEntity의 타입을 명시하지 않으면 Object 타입을 Return 해줍니다. 

 

public ResponseEntity getMemo() {...}

public ResponseEntity<Object> getMemo(int id) {...}

 

 

따라서 위 두 메서드의 리턴 타입은 같습니다.

 

 

 

 

하지만 타입을 여러 개 받고 싶다면 와일드카드 <T>를 사용하는 것이 낫습니다.

 

Object에서 원하는 타입으로 형변환하지 않아도 되기 때문입니다.

 

public ResponseEntity<T> getMemo() {
    T memo = memoService.getMemo();
    return ResponseEntity.ok(memo);
}

 

 

 

 

 

 

 


 

추가 사항

 

 

 

 

@ResponseStatus(HttpStatus.BAD_REQUEST)
@PostMapping("/login")
public UserResponseDto login(@RequestBody LoginRequestDto requestDto) {
    return userService.login(requestDto);
}

위와 같이 메서드에 @ResponseStatus를 달면 응답을 일부 관리할 수 있으나, 메서드가 실행될 때 항상 400(BAD_REQUEST) 상태 코드로 응답을 반환하게 됩니다.

 

 

 

 

 

@ResponseStatus(HttpStatus.BAD_REQUEST)
public class InvalidLoginException extends RuntimeException {
    public InvalidLoginException(String message) {
        super(message);
    }
}

위와 같이 클래스에 @ResponseStatus를 달면 특정 예외가 발생했을 때 해당 상태 코드로 응답을 반환하도록 설정할 수 있습니다.

 

 

 

그리고 서비스나 컨트롤러에서 예외를 던지면 자동으로 400 상태 코드가 응답됩니다.

@PostMapping("/login")
public String login(@RequestBody LoginRequestDto requestDto) {
    String result = userService.login(requestDto);
    if (result == null) {
        throw new InvalidLoginException("아이디 또는 비밀번호를 확인하세요");
    }
    return result;
}