-
Notifications
You must be signed in to change notification settings - Fork 1
conventions API Convention
Seoyoung Cho edited this page Jan 15, 2026
·
4 revisions
모든 API는 CommonApiResponse로 통일된 응답 형식을 사용합니다.
{
"code": "S200",
"message": "성공",
"data": { ... }
}SuccessCode는 global에서 통합 관리합니다.
-
공통 성공 코드 (
SuccessCode.java)
public enum SuccessCode implements SuccessType {
SUCCESS("S200", "성공");
private final String code;
private final String message;
SuccessCode(String code, String message) {
this.code = code;
this.message = message;
}
@Override
public String getCode() {
return code;
}
@Override
public String getMessage() {
return message;
}
}- Controller에서 사용
@GetMapping("/{id}")
public CommonApiResponse<UserResponseDto> getUser(@PathVariable Long id) {
UserResponseDto user = userService.getUser(id);
return CommonApiResponse.success(SuccessCode.USER_RETRIEVED, user);
}코드 네이밍 규칙
- S###: 공통 성공 코드
- CH###: Challenge 성공 코드
- 각 도메인별로 001부터 099까지 할당
도메인별 ErrorCode와 Exception을 사용하여 관리합니다.
GlobalExceptionHandler
├── BaseException (커스텀 비즈니스 예외 - 도메인별 Exception의 부모 클래스)
│ ├── UserException
│ ├── ChallengeException
│ ├── ProcedureException
│ ├── UserProcedureException
│ └── AiClientException
├── MethodArgumentNotValidException (@Valid 검증 실패)
├── ConstraintViolationException, HandlerMethodValidationException (메서드 파라미터 검증 실패 처리)
├── MissingRequestHeaderException (필수 요청 헤더 누락 처리)
├── IllegalArgumentException (입력 값 검증 실패 처리)
├── HttpMessageNotReadableException (JSON 파싱 실패)
├── ObjectOptimisticLockingFailureException (낙관적 락 충돌 처리)
└── Exception (그 외 모든 예외)
-
공통 에러 코드 (
global/response/error/ErrorCode.java)
public enum ErrorCode implements ErrorType {
// 공통 에러 (C001~C099)
INVALID_INPUT("C001", "입력값이 올바르지 않습니다", 400),
INVALID_FORMAT("C002", "데이터 형식이 올바르지 않습니다", 400),
CONCURRENT_UPDATE("C003", "다른 사용자가 동시에 수정했습니다. 다시 시도해주세요.", 409),
INTERNAL_SERVER_ERROR("C999", "서버 내부 오류가 발생했습니다", 500);
private final String code;
private final String message;
private final int status;
// 생성자 및 getter 생략
}-
도메인별 에러 코드 (각 도메인의
exception패키지에 위치)
// domain/user/exception/UserErrorCode.java
@Getter
@RequiredArgsConstructor
public enum UserErrorCode implements ErrorType {
// User 도메인 에러 (U001 ~ U099)
USER_NOT_FOUND("U001", "사용자를 찾을 수 없습니다", 404),
INVALID_USER_NAME("U002", "유효하지 않은 사용자 이름입니다", 400),
USER_ALREADY_EXISTS("U004", "이미 존재하는 사용자입니다", 409);
private final String code;
private final String message;
private final int status;
}- 도메인별 Exception 클래스
// domain/user/exception/UserException.java
public class UserException extends BaseException {
public UserException(UserErrorCode errorCode) {
super(errorCode);
}
}@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class UserService {
private final UserRepository userRepository;
public UserResponseDto getUser(Long id) {
// 도메인별 Exception과 ErrorCode 사용
User user = userRepository.findById(id)
.orElseThrow(() -> new UserException(UserErrorCode.USER_NOT_FOUND));
return UserResponseDto.from(user);
}
}- 도메인 패키지 내에
exception패키지 생성 -
XxxErrorCodeenum 생성 (ErrorType 구현) -
XxxException클래스 생성 (BaseException 상속)
코드 네이밍 규칙
- C###: 공통 에러 코드 (Common)
- U###: User 도메인
- UP###: UserProcedure 도메인
- P###: Procedure 도메인
- CH###: Challenge 도메인
- AI###: AI 도메인
- 각 도메인별로 001부터 099까지 할당
도메인별 에러 응답
{
"code": "U001",
"message": "사용자를 찾을 수 없습니다",
"data": null
}Validation 실패 시
{
"code": "C001",
"message": "입력값이 올바르지 않습니다",
"data": {
"email": "올바른 이메일 형식이 아닙니다",
"name": "이름은 필수입니다"
}
}Swagger를 통해 자동으로 API 문서가 생성됩니다.
- 개발 환경:
http://localhost:8080/swagger-ui/index.html - 배포 환경:
${SWAGGER_BASE_URL}/swagger-ui/index.html
@RestController
@RequestMapping("/api/users")
@RequiredArgsConstructor
@Tag(name = "User", description = "사용자 관련 API")
public class UserController {
private final UserService userService;
@Operation(
summary = "사용자 조회",
description = "사용자 ID로 사용자 정보를 조회합니다."
)
@ApiExceptions({UserErrorCode.class, ErrorCode.class})
@GetMapping("/{id}")
public CommonApiResponse<UserResponseDto> getUser(
@Parameter(description = "사용자 ID", required = true, example = "1")
@PathVariable Long id
) {
UserResponseDto response = userService.getUser(id);
return CommonApiResponse.success(SuccessCode.SUCCESS, response);
}
@Operation(
summary = "사용자 정보 수정",
description = "사용자의 이름 또는 나이를 수정합니다. 제공된 필드만 수정됩니다."
)
@ApiExceptions({UserErrorCode.class, ErrorCode.class})
@PatchMapping("/{id}")
public CommonApiResponse<UserResponseDto> updateUser(
@Parameter(description = "사용자 ID", required = true, example = "1")
@PathVariable Long id,
@Valid @RequestBody UserUpdateRequestDto request
) {
UserResponseDto response = userService.updateUser(id, request);
return CommonApiResponse.success(SuccessCode.SUCCESS, response);
}
}@ApiExceptions 어노테이션:
- 해당 API에서 발생 가능한 에러 코드들을 지정
- Swagger 문서에 자동으로 에러 응답 예시가 생성됨
- HTTP 상태 코드별로 그룹화되어 표시
예시:
@ApiExceptions({UserErrorCode.class, ErrorCode.class})위 코드는 Swagger에서 다음과 같이 표시됩니다:
- 400 Bad Request:
INVALID_INPUT,INVALID_FORMAT등 - 404 Not Found:
USER_NOT_FOUND - 500 Internal Server Error:
INTERNAL_SERVER_ERROR
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Schema(description = "회원 생성 요청")
public class UserRequestDto {
@Schema(description = "회원 이름", example = "홍길동", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "이름은 필수입니다")
private String name;
@Schema(description = "이메일 주소", example = "hong@example.com", requiredMode = Schema.RequiredMode.REQUIRED)
@Email(message = "올바른 이메일 형식이 아닙니다")
private String email;
}
@Getter
@Builder
@Schema(description = "회원 정보 응답")
public class UserResponseDto {
@Schema(description = "회원 ID", example = "1")
private Long id;
@Schema(description = "회원 이름", example = "홍길동")
private String name;
@Schema(description = "이메일 주소", example = "hong@example.com")
private String email;
@Schema(description = "생성일시", example = "2024-01-15T10:30:00")
private LocalDateTime createdAt;
}| 어노테이션 | 사용 위치 | 설명 |
|---|---|---|
@Tag |
Controller 클래스 | API 그룹 정의 |
@Operation |
Controller 메서드 | API 설명 (summary, description) |
@ApiExceptions |
Controller 메서드 | 발생 가능한 에러 코드 지정 (자동 문서화) |
@Parameter |
메서드 파라미터 | 파라미터 설명 (description, required, example) |
@Schema |
DTO 클래스/필드 | 스키마 설명 |