오류 및 응답
모든 공개 API 엔드포인트는 예측 가능한 응답 형식을 반환합니다. 오류는 본문에 안정적인 기계 판독 가능한 코드를 포함하므로 영어를 파싱하지 않고도 분기할 수 있습니다.
응답 봉투
성공 응답은 리소스(또는 리소스 목록)를 직접 반환합니다. 최상위 래퍼는 없습니다 — 클라이언트는 타입이 지정된 모델로 직접 역직렬화할 수 있습니다:
GET /api/public/v1/org
{
"id": "e188fc87-…",
"name": "Acme Corp",
"plan": "growth",
…
}실패 응답은 유일한 필수 필드로 error 코드를 포함하는 작고 균일한 형식을 사용합니다. 선택적 필드는 호출을 수정하는 데 도움이 되는 컨텍스트를 제공합니다:
{
"error": "insufficient_scope",
"required": "assignments:write",
"present": ["assignments:read", "users:read"]
}상태 코드 참조
| 상태 | 표시 시점 | 처리 방법 |
|---|---|---|
200 | 요청 성공. 본문에 리소스 또는 확인 메시지가 들어 있습니다. | 본문을 처리합니다. |
400 | 잘못된 형식의 요청: 필수 필드 누락, 잘못된 열거형 값, 본문 너무 큼, 파싱할 수 없는 JSON입니다. | 클라이언트 요청을 수정하세요 — 동일한 페이로드로 재시도하지 마세요. |
401 | 누락, 잘못된 형식, 취소 또는 만료된 토큰입니다. | Authorization 헤더를 확인하세요. 토큰이 취소된 경우 회전하세요. |
403 | 토큰은 유효하지만 필요한 범위가 없습니다. | 관리자 UI에서 범위를 추가하세요. 응답에는 정확한 범위 이름이 포함되어 있습니다. |
404 | 리소스가 존재하지 않거나 다른 조직에 속합니다. | 상위 컬렉션을 다시 가져오세요. 조직 간에 오래된 ID를 따르지 마세요. |
409 | 충돌 — 예를 들어 이메일이 이미 사용 중입니다. | 작업이 멱등성이 있는 경우 성공으로 취급하세요. |
413 | 요청 본문이 엔드포인트별 한도를 초과합니다. 하드 오버플로의 경우 Kestrel이 반환합니다. SARIF 엔드포인트도 선언된 Content-Length가 10 MB를 초과할 때 이를 400 body_too_large로 반환합니다. | 페이로드를 줄이세요. SARIF의 경우 한 번에 한 도구의 결과만 증분 수집하세요. |
429 | 이 API 키에서 속도 제한에 도달했습니다. | Retry-After을 존중하세요. 속도 제한을 참조하세요. |
5xx | 서버 측 문제입니다. | 지수 백오프와 함께 재시도하세요. 응답 X-Request-Id 헤더를 캡처하고 모든 지원 티켓에 인용하세요. |
오류 코드
error 필드는 버전 간에 안정적입니다 — 동일한 상태가 서로 다른 코드를 전달할 수 있으므로 HTTP 상태가 아니라 클라이언트 코드에서 분기하세요:
| 코드 | 상태 | 의미 |
|---|---|---|
unauthorized | 401 | 요청에 사용 가능한 bearer 토큰이 없습니다. |
insufficient_scope | 403 | 토큰은 괜찮지만 범위가 누락되었습니다. 응답에 required 및 present가 포함됩니다. |
rate_limited | 429 | 한도 초과. Retry-After 헤더를 참조하세요. |
user_not_found | 404 | 사용자 ID가 존재하지 않거나 조직에 속하지 않습니다. |
team_not_found | 404 | 팀 ID가 존재하지 않거나 조직에 속하지 않습니다. |
assignment_not_found | 404 | 과제 ID가 존재하지 않거나 조직에 속하지 않습니다. |
empty_body | 400 | 본문이 필요한 곳에 본문 없이 전송된 POST 또는 PATCH입니다. |
body_too_large | 400 / 413 | 요청 본문이 엔드포인트 한도를 초과했습니다. SARIF는 선언된 Content-Length가 너무 클 때 본문에 maxBytes를 포함하여 이를 400으로 발행합니다. 본문이 실제로 오버런되면 Kestrel이 빈 413을 발행합니다. |
요청 ID
모든 응답에는 X-Request-Id 헤더(UUID v4)가 포함됩니다. 클라이언트 측에서 캡처하고 지원 요청에 포함시키세요 — 실패한 호출의 정확한 서버 측 추적을 가져올 수 있습니다. 5xx 응답의 경우 요청 ID가 진단의 가장 빠른 단일 경로입니다.
유효성 검사 오류
POST 및 PATCH 본문의 유효성 검사 실패는 첫 번째 실패한 규칙을 설명하는 플랫 error와 함께 400를 반환합니다. 다중 필드 유효성 검사 노출은 v1의 일부가 아닙니다 — 보고된 첫 번째 필드를 수정하고 재시도하세요. 향후 버전에서는 필드별 상세 정보를 추가할 수 있으며, 최상위 error 계약은 유지됩니다.
오류에서 분기하기 — 예제
const res = await fetch(url, { headers });
if (res.ok) return res.json();
const body = await res.json().catch(() => ({}));
switch (body.error) {
case 'rate_limited':
return retryWithBackoff(url);
case 'insufficient_scope':
throw new Error(`API key missing scope: ${body.required}`);
case 'unauthorized':
throw new Error('API key revoked or invalid — rotate the secret');
default:
throw new Error(`API error ${res.status}: ${body.error || 'unknown'}`);
}