[SpringBoot] 공통 응답 객체 설계하기 🔍 | 실제 예시 ⭕️ | ErrorCode, ApiResponse, ResponseCode

2025. 9. 21. 15:22·✏️공부/💡SpringBoot
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)에 대한 설명

  1. 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
'✏️공부/💡SpringBoot' 카테고리의 다른 글
  • [JPA] 트러블슈팅🚀 | N+1 문제 | Fetch Join 대신 DTO Projection을 선택한 이유
  • ✏️싱글톤(Singleton) 컨테이너
  • ✏️스프링 컨테이너와 스프링 빈
  • ✏️알림 메시지 띄우기 (feat.Thymeleaf)
망꼬누나
망꼬누나
공부한 내용을 정리하는 공간입니다.
  • 망꼬누나
    망꼬누나의 개발 공부
    망꼬누나
  • 전체
    오늘
    어제
    • 분류 전체보기 (165)
      • ℹ️ 정보 및 실습 (19)
        • ☑️ Git & GitHub (8)
        • ☑️ 프로젝트 (6)
        • ☑️ 회고 및 후기 (5)
      • 🛠 CS (1)
      • 💻코딩 (88)
        • 💡Baekjoon (17)
        • 💡Programmers (71)
      • ✏️공부 (48)
        • 💡OS (1)
        • 💡Network (6)
        • 💡SpringBoot (9)
        • 💡JAVA (21)
        • 💡SQL (1)
        • 💡DB (2)
        • ☁️ Cloud (4)
        • 💡알고리즘 (4)
      • 📌 자격증 (6)
        • 📝정보처리기사 (3)
        • 📝SQLD (3)
  • 블로그 메뉴

    • 홈
    • github
  • 나의 GitHub Contribution 그래프
    Loading data ...
  • 인기 글

  • 태그

    자료구조
    알고리즘
    프로그래머스
    동시성제어
    github
    Stream
    자바
    코딩테스트
    AWS
    baekjoon
    Java
    GIT
    데브코스
    프로그래머스 #JAVA
    Set
    백엔드
    map
    트랜잭션
    S3
    네트워크
  • 최근 댓글

  • 최근 글

  • 250x250
    반응형
  • hELLO· Designed By정상우.v4.10.5
망꼬누나
[SpringBoot] 공통 응답 객체 설계하기 🔍 | 실제 예시 ⭕️ | ErrorCode, ApiResponse, ResponseCode
상단으로

티스토리툴바