REST는 HTTP의 창시자 로이 필딩(Roy Fielding)의 2000년 논문에 의해서 소개된 웹의 장점을 최대한 활용할 수 있는 네트워크 기반의 아키텍쳐 이다. 자원을 이름(자원의 표현)으로 구분하여 해당 자원의 상태(정보)를 주고 받는 모든 것을 의미한다.
이러한 REST 아키텍쳐의 디자인 원칙을 준수하는 것이 REST API이다.
REST API에는 다른 디자인 패턴과 비교하였을 때, 확연한 단점이 한가지 존재하는데, 바로 표준이 명확하지 않다는 것이다. SOAP(Simple Object Access Protocol), XML-RPC등 엄격한 프로토콜 표준에 비하면, REST는 엄격한 표준이 존재하지 않는다. 반대로 REST의 장점 또한 유연성이다. 아직까지도 REST는 표준이 존재하지 않는다. 단지, 암암리에 생겨난 표준 비스무리 한 것이 있을 뿐이다.
(그러한 표준을 Defactor 표준이라고 부른다.)
REST 아키텍쳐와 대응되는 REST API의 요소는 다음과 같다.
1. 자원의 이름 = URI
모든 자원에 고유한 ID(URI)가 존재하고, 이 자원은 서버에 존재하며, URI로 자원을 구별한다. 클라이언트는 URI를 이용해서 자원을 지정하고 해당 자원의 상태(정보)에 대한 조작을 서버에 요청한다.
ps) URI의 정의는 다음을 참고하자.
2. 행위 = HTTP Method
HTTP 프로토콜의 Method를 행위로서 사용한다. HTTP 프로토콜은 GET, POST, PUT, DELETE 와 같은 메서드를 제공한다.
3. 표현 = JSON, XML, TEXT, RSS...
클라이언트가 자원의 상태(정보)에 대한 조작을 요청하면, 서버는 이에 적절한 응답을 보낸다. REST의 가장 큰 장점중 하나로 표현이 자유롭다. JSON, XML, TEXT, RSS등 여러 형태로 표현이 가능하다. 보통은 JSON 또는 XML을 통해 주고 받는다.
우리는 대개 서버에 요청하면 데이터로 응답해주는 API들을 REST API라고 부르지만, 완벽한 REST API 디자인 원칙을 지키는 것이 진정한 REST API라고 볼 수 있다. 이를 RESTful API라고 한다.
다음은 RESTful API를 실현하기 위한 디자인 원칙 들이다.
1. 균일한 인터페이스
요청이 어디에서 오는지와 무관하게, 동일한 리소스에 대한 모든 API 요청은 동일하게 보여야 한다. REST API는 사용자의 이름이나 이메일 주소 등의 동일한 데이터 조각이 오직 하나의 URI에 속함을 보장해야 한다. 리소스가 너무 클 필요는 없지만, 이는 클라이언트가 필요로 하는 모든 정보를 포함해야 한다.
2. 클라이언트-서버 디커플링(Client-Server Decoupling, 결합도 감소)
REST API 디자인에서 클라이언트와 서버 애플리케이션은 서로 간에 완전히 독립적이어야 한다. 클라이언트 애플리케이션이 알아야 하는 유일한 정보는 요청된 리소스의 URI이며, 이는 다른 방법으로 서버 애플리케이션과 상호작용할 수 없다.
이와 유사하게, 서버 애플리케이션은 HTTP를 통해 요청된 데이터에 전달하는 것 말고는 클라이언트 애플리케이션을 수정하지 않아야 한다.
3. 무상태성(Stateless)
REST API는 무상태성을 지녀야 한다. 이는 각 요청에서 이의 처리에 필요한 모든 정보를 포함해야 함을 의미한다. (자기 설명성) 즉, REST API는 서버 측 세션을 필요로 하지 않는다. 또한 서버 애플리케이션은 클라이언트 요청과 관련된 데이터를 저장 할 수 없다. 즉, 서버가 클라이언트의 상태를 보존하지 않는다.
반대로 상태유지(Stateful)는 서버가 클라이언트의 상태를 보존하는 것으로, 만일 서버에서 장애가 발생한다면, 유지된 상태가 없어져 버리므로 처음부터 다시 요청을 해야한다.
예를 들면, 로그인이 필요한 서비스를 제작한다고 하자. 상태를 유지하며 설계하게 되면, 서버 장애 발생시 처음부터 로그인과 인증을 진행해야한다. 하지만 무상태성으로 설계하게 된다면, 서버는 클라이언트가 보내주는 쿠키, 서버, 세션, 토큰등을 이용해 클라이언트의 요청만을 받아들여, 그에 응하는 응답만 해주면 된다.
4. 캐싱 가능성
REST API는 가능하면 리소스를 클라이언트 또는 서버측에서 캐싱할 수 있어야 한다. 또한 서버 응답에는 전달된 리소스에 대해 캐싱이 허용되는지 여부에 대한 정보도 포함되어야 한다. 이의 목적은 서버측의 확장성 증가와 함께 클라이언트의 성능 향상을 위한 것이다.
5. 계층 구조 아키텍처
REST API에서는 호출과 응답이 서로 다른 계층을 통과한다. (대부분 API 호출 경험에 따르면 클라이언트와 서버 애플리케이션이 서로 간에 직접 연결된다고 가정하지 않는 것이 좋다. 통신 루프에는 다수의 서로 다른 중개자가 있을 수 있다. REST API는 클라이언트가 중개자를 통해 통신하는지, 엔드 애플리케이션을 통해 통신하는지 서버가 알 수 없도록 설계되어야 한다.
계층 구조 아키텍처의 대표적인 예로는 마이크로서비스 아키텍처를 들 수 있다.
6. 코드 On-Demand(옵션)
REST API는 일반적으로 정적 리소스를 전송하지만, 특정한 경우에는 응답에 실행코드를 포함할 수 도 있다. 이 경우에 코드는 요청 시에만 실행이 되어야 한다.
다음은 레너드 리차드슨이 고안한 리차드슨 성숙도 모델(Richardson Maturity Model) 이다.
이는 RESTful의 실현단계를 리소스, 메서드, 하이퍼미디어 등의 용어를 사용해 알기 쉽게 설명한 모델이다. 이는 먼저 HTTP를 전송 계층의 관점에서 바라보는 것으로 시작한다.
일반 XML 데이터를 SOAP나 XML-RPC등으로 전송한다. POST 메서드만 사용하며, 서비스간에 단일 POST 메서드로 XML 데이터를 교환한다. 초창기 SOA 애플리케이션 제작 시 흔히 사용된 방식이다.
함수에 파라미터를 넘기는 대신 REST URI를 이용한다. 레벨 0처럼 POST 메서드 하나밖에 사용하지 않지만, POST 메서드로 서비스 간 통신을 하면서 복잡한 기능을 여러 리소스로 분산시킨다는 점에서 한 단계 발전한 형태로 볼 수 있다.
레벨2는 POST 이외에 GET, HEAD, DELETE, PUT 등의 메서드를 추가적으로 사용한다. HTTP 요청시 여러 메소드를 사용하여 다양한 리소를 제공할 수 있다는 점에서 REST의 진정한 Use Case라고 할 수 있다. 실제로, Level2까지만 구현된 REST API들이 현제 RESTful API 보다 많다.
HATEOAS는 요청에 대한 하이퍼 미디어 응답 속에 클라이언트가 다음에 취해야 할 액션에 관한 상태 정보를 담는다. 말 그대로 하이퍼텍스트를 애플리케이션 상태를 표현하기 위한 방법으로 사용하는 것이다.
HATEOAS를 이용하면, 무상태성의 조건중 하나인 자기설명성(Self-Descriptive)을 실현할 수 있다.
다음 글에서 HATEOAS에 대한 설명과, 이러한 개념을 편리하게 적용할 수 있도록 도와주는 Spring HATEOAS와 이를 이용하여 완성된 Spring Data REST를 소개하도록 하겠다.