728x90
반응형
🔍 공통 응답 객체 설계하기
: ErrorCode, ApiResponse, ResponseCode
1. 공통 응답 객체란?
- API 서버에서 클라이언트로 응답을 줄 때, 일관된 형식으로 전달하는 것이 중요 ⭐️
- 예를 들어, 어떤 API는 { data: ... }만 반환하고, 또 다른 API는 { result: ... } 형식으로 반환한다면 클라이언트 입장에서 처리하기가 복잡해짐
➡️ 이를 해결하기 위해 공통 응답 객체(ApiResponse)를 만들어두면, 모든 API 응답이 같은 구조를 갖게 되어 유지보수성과 확장성이 높아짐
✚ Swagger 작성 시에 진행하면 좋음
2. 공통 응답 객체 설계
📍 ApiResponse 클래스
- API 응답을 표준화하기 위한 공통 응답 객체
- 모든 API가 같은 구조(code, message, data)를 가지도록 강제하는 역할
📚 @AllArgsConstructor를 붙인 이유
- ApiResponse 클래스는 code, message, data 세 가지 필드 가짐
➡️ 이 객체를 생성하려면 모든 필드를 초기화하는 생성자 필요
➡️ 즉, 팩토리 메서드(success, error, create)에서
new ApiResponse<>(...)를 호출할 때, 생성자가 자동으로 제공되므로 편리하게 객체를 만들 수 있음
@AllArgsConstructor
@Getter
public class ApiResponse <T> {
private String code;
private String message;
private T data;
public static <T> ApiResponse<T> success(T data) {
return new ApiResponse<>(ResponseCode.OK.getCode(), ResponseCode.OK.getMessage(), data);
}
public static <T> ApiResponse<T> success() {
return new ApiResponse<>(ResponseCode.OK.getCode(), ResponseCode.OK.getMessage(), null);
}
public static <T> ApiResponse<T> create() {
return new ApiResponse<>(ResponseCode.CREATED.getCode(), ResponseCode.CREATED.getMessage(), null);
}
public static <T> ApiResponse<T> error(ResponseCode code) {
return new ApiResponse<>(code.getCode(), code.getMessage(), null);
}
public static <T> ApiResponse<T> error(ErrorCode code) {
return new ApiResponse<>(code.getCode(), code.getMessage(), null);
}
}
✅ 성공 응답(success, create)에 대한 설명
- success(T data)
- 요청이 정상적으로 처리되었을 때(200 OK)
- 결과 데이터를 함께 반환하는 경우
- 예: 회원 조회, 게시글 상세 조회
{
"code": "200",
"message": "정상적으로 완료되었습니다.",
"data": {
"id": 1,
"name": "홍길동"
}
}
2. success()
- 요청은 성공했지만 별도의 반환 데이터가 필요 없는 경우
- 예: 로그아웃 API, 상태 확인 API
{
"code": "200",
"message": "정상적으로 완료되었습니다.",
"data": null
}
3. create()
- 리소스가 성공적으로 생성되었을 때(201 Created)
- 주로 POST 요청에서 사용
- 데이터가 없어도 생성 성공 사실을 알려주기 위한 용도
{
"code": "201",
"message": "정상적으로 생성되었습니다.",
"data": null
}
📍 ResponseCode (성공/실패 기본 응답 코드)
@Getter
public enum ResponseCode {
OK("200", HttpStatus.OK, "정상적으로 완료되었습니다."),
CREATED("201", HttpStatus.CREATED, "정상적으로 생성되었습니다."),
BAD_REQUEST("400", HttpStatus.BAD_REQUEST, "잘못된 요청입니다."),
UNAUTHORIZED("401", HttpStatus.UNAUTHORIZED, "권한 정보가 없습니다."),
INTERNAL_SERVER_ERROR("500", HttpStatus.INTERNAL_SERVER_ERROR, "서버 에러 입니다.");
private final String code;
private final HttpStatus status;
private final String message;
ResponseCode(String code, HttpStatus status, String message) {
this.code = code;
this.status = status;
this.message = message;
}
}
- 전체적으로 자주 쓰일 응답 생성
- 작자는 로그인 기능이 포함되므로 위와 같이 생성
✅ ErrorCode (도메인/비즈니스별 에러 코드)
@Getter
public enum ErrorCode {
CONFLICT_REGISTER("U001",HttpStatus.CONFLICT, "이미 가입된 회원입니다."),
NOT_FOUND_MEMBER("U002", HttpStatus.NOT_FOUND, "존재하지 않는 회원입니다."),
NICKNAME_ALREADY_EXISTS("U003", HttpStatus.CONFLICT, "이미 사용 중인 닉네임입니다."),
BAD_CREDENTIAL("U004", HttpStatus.UNAUTHORIZED, "아이디나 비밀번호가 틀렸습니다."),
INVALID_TOKEN("U005", HttpStatus.UNAUTHORIZED, "유효하지 않은 토큰입니다."),
EXPIRED_TOKEN("U006", HttpStatus.UNAUTHORIZED, "엑세스 토큰이 만료되었습니다. 토큰을 갱신해주세요."),
NOT_EXIST_PRE_AUTH_CREDENTIAL("U007", HttpStatus.UNAUTHORIZED, "사전 인증 정보가 요청에서 발견되지 않았습니다."),
SECURITY_INCIDENT("U008", HttpStatus.OK, "비정상적인 로그인 시도가 감지되었습니다."),
SOCIAL_LOGIN_FAILED("U009", HttpStatus.UNAUTHORIZED, "소셜 로그인 인증에 실패했습니다."),
EMAIL_VERIFICATION_FAILED("U010", HttpStatus.BAD_REQUEST, "이메일 인증에 실패했습니다.");
private final String code;
private final HttpStatus status;
private final String message;
ErrorCode(String code, HttpStatus status, String message) {
this.code = code;
this.status = status;
this.message = message;
}
}
- 도메인 / 비즈니스별 발생할만한 오류 생성
- U001 : 커스텀 오류 코드
- 정해진 것 없이 프론트, 백엔드끼리 정한 코드번호
- "U로 시작하니 User 문제이군" ➡️ "NOT_FOUND이니 가입되지 않은 회원 문제로 유추 할 수 있겠다"
- 위와 같은 흐름으로 유추 가능 ⭕️
- 작자는 로그인 기능을 맡았기에 초기에 위와 같이 만들었음
- 각자 도메인에 맡게 추가하면 됨
✅ 에러 응답
{
"code": "U002",
"message": "존재하지 않는 회원입니다.",
"data": null
}
728x90
반응형
'✏️공부 > 💡SpringBoot' 카테고리의 다른 글
| [JPA] 트러블슈팅🚀 | N+1 문제 | Fetch Join 대신 DTO Projection을 선택한 이유 (0) | 2025.10.27 |
|---|---|
| ✏️싱글톤(Singleton) 컨테이너 (3) | 2024.01.24 |
| ✏️스프링 컨테이너와 스프링 빈 (1) | 2024.01.18 |
| ✏️알림 메시지 띄우기 (feat.Thymeleaf) (0) | 2023.11.29 |
| [spring] thymeleaf 활용 (2) | 2023.09.06 |
