클라이언트 <-> 서버
ps) 필자는 현재 스프링부트와 리액트를 이용해 프로젝트를 진행 중이어서 위와 같이 리액트와 스프링부트 이미지를 사용했다.
클라이언트는 요청을 보내고, 서버는 응답 요청이 들어오면 요청한 데이터를 서버 단 로직을 통해 수행 후, 클라이언트에게 응답 값을 보낸다.
참고
2024.03.26 - [Backend/Web] - [Web] REST API란 무엇인가?
ResponseEntity vs. ApiResponse
Spring에서 API Response를 구현하는 데에는 ResponseEntity와 ApiResponse 두 가지 접근 방식이 있다.
ResponseEntity
- Spring의 HTTP응답을 나타내는 클래스
- HTTP 응답 코드, Header와 Body를 포함할 수 있다.
- HTTP 응답의 모든 부분을 세밀하게 제어할 수 있다.
- 상태 코드, Header, Body 등 명시적으로 응답 값을 나타낼 수 있다.
- 다양한 유형의 응답을 효과적으로 처리할 수 있다.
- JSON, XML, HTML 등 다양한 형식의 데이터를 반환할 수 있다.
ApiResponse
- API의 응답을 간단하게 나타내기 위한 사용자 지정 클래스
- JSON 형식의 응답을 표현하는데 사용
- 응답의 상태(성공 여부), 메시지, 데이터 등을 포함
- 사용자에게 응답을 보내기 위한 간단한 데이터 구조를 표현
- HTTP 응답 전체를 다루는 것이 아니라, 응답 내용에 중점보다 간결한 코드로 구성
이번 글에서 사용할 API 응답 방식은 ResponseEntity<ApiResponse> 를 사용하려고 한다.
ResponseEntity <ApiResponse> 사용하는 이유
- HTTP 상태 코드 및 헤더 제어
- HTTP 응답의 상태 코드와 헤더를 명시적으로 설정할 수 있다.
- ResponseEntity.ok() 대신에 ResponseEntity.status(HttpStatus.OK)) 를 사용하여 상태 코드를 설정할 수 있다. 응답의 성공 여부를 더 명확하게 전달 가능
- 다양한 응답 처리
- 아래 코드를 예시로 ResponseEntity.ok와 ApiResponse에서 선언한 OK 메서드를 통해
- HTTP 상태 코드인 200 값과 응답 값을 반환한다.
ResponseEntity.ok(ApiResponse.OK(mailSenderService.sendEmailForCertification(request.getEmail())))
ResponseEntity<ApiResponse> 단점(?)
아무래도 기존에 일반적으로 ApiResponse만 사용할 때보다 절차가 추가된 것이라, 코드를 더 많이 작성해야하며 코드 양이 많아질수록 응답 처리가 복잡해질 수 있다.
API 작성하기
ErrorCode
@Getter
@RequiredArgsConstructor
public enum ErrorCode {
INVALID_TOKEN(401, "Token이 유효하지 않습니다."),
ACCESS_DENIED(403, "접근 권한이 없습니다."),
MEMBER_NOT_FOUND(404, "존재하지 않는 회원입니다."),
AUTHENTICATION_FAILED(400, "아이디 또는 비밀번호가 옳지 않습니다.");
private final int code;
private final String msg;
}
ErrorCode는 Enum 타입으로 형성되어 있다. 팀원 혹은 타 팀과 협업 시 에러 코드를 직접 정의할 수 있다.
ApiBody
@AllArgsConstructor
@Getter
public class ApiBody<T> {
private T data;
private T msg;
}
위 사진과 같이 HTTP Response의 body 값을 나타낸다.
ApiHeader
@Getter
@AllArgsConstructor
public class ApiHeader {
private int resultCode;
private String codeName;
}
Header에서는 성공 혹은 실패 코드를 나타낸다.
ApiResponse<T>
@Getter
public class ApiResponse<T> {
private static final int SUCCESS = 200;
private final ApiHeader header;
private ApiBody body;
public ApiResponse(ApiHeader header, ApiBody body) {
this.header = header;
this.body = body;
}
public ApiResponse(ApiHeader header) {
this.header = header;
}
public static <T> ApiResponse<T> OK(T data) {
return new ApiResponse<T>(new ApiHeader(SUCCESS, "SUCCESS"), new ApiBody(data, null));
}
public static <T> ApiResponse<T> fail(ErrorCode errorCode) {
return new ApiResponse(new ApiHeader(errorCode.getCode(), errorCode.name()), new ApiBody(null, errorCode.getMsg()));
}
}
API 사용하기
@PostMapping("/send-certification")
public ResponseEntity<ApiResponse<EmailCertificationResponse>> sendCertificationNumber(@Validated @RequestBody EmailCertificationRequestDto request) throws MessagingException, NoSuchAlgorithmException {
return ResponseEntity.ok(ApiResponse.OK(mailSenderService.sendEmailForCertification(request.getEmail())));
}
예시로 이메일 인증 코드를 발급받는 API를 구성하였다.
위 사진과 같이 JSON 형태로 이메일 값을 입력하면 아래와 같이 header와 body로 응답 값을 보여주며, header에는 응답 코드를 보여주며 body에는 통신으로 주고받은 값들을 보여준다.
좀 어설프게 코드를 작성하였지만, API Response 부분은 개발자들 간에도 어떤 방식으로 전달하는지 말이 많다고 한다. 프로젝트를 마친 후에는 해당 부분에 대해서 좀 더 공부하고 리팩토링을 진행할 예정이다.
위 블로그에서 작성된 내용에 틀린 점이나 보완할 점을 발견하시고 댓글로 알려주신다면 너무너무 감사합니다.
'Backend > Spring || SpringBoot' 카테고리의 다른 글
[Spring || SpringBoot] Controller와 RestController 란? (2) | 2024.12.29 |
---|---|
[Spring || SpringBoot] MVC 패턴이란? 스프링 MVC와 Counter 앱 예제 (0) | 2024.11.03 |
[Spring || SpringBoot] Thymeleaf Layout - 타임리프 레이아웃 적용 하기 (1) | 2024.09.09 |
[Spring || SpringBoot] IPv4 설정 (0) | 2024.09.09 |
[Spring || SpringBoot] Spring에서 @Value로 Properties 값 가져오기 (0) | 2024.09.09 |