API 안정성 설계 (보호계층, 장애방지, 관측체계)

API 안정성은 단일 기술로 해결되는 문제가 아닙니다. 다양한 전략과 패턴이 결합되어야 비로소 안정적인 시스템을 구축할 수 있습니다. 지금까지 살펴본 다양한 요소들은 각각 독립적인 기능이 아니라, 서로 연결된 구조를 형성합니다. 이 글에서는 API 안정성을 구성하는 핵심 요소를 종합적으로 정리하고, 실무에서 반드시 구축해야 하는 기준을 제시합니다. 서비스가 갑자기 죽었을 때 가장 먼저 드는 생각은 "왜 미리 못 잡았지?"입니다. 저도 새벽에 슬랙 알림을 받고 노트북을 열었던 기억이 있습니다. 알고 보니 외부 결제 API 하나가 느려지면서 연결을 잡고 놓지 않아 전체 서버 스레드가 고갈된 케이스였습니다. Rate Limiting도 없었고, Timeout 설정도 기본값 그대로였습니다. 그때 처음으로 API 안정성 설계가 단순한 '선택 사항'이 아니라는 걸 몸으로 배웠습니다. 기본 보호 계층, 왜 설정하지 않는가 Rate Limiting, Timeout, Retry. 이 세 가지는 API 안정성의 가장 기초적인 보호 계층입니다. Rate Limiting은 단위 시간 내에 허용할 요청 수를 제한하는 방식으로, 트래픽 급증이나 악의적인 과부하 공격으로부터 서버를 지킵니다. Timeout은 응답을 기다리는 최대 시간을 설정하는 것인데, 이게 없으면 느린 외부 서비스 하나가 커넥션 풀 전체를 잠가버릴 수 있습니다. Retry는 일시적 오류에 대해 요청을 자동으로 재시도하는 전략입니다. 그런데 여기서 주의할 점이 있습니다. Retry를 아무 생각 없이 붙이면 오히려 장애를 악화시킵니다. 이미 느린 서버에 재시도가 폭주하면 부하가 기하급수적으로 올라가기 때문입니다. 그래서 Exponential Backoff, 즉 재시도 간격을 점점 늘려가는 방식과 함께 써야 효과가 납니다. 이 조합을 적용하고 나서 저희 팀에서 일시적 오류로 인한 실패율이 체감상 절반 이하로 줄었습니다. 일반적으로 이 설정들은 기본값으로도 충분하다고 생각하는 분...

API Boolean 필드 (상태 확장, 설계 판단, 구조 변경)

API 설계할 때 Boolean 필드 하나 넣는 게 뭐가 어렵겠냐고 생각하셨나요? true와 false 두 개로 끝나니까 간단하고 명확하다고 생각했죠. 그런데 프로젝트를 진행하다 보면 이 단순함이 독이 될 때가 있습니다. 특히 서비스가 성장하면서 새로운 상태가 추가되어야 할 때, Boolean 구조로는 도저히 표현할 방법이 없어서 API 전체를 뜯어고쳐야 하는 상황이 생깁니다.

상태 확장

Boolean 필드의 가장 큰 문제는 딱 두 가지 상태만 표현할 수 있다는 점입니다. 활성(active)이냐 비활성이냐, 삭제됐느냐 안 됐느냐처럼 명확히 나뉘는 경우엔 완벽하게 작동합니다. 그런데 비즈니스 요구사항은 절대 그 자리에 가만히 있지 않습니다.

게시글 공개 여부를 관리하는 API를 만들 때 처음엔 public이라는 Boolean 필드 하나로 충분했습니다. 공개냐 비공개냐 두 가지만 있으면 됐으니까요. 그런데 몇 달 뒤 기획팀에서 예약 공개 기능을 요청했습니다. 특정 시간에 자동으로 공개되는 기능이었죠. 여기서 문제가 생겼습니다. 예약 상태를 Boolean으로 어떻게 표현할 수 있겠습니까?

어떤 분들은 Boolean 필드를 여러 개 만들면 되지 않냐고 하실 수 있습니다. public, scheduled, under_review 이런 식으로 필드를 계속 추가했죠. 그런데 이렇게 하면 상태 관리가 복잡해집니다. 한 게시글이 public=true, scheduled=true 이런 모순된 값을 가질 수도 있고, 클라이언트에서 여러 필드를 조합해서 판단해야 하니 오류가 생길 가능성이 커집니다(출처: Martin Fowler).

