# API Design

> HTTP API의 계약을 새로 설계하거나 기존 계약을 바꿀 때 사용한다. "이 엔드포인트 어떻게 설계하지", "URL을 어떻게 나눌까", "이 응답 형식 괜찮나", "이렇게 바꾸면 클라이언트가 깨지나", "버저닝 어떻게 하지" 같은 요청에 트리거된다. 리소스 모델링, 상태 코드/오류 규약, 호환성 파괴 판단, 페이징·멱등성 규칙을 다룬다. 구현 계층 배치가 목적이면 java-spring-backend를, 이미 있는 구현을 평가하는 것이면 code-review를 쓴다.

- Skill: `j99way99/api-design` (Agent Skill)
- Install (CLI): `npx skillmds@latest add j99way99/api-design`
- Raw SKILL.md: https://api.skillmd.com/api/skills/j99way99/api-design/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- Author: j99way99 (https://skillmd.com/u/j99way99)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/j99way99/api-design

---


# API 설계

API 계약은 **한 번 공개되면 내 것이 아니다.** 바꾸는 비용을 먼저 계산하고 설계한다.

## 절차

1. **호출자와 사용 사례를 먼저 적는다.** 누가, 어떤 화면/작업에서, 얼마나 자주 부르는가.
   호출자가 정해지지 않은 엔드포인트는 설계할 수 없다.
2. **리소스와 동작을 분리한다.** 명사(리소스)를 먼저 정하고, 동작을 HTTP 메서드로 표현한다.
   표현이 어색하면 리소스를 잘못 잡은 것이다.
3. **실패 응답을 정상 응답보다 먼저 정한다.**
4. **호환성 영향을 판정한다.** (아래 기준)
5. **계약을 문서로 고정한다.** 구현이 아니라 계약이 진실이다.

## 리소스 모델링

- URL은 리소스를 가리키고 동작은 메서드로 표현한다: `POST /orders`, `GET /orders/{id}`
- 동사를 URL에 넣기 전에 리소스로 바꿀 수 있는지 본다. `POST /orders/{id}/cancel` 처럼
  상태 전이가 자연스러운 경우에만 동사를 허용한다.
- 중첩은 소유 관계가 진짜일 때만: `/orders/{id}/items`. 두 단계를 넘기지 않는다.
- 컬렉션은 복수형, 식별자는 경로에, 필터·정렬·페이징은 쿼리스트링에 둔다.
- 화면 하나를 위한 전용 엔드포인트를 만들기 전에, 그것이 재사용될지 판단한다.

## 상태 코드와 오류

- 200 조회/성공, 201 생성(+Location), 204 본문 없음
- 400 형식·검증 실패, 401 인증 없음, 403 권한 없음, 404 없음, 409 상태 충돌, 422 의미 검증 실패
- 429 제한 초과, 5xx 서버 결함
- **오류 응답 형식을 하나로 고정한다.** 최소한: 기계가 읽는 코드, 사람이 읽는 메시지,
  필드 단위 오류 목록.
- 오류 메시지에 내부 구조(스택, 쿼리, 테이블명)를 노출하지 않는다.
- 부분 성공은 200으로 감추지 않는다. 어떤 것이 실패했는지 본문에 담거나 요청을 쪼갠다.

## 호환성

**깨는 변경(새 버전 필요)**
- 필드/엔드포인트 제거, 이름 변경
- 타입 변경, 값 형식 변경
- 선택 필드를 필수로 변경
- 기본 동작 변경(기본 정렬, 기본 페이지 크기 등 호출자가 의존하는 것)

**깨지 않는 변경**
- 선택 필드 추가, 새 엔드포인트 추가
- 새 열거값 추가 — 단, **클라이언트가 모르는 값을 만났을 때의 동작이 계약에 있을 때만**

버저닝은 필요해질 때 도입하고, 방식(URL 경로 / 헤더)을 프로젝트 전체에서 하나로 통일한다.
제거는 즉시 하지 않는다: 새 것 추가 → 사용처 이전 → 사용량 0 확인 → 제거.

## 반드시 정해야 하는 것

- **페이징**: 방식(오프셋/커서), 기본 크기, 최대 크기. 상한 없는 목록 조회를 열지 않는다.
- **멱등성**: 재시도가 안전한가. POST 계열은 멱등키를 받을지 정한다.
- **시각 표현**: ISO-8601 + 타임존 기준을 고정한다.
- **인증 주체**: 요청 본문의 사용자 ID를 신뢰하지 않는다. 토큰에서 얻는다.
- **정렬 기준**: 목록 응답에 안정적인 정렬이 없으면 페이징이 중복/누락을 만든다.

## 보고 형식

```
엔드포인트: <메서드 경로>
호출자/용도:
요청: <파라미터·본문 + 검증 규칙>
응답: <성공 형태>
오류: <상태코드 → 상황>
호환성: <깨는 변경 여부와 이전 계획>
```

실제 엔드포인트 목록·필드명·도메인 규칙은 **각 프로젝트의 문서**에 둔다.

