Spring Boot에선 기본적으로 ResponseEntity<T> 라는 클래스를 제공한다. 이는 Http 요청에 대한 Response를 설정할 수 있는 클래스로, Body, Header, StatusCode를 설정할 수 있다.
이 ResponseEntity<T> 클래스를 사용해 적절한 Response를 보낼 수 있다.
ResponseEntity는 HttpEntity를 상속받는다.
public class HttpEntity<T> {
private final HttpHeaders headers;
@Nullable
private final T body;
}
public class ResponseEntity<T> extends HttpEntity<T> {
private final HttpStatusCode status;
public ResponseEntity(HttpStatusCode status) {
this((Object)null, (MultiValueMap)null, status);
}
public ResponseEntity(@Nullable T body, HttpStatusCode status) {
this(body, (MultiValueMap)null, status);
}
public ResponseEntity(MultiValueMap<String, String> headers, HttpStatusCode status) {
this((Object)null, headers, status);
}
public ResponseEntity(@Nullable T body, @Nullable MultiValueMap<String, String> headers, int rawStatus) {
this(body, headers, HttpStatusCode.valueOf(rawStatus));
}
public ResponseEntity(@Nullable T body, @Nullable MultiValueMap<String, String> headers, HttpStatusCode statusCode) {
super(body, headers);
Assert.notNull(statusCode, "HttpStatusCode must not be null");
this.status = statusCode;
}
....
}
ResponseEntity는 사용자의 HttpRequest에 대한 응답 데이터를 포함하는 클래스이다. 따라서 HttpStatus, HttpHeaders, HttpBody를 포함한다. 이 ResponseEntity의 Body에 담을 데이터 클래스를 만들어보자.
우선, Response Body의 형식을 통일해야 한다. 프론트엔드 입장에서 통일되어 있지 않은 Response Body는 매우 불쾌하다. API 마다 형식이 다 다르다고 한번 생각해 보면 이해할 수 있을 것이다. 이는 유지보수 자원을 낭비하는 설계이다. 우선 Response Body에 담은 데이터들을 가지는 ResponseDto 클래스를 만들자.
@Getter
@AllArgsConstructor
public class ResponseDto<T> {
private final String statusCode;
private final String message;
private final T data;
public static <T> ResponseDto<T> res(final HttpStatusCode statusCode, final String message) {
return new ResponseDto<>(String.valueOf(statusCode.value()), message, null);
}
public static <T> ResponseDto<T> res(final HttpStatusCode statusCode, final String message, final T data) {
return new ResponseDto<>(String.valueOf(statusCode.value()), message, data);
}
}
우리는 프론트엔드에 Response를 줄 때 다음과 statusCode, message, data 형식으로 넘겨줄 것이다. Response Body 예시는 이렇게 된다.
{
"statusCode": 200,//응답 코드
"message": "OK",//응답에 대한 메시지
"data": [어쩌고저쩌고]//응답에 들어갈 데이터
}
코드에 대한 자세한 설명은 생략한다.
이 클래스를 ResponseEntity<T>에 담아 Response를 보낼 수 있다.
Controller에서 다음과 같이 사용해보자.
반환값(ResponseDto의 data)이 없는 경우
@DeleteMapping("/{id}")
public ResponseEntity<ResponseDto<Void>> deleteMemoById(@PathVariable("id") UUID id) {
return this.memoService.deleteMemoById(id);
}
public ResponseEntity<ResponseDto<Void>> deleteMemoById(UUID memoId) {
this.memoRepository.deleteById(memoId);
return new ResponseEntity<>(ResponseDto.res(
HttpStatus.OK,
"Success"
), HttpStatus.OK);
}
반환 결과
{
"statusCode": 200,
"message": "Success",
"data": null
}
반환값(ResponseDto의 data)이 있는 경우
@GetMapping("/{id}")
public ResponseEntity<ResponseDto<Memo>> getMemoById(@PathVariable UUID id) {
return this.memoService.getMemoById(id);
}
public ResponseEntity<ResponseDto<Memo>> getMemoById(UUID id) {
Memo memo = this.memoRepository.findById(id).orElseThrow();
return new ResponseEntity<>(ResponseDto.res(
HttpStatus.OK,
"Success",
memo
), HttpStatus.OK);
}
반환 결과
{
"statusCode": 200,
"message": "Success",
"data": [
{
"id": "a5e82152-57ca-4cd5-b9f7-a89e418ec7af",
"title": "memo1",
"content": "hello",
"createdAt": "2024-01-24T06:31:25.013+00:00",
"updatedAt": "2024-01-24T06:31:25.013+00:00"
}
]
}
'Spring Boot' 카테고리의 다른 글
Dto Validation 실패 시 예외처리 (0) | 2024.03.15 |
---|---|
Spring Boot에선 예외를 어떻게 처리할까?(전역, 커스텀 예외처리) (0) | 2024.03.15 |
Dto에 Validation 적용하기 (2) | 2024.01.21 |
Spring Security jwt 적용, 커스터마이징 (0) | 2024.01.21 |
Spring Security 구조와 동작 원리 (0) | 2024.01.21 |