설계 판단

그렇다면 Boolean을 아예 쓰지 말아야 할까요? 그건 아닙니다. 핵심은 언제 Boolean을 쓰고 언제 다른 구조를 써야 하는지 판단하는 것입니다. 다음과 같은 기준으로 판단 할 수 있습니다.

  1. 앞으로도 상태가 두 가지로만 유지될 가능성이 높은가
  2. 이 필드가 다른 시스템 로직과 독립적으로 작동하는가
  3. 상태 변경 이력을 추적할 필요가 없는가

이 세 가지 조건을 모두 만족하면 Boolean을 써도 괜찮습니다. 예를 들어 사용자 이메일 수신 동의 같은 경우는 동의와 거부 두 가지만 있고, 향후에도 중간 상태가 생길 가능성이 거의 없습니다. 이런 경우엔 Boolean이 최선의 선택입니다.

반면 워크플로우가 관련된 상태라면 처음부터 Enum이나 상태 코드를 고려하는 게 좋습니다. 주문 상태, 결제 상태, 콘텐츠 검토 상태처럼 여러 단계를 거치는 프로세스는 나중에 꼭 새로운 상태가 추가됩니다. 솔직히 이건 예상 밖이 아니라 당연한 겁니다. 서비스가 성장하면 비즈니스 로직도 복잡해지거든요.

개발자 관점에서 Boolean은 처리가 간단합니다. if 문 하나로 분기 처리가 끝나니까요. 하지만 API는 클라이언트와 계약입니다. 한번 배포하면 쉽게 바꿀 수 없습니다. 특히 외부에 공개된 API라면 더욱 그렇죠. 그래서 초기 설계 단계에서 확장 가능성을 고려하는 게 중요합니다.

구조 변경

Boolean 구조를 Enum으로 변경하는 작업은 생각보다 고통스럽습니다. 단순히 필드 타입만 바꾸는 게 아니라 전체 시스템에 영향을 미치기 때문입니다.

앞서 말씀드린 게시글 공개 여부 사례에서, 결국 public Boolean 필드를 status Enum 필드로 교체했습니다. 상태 값은 DRAFT, PUBLIC, SCHEDULED, UNDER_REVIEW 네 가지로 정의했죠. 이 과정에서 기존 데이터 마이그레이션이 필요했습니다. public=true는 PUBLIC으로, public=false는 DRAFT로 변환하는 스크립트를 작성했습니다.

더 큰 문제는 클라이언트 대응이었습니다. 모바일 앱, 웹 프론트엔드, 파트너사 연동 시스템까지 모두 API 응답 구조가 바뀌는 것에 대응해야 했습니다. 하위 호환성(backward compatibility)을 유지하기 위해 한동안 public 필드와 status 필드를 동시에 제공하고, 공지를 통해 점진적으로 마이그레이션을 유도했습니다. 이 과정이 약 3개월 정도 걸렸습니다.

이런 경험을 통해 배운 건, API 설계는 현재뿐 아니라 미래를 함께 고려해야 한다는 점입니다. Boolean 필드는 단순하고 명확하지만, 그 단순함이 나중에 족쇄가 될 수 있습니다. 반대로 모든 필드를 Enum으로 만드는 것도 과도한 설계입니다. 중요한 건 각 상황에서 적절한 균형점을 찾는 것입니다.

API Boolean 필드 설계는 단순성과 확장성 사이의 줄타기입니다. 제 조언은 이렇습니다. 정말 확실하게 두 가지 상태만 필요한 경우에만 Boolean을 쓰세요. 조금이라도 의심스럽다면 처음부터 Enum으로 시작하는 게 나중에 고생을 덜 합니다. 설계 단계에서 10분 더 고민하는 것이, 나중에 3개월짜리 마이그레이션 프로젝트를 막을 수 있습니다.

댓글

이 블로그의 인기 게시물

HTTP 메서드의 필요성 (GET과 POST, PUT과 DELETE, API 보안)

API 없는 세상의 불편함 (로그인 연동, 서비스 구조, 디지털 인프라)

API 이해하기 (서비스 연결, 시스템 협력, 디지털 구조)