REST 아키텍처 스타일
ORM Entity와 DB Table을 별 고민 없이 단지 일대일 대응하는 설계는 좋지 않다. DB를 데이터의 적재 수단으로써 생각하고, 비즈니스를 잘 분석하여 설계한 도메인과 적재 형태를 매핑해주는 것이 좋은 설계다. 마찬가지로 API 또한 도메인 모델을 그대로 사용하는 것이 아니라 비즈니스에 맞게 잘 설계해야 한다.
REST API는 개념이 단순하여 직관적으로 이해하기 쉽다. 또 몇 가지 가이드에 따라 설계하면 쉽게 REST를 흉내낼 수 있다. 하지만 이런 특징 때문에 오히려 올바른 설계와 멀어지고, REST API의 진짜 목적과 장점을 잊기 쉬운 것 같다. 앞 문단에서 이야기했던 도메인 설계와 API 설계는 분리되어야 한다는 것과 같은 맥락이다. 또 REST는 단지 API의 설계 뿐만 아니라 더 포괄적인 목적을 갖고 있다. 본 포스팅은 Roy.T.Fielding의 논문 “Architectural Styles and the Design of Network-based Software Architectures“을 바탕으로 REST의 개념을 정리하고, 그 목적과 효용성을 상기한다.
REST의 개념란?
일반적으로 REST는 분산 하이퍼미디어 시스템을 위한 네트워크 아키텍처 스타일이라고 소개된다. Roy.T.Fielding의 논문에 따르면 아키텍처 스타일은 어떤 아키텍처 구성 요소들의 역할 및 기능, 그리고 해당 스타일을 준수하는 아키텍처의 구성 요소 간의 허용된 관계를 제한하는 조정된 아키텍처 제약 조건들의 집합이라고 말한다.
어려운 말이어서 이해하기 힘들지만, 풀어 설명하면 어떤 아키텍처가 지켜야 할 제약 조건들의 집합을 의미한다. 즉, REST는 네트워크 기반 어플리케이션의 주요 관심사(성능, 인터페이스 등)를 효율적으로 해결하기 위한 제약 조건들의 집합이다.
네트워크 기반 어플리케이션의 관심사
REST 논문에서 다루는 아키텍처 스타일 적용 범위는 네트워크 기반 어플리케이션으로 한정된다. 앞서 네트워크 기반 어플리케이션의 주요 관심사에 대해 언급했는데 이들을 더 자세히 알아보자.
- 성능(Performance)
- 네트워크 성능(Network Performance)
- 사용자 인식 성능(User-perceived performance)
- 네트워크 효율성(Network Efficience)
- 확장성(Scalability)
- 단순성(Simplicity)
- 수정성(Modifiability)
- 진화성(Evolvalibity)
- 맞춤성(Customizablity)
- 설정성(Configurability)
- 재사용성(Reusability)
- 가시성(Visibility)
- 이식성(Portability)
- 신뢰성(Reliablity)
여기까지의 내용만을 정리해보더라도 실제로 REST에서 해결하고자 하는 목표는 단지 리소스의 표현 뿐만 아니라 훨씬 더 포괄적이라는 것을 추측할 수 있다. 나중에 시간이 된다면 이 관심사들에 대해 더 자세히 설명하는 포스팅을 작성 예정이다. 그럼 REST 아키텍처 스타일이 실제로 목표하는 바와 구체적인 내용이 무엇인지 살펴보자.
REST의 문제 해결 목표
웹의 폭발적인 성장은 1990년대부터 이어져왔다. 첫 시작은 작은 연구소였지만 이후에는 개인 홈페이지나 캠퍼스 기관에서도 활용하며 기하급수적으로 성장했다. 초기 HTTP는 단일 요청-응답을 위해 설계되어 웹의 급속한 성장을 감당하지 못할 것이라는 우려가 많았다. 특히 당시 웹 사이트에서는 초기 형태와 다르게 웹 페이지의 콘텐츠 일부로 인라인 이미지를 점점 더 사용하며 웹 어플리케이션과의 상호 작용이 더욱 많아졌다. 기존의 개발된 웹 사이트들의 아키텍처는 확장성이 부족하거나 공유 캐싱 및 중간 계층을 추가하기 힘들었고, 이런 구조적 문제로 앞선 문제를 해결하기에도 어려움이 있었다.
이런 문제를 해결하기 위해 REST 아키텍처 스타일이 제안되었다. REST가 전체적으로 적용되는 경우, 아래 이점들을 얻을 수 있다.
- 상호 작용하는 구성 요소의 확장성
- 범용적 인터페이스
- 구성 요소의 독립적 배포
- 중간 계층 구성 요소(통신 시간 단축, 보안 강화, 레거시 시스템의 캡슐화 등의 목적)
REST(REpresentational State Transfer)
드디어 핵심 내용이다. REST는 앞서 인식했던 문제점을 해결하기 위해 제시된 아키텍처 스타일이다. 어떤 제약 조건들이 포함되어 있는지 살펴 보자.
Client-Server
사용자 인터페이스 문제와 데이터 스토리지 문제의 관심사를 분리함으로써 멀티 플랫폼 환경에서의 사용자 인터페이스 이식성과 서버 구성 요소의 확장성을 높인다는 제약 조건이다.
Stateless
클라이언트-서버 통신의 요청이 무상태성을 유지해야 한다는 제약 조건이다. 즉, 서버로의 요청에는 이 요청을 이해하기 위한 모든 정보가 포함되어야 하고, 세션 상태가 서버가 아닌 클라이언트에 저장되어야 한다는 것이다. Stateless 제약 조건은 다음과 같은 이점을 얻을 수 있다.
- 임의의 요청을 독립적인 문맥에서 해석할 수 있어 가시성이 향상된다.
- 부분적인 장애의 복구가 용이하여 안정성이 향상된다.
- 통신 사이의 상태를 저장할 필요가 없으므로 확장성이 개선된다.
Cache
통신 응답에 포함된 데이터에 명시적이든 암시적이든 Cache 가능 여부가 포함되어, 응답을 Cache할 수 있어야 한다. 이를 통해 클라이언트-서버 간의 통신을 줄여 효율성, 확장성, user-perceived 성능을 높일 수 있다.
Uniform Interface
구성 요소 간 인터페이스는 통일(범용적)되어야 한다는 제약 조건이다. REST의 핵심적인 부분이고, 가장 논의가 많이 이루어지는 내용이다. 시스템 구성 요소의 인터페이스에 이를 적용함으로써 전체 시스템 아키텍처가 단순해지고, 상호작용의 가시성이 높아지며, 구현과 서비스가 분리되므로 독립적인 진화가 가능해진다.
Uniform Interface은 아래의 네 가지 제약 조건으로 구성된다.
- identification of resources
- manipulation of resources through representation
- self-descriptive messages
- hypermedia as the engine of application state
Layered System
지속적으로 생겨나는 요구 사항에 대응하기 위해 계층화된 시스템으로 구성할 수 있어야 한다는 제약 조건이다. 각 계층의 구성 요소는 인접하지 않은 계층의 구성 요소를 볼 수 없도록 구성 요소의 동작을 제한함으로써 전체 시스템의 복잡성을 낮추고, 계층의 독립성을 높인다.
이를 통해, 중간 계층 구성 요소를 추가하여 Legacy 서비스를 캡슐화하거나 보안을 강화할 수 있고, 로드 밸런싱을 통해 시스템 확장성을 높일 수 있다.
이상적인 REST API에 관하여
REST에 관해 깊게 고민하거나 공부한 사람들이라면 논문에서 말하는 아키텍처 스타일을 완벽하게 적용하는 것은 어렵다고 생각해봤을 것이다. 요즘은 모두가 REST API를 외치지만, HTTP 메서드로 행위를 표현하고, URI로 자원을 표현하는 것만으로는 REST API라고 할 수 없다. Roy Fielding은 본인의 블로그에 REST라고 부를 거면 REST 제약 조건을 지키거나 다른 용어를 사용하라는 글을 올리기도 했다. 사실 REST는 Hypertext에 국한되는 제약 조건이다. 따라서 엄밀히 말하면 현재 전세계적으로 가장 많이 사용되는 JSON API 형태의 API는 REST라고 부를 수 없는 것이다. 그럼 왜 이들은 REST API로 불리게 되었을까?
아마도 REST 제약 조건을 모두 수용하지 않고 일부만 채택해서 사용하더라도 여러 이점을 누릴 수 있었기 때문이 아닐까 싶다. 흔히 REST 제약 조건에서 잘 지켜지지 않는 부분은 Uniform Interface의 self-descriptive messages, hypermedia as the engine of application state이다. 현대의 웹 기반 API는 Client-Server 구조 기반의 Layered System이고, Stateless하며, Cachable하다. 앞서 말한 두 가지 제약 조건 외에는 잘 지켜진다. 문제는 이 두 제약 조건을 지키는 것이 현실적으로 어렵다는 것이다. 엄격하게 이들을 지키는 것보다 웹 개발자와 서버 개발자가 물리적으로 약속하고 약간의 결합도를 갖는게 더 효율적이기 때문이다.
그럼 우리는 이들을 REST API라고 명명해도 괜찮을까? 솔직히 잘 모르겠다. REST API가 아닌 HTTP API, RPC를 이미 관습적으로 그렇게 부르고, 커뮤니케이션하고 있기 때문이다. 그럼에도 만든 사람이 아니라고 주장하니까 용어의 혼동을 없애기 위해 정확하게 불러야 하는 것 같기도 하다.
하지만 확실한 한 가지는 최근엔 REST API의 한계가 드러나고 있다는 것이다. URI에 행위 없이 리소스를 나타내야만 한다는 제약이 API의 표현 자체를 제한하기에 수 많은 사람들이 REST의 규약으로부터 벗어나고 있다. 웹 기반 시스템을 디자인 하며 REST스럽게 개발하며 여러 이점을 얻기도 하고, 모든 제약 조건을 지지 않아도 현실의 맥락에 따라 효율적인 방법을 채택하여 활용하기도 한다. 현 시점에서는 어떤 것은 REST이고 어떤 것은 REST가 아니라는 명확한 구분이 중요한 것이 아니다. 의미 없는 논쟁에서 벗어나서 REST에서 해결하고자 했던 문제점과 해결 방식을 인식하는 것으로도 좋은 방향성을 유지할 수 있다고 생각한다.