API 계약 설계: 입력 검증·오류 응답·버전 변경
주문 생성 요청을 예로 필드 검증, 상태 코드, 재시도, 호환성 기준을 정합니다.
API 문서가 짧다고 사용하기 쉬운 것은 아닙니다. 주문을 생성하는 요청 하나만 보더라도 필드 누락, 중복 전송, 권한 부족, 재고 부족을 호출자가 구분할 수 있어야 합니다. 먼저 성공과 실패의 계약을 작성한 뒤 구현합니다.
요청에서 결정하면 안 되는 값
가상의 주문 요청은 상품 ID와 수량을 받을 수 있지만 결제 금액과 소유자 권한을 요청 본문 그대로 믿어서는 안 됩니다. 가격은 서버의 기준으로 계산하고 사용자 신원은 인증 문맥에서 가져옵니다. 브라우저 검증은 편의 기능이며 서버 검증을 대신하지 않습니다.
{"product_id": "demo-7", "quantity": 2}
수량은 정수인지, 허용 범위 안인지 검사합니다. 빈 문자열, null, 음수, 과도하게 큰 수를 각각 어떻게 처리할지 정합니다. 허용하지 않는 필드를 무시할지 오류로 돌려줄지도 일관되게 정해야 합니다.
오류를 호출자가 분기할 수 있게
{
"error": {
"code": "INVALID_QUANTITY",
"message": "수량을 확인해 주세요.",
"field": "quantity"
}
}
위 응답은 형식을 설명하는 예제입니다. 기계가 사용할 안정적인 코드와 사람이 읽을 문구를 구분하면 문구를 개선해도 클라이언트 분기가 깨지지 않습니다. 내부 스택, SQL, 비밀 토큰을 사용자 응답에 넣지 않습니다.
400은 잘못된 요청, 401은 인증 문제, 403은 접근 거부, 409는 상태 충돌 같은 상황을 표현할 때 검토할 수 있습니다. 구체적인 계약은 서비스 문서에 명시하고 모든 오류를 200으로 감싸 호출자가 본문을 추측하게 만들지 않습니다.
타임아웃 뒤 재시도는 중복을 만들 수 있다
클라이언트가 응답을 받지 못했어도 서버에서는 주문이 만들어졌을 수 있습니다. 쓰기 요청에는 멱등성 키와 동일 키·다른 본문 충돌 규칙을 설계합니다. 안전한 재시도는 호출 횟수를 늘리는 설정만으로 완성되지 않습니다. 처리 상태 저장 방법은 웹훅 수신 설계와 비슷한 문제를 가집니다.
버전 변경은 소비자의 관점에서
필드 추가가 항상 호환되는 것은 아닙니다. 엄격한 스키마 검증을 하는 클라이언트가 있을 수 있고, enum 값 추가도 처리되지 않은 분기를 만들 수 있습니다. 필드 삭제나 의미 변경 전에는 실제 소비자와 지원 기간을 확인합니다.
구버전 요청과 새 요청의 예제, 오류 응답, 이전 종료 조건을 함께 문서화합니다. URL에 버전 번호를 붙였다는 사실보다 두 버전이 공존하는 동안 어떤 동작을 보장하는지가 중요합니다.