"Status code 가 '뭔가 잘못됨' 말함. Error body 가 client 한테 뭐가 잘못됐는지, 왜, 그에 대해 뭘 할지 알려주는 곳. 구조화된 body 없으면 모든 error 가 똑같이 보이고 support 인박스가 차."
Error body 가 해야 하는 일
잘 설계된 error response 가 자주 한 번에 네 청중 서빙:
- 최종 사용자, UI error 메시지 보고 뭘 고쳐야 하는지 알아야.
- 통합하는 개발자, client 코드 debug 중이고 분기할 machine-readable code 필요.
- Support desk 의 on-call 엔지니어, server 로그와 correlate 위해 request ID 필요.
- 자동 monitoring, code 별 error 세고 outlier 감지 원함.
Status code 하나가 넷 다 운반 못 함. Body 가 해야.
최소 envelope
필드 셋이 80% 케이스 커버:
{
"error": {
"code": "invalid_email_format",
"message": "이메일 주소 'pippa@@example.com' 가 유효하지 않습니다.",
"request_id": "req_xyz789"
}
}
code 가 machine-readable 식별자 — client 가 여기서 분기, 절대 human 메시지에서 안 함. message 가 사람용 (그리고 점점 API response 읽는 AI 에이전트용). request_id 가 client 와 server 로그 사이 loop 닫음.
Multi-error envelope (validation)
Validation 에러는 특별: 한 request 에 문제 여러 (email malformed AND password 너무 짧음 AND age 음수). 하나씩 surface 하면 round trip 셋 강제. 다 돌려줘:
{
"error": {
"code": "validation_failed",
"message": "필드 3개에 대해 request validation 실패.",
"errors": [
{"field": "email", "code": "invalid_format", "message": "..."},
{"field": "password", "code": "too_short", "message": "...", "min": 8},
{"field": "age", "code": "out_of_range", "message": "...", "min": 0}
],
"request_id": "req_xyz789"
}
}
FastAPI + Pydantic 이 422 response 에 즉시 이거 해. 손수 짠 API 다수가 이거 underspecify 하고 client 가 어느 필드인지 안 말하고 "validation 실패" 표시 강제.
RFC 7807 — HTTP API 용 Problem Details
IETF 가 error envelope 를 RFC 7807 에 공식화, media type application/problem+json. 필드 다섯:
{
"type": "https://example.com/errors/invalid-email",
"title": "Invalid email format",
"status": 400,
"detail": "이메일 주소 'pippa@@example.com' 가 유효하지 않습니다.",
"instance": "/users/42"
}
type 이 error class 식별하는 안정 URI (뒤에 문서 가진 안정 code 로 생각). title 이 짧은 사람 요약. status 가 HTTP status 미러. detail 이 specific 메시지. instance 가 error 난 specific resource.
RFC 7807 은 일부 API (Microsoft, Spring Boot) 가 채택했고 대부분이 무시. 둘 다 동작. 원칙 — 안정 식별자 가진 구조화된 error body — 가 specific format 보다 더 중요.
if error_message == "User not found": ... 하는 client 절대 쓰지 마 — 그 string 이 usability 이유로 바뀔 수 있고, 이제 client 깸. 항상 안정 machine code 에서 분기. 두 필드 존재 이유 정확히 다른 청중 서빙이라서.아픈 안티패턴
진짜 API 에 나타나면 안 되는 패턴 다섯:
- {error: ...} 가진 200 OK — Cache 가 성공으로 다룸. Retry 로직 안 켜짐. Monitoring dashboard 가 다 깨졌는데 녹색. 항상 4xx 나 5xx 써.
- Plain string body. 전체 response 가
"User not found". Client 가 분기 못 함; localizer 가 번역 못 함; support 가 correlate 못 함. - Production 의 HTML stack trace. Server 내부 누설 (파일 경로, framework 버전, 환경 변수). 개발용 예약; production 엔 generic 메시지 + on-call 이 찾아볼 request_id 돌려줘.
- Endpoint 간 일관성 없는 shape.
/users는{error: ...}돌려줌;/orders는{message: ...};/payments는{detail: ...}. Client 가 포기. - Request_id 없음. User 가 error 보고할 때 support 가 해당 server 로그 찾을 방법 없음. 성공 response 에도 항상 request ID 포함해.
cwkPippa 의 error envelope
{detail: "..."}, 422 Pydantic 에러에 validation-array) 씀. 처음부터 설계하면 안 일관 — 단일 필드 detail 이 client 한테 machine-readable code 안 줌, request_id 없음. 근데 frontend 가 유일 client 이고 toast 메시지 위해 detail 읽어서 비용 아직 안 물음. 그 날 오면 (제 3자 client, support escalation), migration 이 구조화된 envelope 가진 custom 예외 handler 로 모든 거 감싸기.