API 에러 설계 패턴. 에러 코드 체계, 에러 응답 구조, 클라이언트 친화적 에러 메시지, 에러 카탈로그 구축, retry/fallback 전략을 제공하는 doc-writer/mock-tester 확장 스킬. 'API 에러 설계', '에러 코드', '에러 응답', '에러 카탈로그', '에러 메시지', 'retry 전략' 등 API 에러 처리 체계 설계 시 사용한다. 단, 실제 에러 핸들링 코드 구현은 이 스킬의 범위가 아니다.
Scanned 5/29/2026
Install via CLI
openskills install revfactory/harness-100---
name: api-error-design
description: "API 에러 설계 패턴. 에러 코드 체계, 에러 응답 구조, 클라이언트 친화적 에러 메시지, 에러 카탈로그 구축, retry/fallback 전략을 제공하는 doc-writer/mock-tester 확장 스킬. 'API 에러 설계', '에러 코드', '에러 응답', '에러 카탈로그', '에러 메시지', 'retry 전략' 등 API 에러 처리 체계 설계 시 사용한다. 단, 실제 에러 핸들링 코드 구현은 이 스킬의 범위가 아니다."
---
# API Error Design — API 에러 설계 패턴
doc-writer와 mock-tester 에이전트가 API 에러 문서화 및 테스트 설계 시 활용하는 에러 체계, 메시지 설계, 복구 전략 레퍼런스.
## 대상 에이전트
- `doc-writer` — 에러 레퍼런스 문서 작성에 적용
- `mock-tester` — 에러 시나리오 테스트 설계에 적용
## 에러 코드 체계 설계
### 계층적 에러 코드 구조
```
{도메인}_{카테고리}_{상세}
예시:
AUTH_TOKEN_EXPIRED -- 인증 > 토큰 > 만료
ORDER_PAYMENT_DECLINED -- 주문 > 결제 > 거절
USER_VALIDATION_EMAIL -- 사용자 > 유효성 > 이메일
```
### 도메인별 에러 코드 카탈로그
#### 인증/인가 (AUTH)
| 코드 | HTTP | 메시지 | 클라이언트 액션 |
|------|------|--------|---------------|
| AUTH_REQUIRED | 401 | 인증이 필요합니다 | 로그인 페이지로 이동 |
| AUTH_TOKEN_EXPIRED | 401 | 토큰이 만료되었습니다 | 토큰 갱신 시도 |
| AUTH_TOKEN_INVALID | 401 | 유효하지 않은 토큰입니다 | 재로그인 |
| AUTH_FORBIDDEN | 403 | 이 작업에 대한 권한이 없습니다 | 권한 요청 안내 |
| AUTH_ACCOUNT_LOCKED | 403 | 계정이 잠겼습니다. 15분 후 재시도하세요 | 대기 타이머 표시 |
| AUTH_INVALID_CREDENTIALS | 401 | 이메일 또는 비밀번호가 올바르지 않습니다 | 재입력 유도 |
#### 유효성 검증 (VALIDATION)
| 코드 | HTTP | 메시지 | 필드별 상세 |
|------|------|--------|-----------|
| VALIDATION_REQUIRED | 422 | 필수 필드가 누락되었습니다 | `{field}` 필드는 필수입니다 |
| VALIDATION_FORMAT | 422 | 형식이 올바르지 않습니다 | 유효한 `{type}`을 입력하세요 |
| VALIDATION_RANGE | 422 | 범위를 벗어났습니다 | `{min}`~`{max}` 사이 값을 입력하세요 |
| VALIDATION_UNIQUE | 409 | 이미 사용 중인 값입니다 | 이 `{field}`는 이미 등록되어 있습니다 |
| VALIDATION_LENGTH | 422 | 길이 제한을 초과했습니다 | `{max}`자 이내로 입력하세요 |
#### 리소스 (RESOURCE)
| 코드 | HTTP | 메시지 |
|------|------|--------|
| RESOURCE_NOT_FOUND | 404 | 요청한 리소스를 찾을 수 없습니다 |
| RESOURCE_ALREADY_EXISTS | 409 | 이미 존재하는 리소스입니다 |
| RESOURCE_DELETED | 410 | 삭제된 리소스입니다 |
| RESOURCE_LOCKED | 423 | 리소스가 잠겨 있습니다 |
#### Rate Limit
| 코드 | HTTP | 메시지 |
|------|------|--------|
| RATE_LIMIT_EXCEEDED | 429 | 요청 한도를 초과했습니다. {retryAfter}초 후 재시도하세요 |
#### 서버 (SERVER)
| 코드 | HTTP | 메시지 |
|------|------|--------|
| SERVER_INTERNAL | 500 | 서버 오류가 발생했습니다. 잠시 후 재시도하세요 |
| SERVER_MAINTENANCE | 503 | 서비스 점검 중입니다 |
| SERVER_UPSTREAM | 502 | 외부 서비스 연결에 실패했습니다 |
## 에러 응답 구조 표준
### 기본 구조
```json
{
"error": {
"code": "AUTH_TOKEN_EXPIRED",
"message": "토큰이 만료되었습니다",
"detail": "access token의 유효기간이 지났습니다. refresh token으로 갱신하세요.",
"timestamp": "2025-03-15T09:30:00Z",
"requestId": "req_abc123def456",
"path": "/api/v1/users/me"
}
}
```
### 유효성 검증 에러 (필드별)
```json
{
"error": {
"code": "VALIDATION_ERROR",
"message": "입력값이 올바르지 않습니다",
"errors": [
{
"field": "email",
"code": "VALIDATION_FORMAT",
"message": "유효한 이메일 주소를 입력하세요",
"value": "invalid-email"
},
{
"field": "password",
"code": "VALIDATION_LENGTH",
"message": "비밀번호는 8자 이상이어야 합니다",
"constraint": { "min": 8 }
}
]
}
}
```
## 에러 메시지 작성 원칙
### 좋은 에러 메시지의 3요소
1. **무엇이 잘못됐는가** — 문제 설명
2. **왜 잘못됐는가** — 원인/제약 조건
3. **어떻게 해결하는가** — 구체적 액션
### Do / Don't
| Don't | Do |
|-------|---|
| "Error occurred" | "주문 생성에 실패했습니다" |
| "Invalid input" | "가격은 0보다 큰 숫자여야 합니다" |
| "Server error: NullPointerException at..." | "서버 오류가 발생했습니다. 잠시 후 재시도하세요" |
| "Access denied" | "이 주문을 수정할 권한이 없습니다. 관리자에게 문의하세요" |
| "Duplicate key constraint violation" | "이 이메일은 이미 등록되어 있습니다" |
### 다국어 에러 메시지 구조
```json
{
"error": {
"code": "VALIDATION_REQUIRED",
"message": "필수 필드가 누락되었습니다",
"messageKey": "error.validation.required",
"params": { "field": "email" }
}
}
```
## Retry/Fallback 전략
### Retry 가능 여부 판단
| HTTP 상태 | Retry 가능? | 전략 |
|----------|-----------|------|
| 408 | O | 즉시 재시도 |
| 429 | O | Retry-After 헤더 대기 후 |
| 500 | O (조건부) | 지수 백오프 |
| 502, 503, 504 | O | 지수 백오프 |
| 400, 401, 403, 404 | X | 클라이언트 수정 필요 |
| 409, 422 | X | 입력값 수정 필요 |
### 지수 백오프 (Exponential Backoff)
```
대기시간 = min(baseDelay * 2^attempt + jitter, maxDelay)
예시: baseDelay=1초, maxDelay=30초
시도 1: 1초 + 랜덤(0~500ms)
시도 2: 2초 + 랜덤(0~500ms)
시도 3: 4초 + 랜덤(0~500ms)
시도 4: 8초 + 랜덤(0~500ms)
최대 3~5회 시도
```
## 에러 테스트 시나리오 매트릭스
| 카테고리 | 테스트 케이스 | 기대 코드 |
|---------|------------|----------|
| 인증 없음 | Authorization 헤더 없이 요청 | 401 |
| 만료 토큰 | 만료된 JWT로 요청 | 401 |
| 권한 없음 | 다른 사용자 리소스 접근 | 403 |
| 존재하지 않는 ID | 랜덤 UUID로 조회 | 404 |
| 필수 필드 누락 | body에서 필수 필드 제거 | 422 |
| 잘못된 형식 | 이메일 필드에 "abc" | 422 |
| 중복 생성 | 같은 데이터로 POST 2회 | 409 |
| 대량 요청 | Rate Limit 초과 | 429 |
| 잘못된 JSON | `{invalid json` 전송 | 400 |
| 빈 바디 | Content-Length: 0 | 400 |
No comments yet. Be the first to comment!