💡 Key Takeaways
- The Foundation: Understanding REST Beyond the Buzzword
- Principle 1: Resources Are Nouns, Not Verbs
- Principle 2: HTTP Methods Mean What They Mean
- Principle 3: Status Codes Are Your Communication Protocol
핀테크 유니콘에서 수석 API 아키텍트로 3년을 보낸 저는 투자자에게 제품 데모 중 우리 모바일 앱이 화려하게 충돌하는 모습을 지켜봤습니다. 그 원인은? "더 많은 데이터는 항상 더 좋다"고 생각한 누군가가 47MB의 JSON을 반환하는 단일 API 엔드포인트 때문이었습니다. 그 수치스러운 순간과 그로 인해 발생한 200만 달러의 자금 지연은 API 디자인이 단순히 작동하게 만드는 것이 아님을 가르쳐 주었습니다. 이는 우아하고 예측 가능하며 지속 가능하게 작동하도록 만드는 것입니다.
💡 주요 요점
- 기초: 유행어를 넘어서 REST 이해하기
- 원칙 1: 리소스는 명사, 동사가 아니다
- 원칙 2: HTTP 메서드는 그 의미를 의미한다
- 원칙 3: 상태 코드는 당신의 커뮤니케이션 프로토콜이다
저는 마커스 첸입니다. 지난 12년 동안 하루에 50개의 요청에서 5000만 개의 요청까지 처리하는 API를 설계해왔습니다. 뛰어난 엔지니어들이 너무 복잡한 API를 만들어서 스스로도 6개월 후에는 사용하는 방법을 기억하지 못한 모습을 보았습니다. 또한, 주니어 개발자들이 문서화가 거의 필요 없을 정도로 직관적인 인터페이스를 만들어내는 것도 보았습니다. 그 차이는? 프레임워크, 언어 및 아키텍처 트렌드를 초월한 기본 원칙에 대한 약속입니다.
그래서 지금까지 제가 구축한 모든 성공적인 API를 안내해준 10가지 원칙을 공유하려고 합니다. 이 원칙들은 생산 사고, 사용자 피드백, 수많은 코드 리뷰를 통해 구축되었습니다. 이들은 이론적 이상이 아니라 제 팀이 수백 시간의 시간을 절약하고 수많은 통합 문제를 예방한 전투에서 검증된 가이드라인입니다.
기초: 유행어를 넘어서 REST 이해하기
특정 원칙에 대해 논의하기 전에 불편한 진실을 다루어봅시다: 대부분의 "REST API"는 실제로 RESTful하지 않습니다. 그것들은 JSON 응답을 가진 HTTP API로, 괜찮지만 REST라고 부르는 것은 두 바퀴가 있는 자전거를 오토바이라고 부르는 것과 같습니다. 로이 필딩의 원래 REST 논문에서는 여섯 가지 제약을 설명했으며, 대부분의 API는 그 중 최소 세 가지를 위반합니다.
실제로 중요한 것은 다음과 같습니다: REST는 API를 URL로 식별된 리소스 모음으로 취급하는 아키텍처 스타일입니다. 이는 표준 HTTP 메서드를 통해 조작됩니다. 이 접근 방식의 아름다움은 예측 가능성입니다. GET /users/123를 볼 때, 저는 문서를 읽지 않고도 그것이 무엇을 하는지 정확히 압니다. POST /users를 보면, 이는 새 사용자를 생성한다는 것을 알 수 있습니다. 이 일관성이 REST의 초능력입니다.
제 경험상, REST 원칙을 진정으로 이해하는 팀은 REST를 체크 박스로 여기는 팀보다 API를 40% 더 빠르게 출시합니다. 왜 그럴까요? REST는 디자인 결정을 안내하는 정신 모델을 제공합니다. 이것이 새로운 엔드포인트여야 합니까, 아니면 쿼리 매개변수여야 합니까? REST가 답을 줍니다. 이것이 POST여야 합니까, 아니면 PUT여야 합니까? REST가 알려줍니다. 원칙은 제약이 아니라, 유지를 가능하게 하고 확장 가능한 API로 가는 길을 유지시켜주는 안전 장치입니다.
제 경력 동안 200개 이상의 API 디자인을 검토해왔으며, 잘 유지된 것들은 모두 한 가지 특징을 공유했습니다: REST의 리소스 지향적 사고를 존중했습니다. 유지보수의 악몽이 된 것들은? REST를 프레임워크가 아닌 제안으로 취급했습니다. 당신의 API는 당신이 예상하는 것보다 더 오랫동안 살아남을 것입니다—아마도 생산 환경에서 최소 5-7년입니다. 그 긴 수명을 염두에 두고 설계하십시오.
원칙 1: 리소스는 명사, 동사가 아니다
이 원칙은 현실 세계의 위반을 보지 않을 때는 명백해 보입니다. 저는 한 번 /getUser, /createOrder, /deleteProduct와 같은 엔드포인트가 있는 API를 물려받았습니다. 모든 작업이 URL에서 동사여서 HTTP 메서드는 중복되었습니다. 이 API에는 23개의 리소스 기반 엔드포인트가 더 잘 수행할 수 있는 127개의 엔드포인트가 있었습니다.
규칙은 다음과 같습니다: 당신의 URL은 사물(리소스)을 나타내야 하고, HTTP 메서드는 그 사물에 대한 작업을 나타내야 합니다. POST /createUser 대신 POST /users를 사용하십시오. GET /getUserOrders 대신 GET /users/123/orders를 사용하십시오. 이는 그저 학문적이지 않으며, 확장 가능한 일관된 정신 모델을 만들어내는 것입니다.
인지적 부담을 고려하십시오. 동사 기반 URL을 사용하면 개발자는 임의의 엔드포인트 이름을 기억해야 합니다. 리소스 기반 URL을 사용하면 패턴을 따릅니다. 우리 핀테크 앱에서는 적절한 리소스 명명으로 인하여 새로운 개발자들의 온보딩 시간을 3주에서 1.5주로 줄일 수 있었습니다. API는 자가 문서화가 되었습니다.
물론 예외가 있습니다. CRUD 작업에 맞지 않는 작업—예를 들어 POST /payments/123/refund 또는 POST /orders/456/cancel—은 허용됩니다. 이는 컨트롤러 스타일의 엔드포인트이며 대안이 어색할 때는 괜찮습니다. 핵심은 이를 드물고 일관되게 사용하는 것입니다. 현재 API에서는 89%의 엔드포인트가 순수 리소스 작업이며, 나머지 11%는 명확하게 문서화된 컨트롤러 작업입니다.
리소스를 명명할 때는 복수 형태의 명사를 일관되게 사용하십시오. /users가 아니라 /user, /orders가 아니라 /order입니다. 예, GET /users/123는 단일 사용자를 반환하며 이는 문법적으로 이상하게 느껴질 수 있지만, 일관성이 문법보다 우선합니다. 저는 팀들이 단수 대 복수에 대해 수시간을 낭비하는 모습을 보았습니다. 복수를 선택하고 진행하십시오.
원칙 2: HTTP 메서드는 그 의미를 의미한다
HTTP는 우리에게 풍부한 어휘를 제공합니다: GET, POST, PUT, PATCH, DELETE 등. 각각은 특정한 의미를 가지며 이 의미를 존중하는 것은 API를 예측 가능하고 캐시할 수 있게 만듭니다. 그럼에도 불구하고 저는 POST가 모든 작업을 수행하는 API를 정기적으로 봅니다—생성, 업데이트, 삭제, 심지어 데이터 검색까지. 이것은 배워야 할 다른 도구를 배우고 싶지 않아서 모든 목수 작업에 망치를 사용하는 것과 같습니다.
| 접근 방식 | 응답 크기 | 네트워크 효율성 | 클라이언트 복잡성 |
|---|---|---|---|
| 모든 것 반환 | 요청당 47MB 이상 | 나쁨 - 막대한 오버헤드 | 낮음 - 그러나 낭비됨 |
| 페이징 전용 | 변동, 제어되지 않음 | 보통 - 여전히 과잉 가져오기 | 낮음 - 단순한 구현 |
| 필드 필터링 | 클라이언트 제어 | 좋음 - 필요한 것만 가져오기 | 보통 - 쿼리 매개변수 필요 |
| GraphQL 대안 | 정확히 제어됨 | 탁월함 - 오버-페칭 없음 | 높음 - 학습 곡선 |
| 스마트 기본값 + 확장 | 최적화된 기준선 | 탁월함 - 균형 잡힌 접근 | 낮음 - 대부분의 경우 직관적 |
GET 요청은 안전하고 멱등해야 합니다. 안전하다는 것은 서버 상태를 수정하지 않는다는 의미입니다. 멱등은 여러 번 호출해도 동일한 결과를 낸다는 의미입니다. 이는 이론적인 것이 아니라 캐싱을 가능하게 하여 읽기 중심의 API의 서버 부하를 60-80% 줄일 수 있습니다. GET 의미론을 제대로 구현하고 HTTP 캐싱을 적용하여 사용자 프로필 API를 최적화했을 때, 우리의 서버 비용이 매달 4,200달러 줄어들었습니다.
POST는 새로운 리소스를 생성합니다. 이는 안전하지도 않고 멱등하지도 않습니다—한 번 호출하면 두 개의 리소스가 생성됩니다. PUT은 전체 리소스를 교체하며 멱등합니다—열 번 호출해도 한 번 호출하는 것과 동일한 효과가 있습니다. PATCH는 리소스를 부분적으로 업데이트하며 멱등해야 합니다. DELETE는 리소스를 제거하며 멱등합니다. 이러한 구분은 클라이언트 재시도 로직, 캐싱 전략 및 API 게이트웨이 구성에 중요합니다.
다음은 우리 결제 처리 API에서의 실제 사례입니다. 우리는 처음에 모든 작업에 POST를 사용했습니다, 결제 상태 확인도 포함해서 말입니다. 네트워크 문제로 인해 클라이언트가 요청을 재시도 할 때, 우리는 중복 결제 기록을 생성했습니다. 상태 확인에 GET을 사용하고 POST 요청에 대해 적절한 멱등 키를 구현한 후, 중복 결제는 거래의 2.3%에서 0.01%로 줄어들었습니다. 이는 실질적으로 절약된 돈과 고객 신뢰의 보존입니다.
한 가지 일반적인 질문: PUT과 PATCH 중 언제 사용해야 합니까? 클라이언트가 전체 리소스 표현을 보낼 때는 PUT을 사용하십시오. 클라이언트가 변경할 필드만 보낼 때는 PATCH를 사용하십시오. 실제로 PATCH가 더 적절한 경우가 많습니다. 왜냐하면 클라이언트는 모든 필드를 보내고 싶어 하지 않기 때문입니다. 우리의 분석 결과에 따르면, 업데이트 작업의 94%가 PATCH를 사용하고 있으며 이는 평균 73%의 페이로드 크기를 줄여 모바일 앱의 효율성을 증가시켰습니다.
원칙 3: 상태 코드는 당신의 커뮤니케이션 프로토콜이다
HTTP 상태 코드는 커뮤니케이션을 위한 표준화된 언어입니다.