REST 또는 RESTful API에 대해서는 이미 많은 정보나 아티클이 존재하지만, REST를 직접 정립한 Roy Fielding의 논문을 통해 REST를 공부하고자 한다.
REST (= REpresentational State Transfer) 는 '분산형 하이퍼미디어 시스템 (Distributed Hypermedia System)'을 위한 아키텍처 스타일이다.
- Distributed Hypermedia System
: 분산된 환경에서 작동하는 Hypermedia system을 의미하며,
Hypermedia는 text, image, video etc. 다양한 미디어 요소들이 하이퍼링크로 연결된 정보.
↪ Distributed Hypermedia System의 대표격으로 WWW (World Wide Web) 이 있다.ref. Roy Fielding 作 - Designing the Web Architecture: Problems and Insights
여러 네트워크 기반 아키텍처 스타일에서 파생된 하이브리드 스타일이며 균일한 커넥터 인터페이스 (uniform connector interface)를 정의하는 추가 제약 조건과 결합된다.
Web architecture의 설계 원리는 아키텍처 내 요소에 적용된 제약조건 세트로 구성된 아키텍처 스타일로 설명할 수 있다.
진화하는 스타일에 추가되는 각 제약조건의 영향을 검토하여, 웹의 제약조건에 의해 유발되는 properties를 식별할 수 있다.
제약조건을 추가적으로 적용하여 모던 Web architecture가 원하는 properties를 더 잘 반영하는 새로운 아키텍처 스타일을 구성할 수 있다.
: 건물이든 소프트웨어든 건축 설계 프로세스에는 공통적으로 2가지 관점이 존재하는데,
First: 설계자는 아무것도 없는 상태 (a blank slate, whiteboard와 같은)에서 시작해 의도된 시스템의 요구를 충족할 때까지 익숙한 components로부터 architecture를 구축한다.
- 창의성과 무한한 vision을 강조
Second: 설계자가 제약조건 없이 전체 시스템에서 시작하여 점진적으로 시스템의 요소들에 제약조건을 식별하고 적용하여 설계 공간을 차별화하고 시스템 동작에 영향을 미치는 force가 시스템과 조화를 이루어 natural하게 흘러가야 한다. (flow naturally)
- system context에 대한 제한과 이해를 강조
이러한 2가지 관점에서 REST는 후자에 중점을 두어 개발되었다.
아래는 적용된 제약조건들이 증가함에 따라 아키텍처의 프로세스 뷰를 어떻게 차별화하는지 나타낸 그림들이다.
Null Style은 빈 제약조건 세트로써, 아키텍처 관점에서 components 간에 구별되는 경계가 없는 시스템으로 REST 설명의 시작점 (starting point)이 된다.
: 관심사 분리는 client-server 제약조건의 배경이 되는 원칙으로, user interface 문제와 data storage 문제를 분리함으로써, 멀티 플랫폼 환경에서 사용자 인터페이스 이식성을 개선하고 server components를 단순화하여 확장성을 개선한다.
웹에서 가장 중요한 것은 분리를 통해 components가 독립적으로 발전하여 여러 조직 도메인의 인터넷 규모 요구사항을 지원할 수 있다는 것이다.
: client-server 상호작용 제약조건을 추가한다. 상호작용은 기본적으로 CSS (client-stateless-server)와 같이 stateless (무상태성)이어야 한다.
클라이언트에서 서버로 요청을 보낼 때, client는 server가 요청을 이해하는 데 필요한 모든 정보를 포함해야 하며 server에 저장된 context를 이용할 수 없다. 그러므로 Session의 state는 전적으로 client에 보관된다.
- Server는 No Sessions, No Cookies
이러한 제약조건은 visibility (가시성)
, reliability (신뢰성)
, scalability (확장성)
속성을 유도한다.
대부분의 아키텍처 선택과 마찬가지로, stateless 제약은 design trade-off를 반영한다.
단점은 공유 컨텍스트에서 데이터를 server에 남길 수 없기 때문에 일련의 요청으로 전송되는 반복되는 데이터 (상호 작용별 오버헤드, per-interaction overhead)를 증가시켜 network의 퍼포먼스를 저하시킬 수 있다는 점이다.
추가로, application의 상태를 client-side 측에 두는것은 여러 client versions에 걸쳐 semantics를 정확하게 구현하는 것에 의존하게 되어 application 동작에 대한 server의 제어가 줄어든다.
: 네트워크 효율성을 개선시키기 위해 cache라는 제약조건을 추가하여 client-cache-stateless-server 스타일로 구성해야한다.
cache 제약조건은 request에 대한 response 내의 데이터가 암묵적 또는 명시적으로 cacheable or non-cacheable로 지정해야함을 요구한다.
response가 cacheable인 경우, client cache는 이후의 동일한 요청에 대해 해당 응답 데이터를 재사용할 수 있는 권한을 부여받는다.
cache 제약조건을 추가하면,
장점: 일부 interaction을 부분적 또는 완전히 제거하여 일련의 interaction의 평균 지연 시간을 줄여 효율성, 확장성 및 사용자가 인식하는 성능을 향상시킬 수 있는 잠재력이 있다.
단점: cache 내에 존재라는 오래된 데이터가 요청을 server로 직접 전송했을 때 얻은 데이터와 크게 다를 경우, cache가 안정성 (신뢰성)을 저하시킬 수 있다.
: REST 아키텍처 스타일이 다른 네트워크 기반 스타일과 구별되는 핵심 특징은 components 간의 균일한 인터페이스를 강조한다는 점이다.
component interface에 소프트웨어 엔지니어링 원칙의 일반성을 적용함으로써, 전체 시스템 아키텍처가 단순화되고 interface의 가시성이 향상된다.
Implementations (구현)은 서비스를 제공으로부터 분리되어 독립적으로 발전할 수 있도록 격리된다.
그러나 uniform interface는 정보가 애플리케이션 요구사항에 특정형식이 아닌 표준화된 형식으로 정보를 전송하기 때문에 효율성이 저하된다.
REST 인터페이스는 대용량 하이퍼미디어 데이터 전송이 효율적으로 되게 하기위해 설계되었으므로 일반적인 Web의 경우에는 최적화가 잘 되어 있지만 다른 형태의 아키텍처 인터랙션에는 최적이 아닌 인터페이스가 된다.
uniform interface를 얻기 위해서는 components의 동작을 안내하기 위한 여러 아키텍처 제약조건이 필요하다.
REST는 아래의 4가지 인터페이스 제약조건으로 정의된다.
리소스 식별 (identification of resources)
표현을 통한 리소스 조작 (manipulation of resources through representations)
자체 설명 메시지 (self-descriptive messages)
애플리케이션 상태 엔진으로서의 하이퍼미디어 (hypermedia as the engine of application state)
: Internet-scale 요구사항을 위해 더욱 향상된 동작을 위해, 계층 시스템 (layered system) 제약조건을 추가한다.
Layered system style을 적용하면 각 component가 인터랙팅하는 immediate layer를 "see" 할 수 없도록 component의 동작을 제한하여 아키텍처를 hierarchical layers (계층적 계층)로 구성할 수 있다.
system에 대한 지식을 single layer로 제한함으로써, 전반적인 시스템 복잡성을 제한하고 substrate 독립성을 촉진한다.
Layer는 레거시 서비스를 캡슐화하고 레거시 클라이언트로부터 새로운 서비스를 보호하여, 자주 사용하지 않는 기능을 공유된 중간매체 (shared intermediary)로 보내 components를 단순화할 수 있다.
중간매체는 여러 네트워크와 프로세스에 걸쳐 서비스의 load balancing (분산 처리)을 가능하게 하여 system 확장성을 개선하는데 사용될 수도 있다.
중간매체인 intermediary에는 proxy, gateway 같은 네트워크 기반의 중개 역할을 하는 장치나 소프트웨어를 말한다.
- Proxy: client가 다른 네트워크 서비스에 간접적으로 접속할 수 있게 해주는 컴퓨터 시스템이나 응용프로그램
- Gateway: 컴퓨터 네트워크에서 서로 다른 통신망, 프로토콜을 사용하는 네트워크 간의 통신을 가능하게 하는 컴퓨터나 소프트웨어
layered system의 주요 단점은 데이터 처리에 overhead (오버헤드)와 대기시간을 추가하여 사용자가 인지하는 성능을 저하시킨다.
cache 제약조건을 지원하는 네트워크 기반의 시스템의 경우, 중간매체에 공유 캐싱을 통한 이점으로 이 문제를 상쇄할 수 있다.
조직 도메인 영역에서 공유 캐시를 배치하면 상당한 퍼포먼스 이점을 얻을 수 있다.
이러한 계층을 사용하면 방화벽에서 요구하는 조직 경계를 넘는 데이터에 보안정책을 적용할 수도 있다.
layered system과 uniform interface의 조합은 uniform pipe-and-filter 스타일과 유사한 아키텍처 특성을 유발한다.
REST 인터랙션은 two-way (양방향)이지만 하이퍼미디어 인터랙션의 대용량 데이터 흐름은 각각 data-flow 네트워크처럼 될 수 있으며, 데이터 스트림을 통과하는 동안 filter component가 선택적으로 적용되어 전달되는 content를 변환한다.
REST 내에서 intermediary components는 메시지가 자체 설명적 (self-descriptive)이고 intermediaries에게 semantics하게 표시되기 때문에 적극적으로 변환할수 있다.
: REST는 applets 또는 scripts 형태로 코드를 다운로드하고 실행하여 client 기능을 확장할 수 있도록한다. 이를 통해 사전 구현에 필요한 기능들의 수를 줄여 client를 단순화한다.
배포 후 기능을 다운로드 할 수 있도록 하면 시스템 확장성이 향상된다. 그러나 가시성이 감소하므로, REST에서 이 제약은 optional 즉, 선택사항이다.
optional 제약조건의 개념은 모순적으로 보일 수 있다. 그러나 이는 여러 조직적 경계 (organizational boundaries)를 포함하는 시스템의 아키텍처 디자인에 목적이 있다. 즉, 아키텍처는 전체 시스템의 일부 영역에서 적용되는 것으로 알려진 경우에만 optional 제약조건의 이점 (및 단점)을 얻는다.
예시로, 조직 내 모든 client software가 Java applet을 지원하는 경우, 조직 내 service는 다운로드 가능한 Java 클래스를 통해 향상된 기능의 이점을 얻도록 구성할 수 있다.
그러나 동시에, 조직의 방화벽이 외부 소스로부터 Java applet을 전송하는 것을 차단할 수 있으므로 나머지 Web에서는 해당 client가 code-on-demand를 지원하지 않는 것처럼 보일 수 있다.
optional 제약조건을 사용하면 일반적으로 원하는 기능을 지원하는 아키텍처를 디자인 할 수 있지만 일부 context에서는 비활성화될 수 있다.
: REST는 후보 아키텍처에 유도하는 속성에 대해 선택된 일련의 아키텍처 제약조건으로 구성된다. 이러한 각 제약조건을 개별적으로 고려할 수 있지만, 일반적인 아키텍처로부터 파생된 측면에서 설명하면 이러한 제약조건을 선택한 이유를 더 쉽게 이해할 수 있다.
네트워크 기반 아키텍처 스타일 측면에서 REST의 제약조건 파생을 그래픽화
REST는 분산 하이퍼미디어 시스템 내 아키텍처 요소를 추상화한 것이다.
REST는 component 구현과 protocol syntax의 세부사항을 무시하고 component의 역할, 다른 component와의 인터랙션에 대한 제약, 중요한 데이터 요소에 대한 해석에 집중한다.
이는 웹 아키텍처의 기반을 정의하는 component, connector, 그리고 data에 대한 기본 제약과 네트워크 기반 애플리케이션으로서의 동작의 본질을 포괄한다.
: 모든 데이터가 processing components 내에 캡슐화되고 숨겨진 분산 객체 스타일과는 달리, 아키텍처의 데이터와 상태는 REST의 핵심 요소이다.
분산형 하이퍼미디어 아키텍트는 3가지의 기본 옵션과 각각의 장단점을 가지고 있다.
options 1: 데이터가 있는 위치에서 렌더링하고 고정 형식의 이미지를 수신자에게 전송한다.
: option 1은 전통적인 client-server 스타일로, 데이터의 실제 특성에 대한 모든 정보를 sender 내부에 숨겨두어 데이터 구조에 대한 가정을 방지하고 client 구현을 더 쉽게 만든다.
그러나 recipient의 기능을 심각하게 제한하고 대부분의 processing load를 sender에게 주어 확장성의 문제를 일으킨다.
options 2: 렌더링 데이터를 캡슐화하고 둘 다 수신자에게 전달한다.
: option 2는 모바일 오브젝트 스타일로, 고유 렌더링 엔진을 통해 데이터를 전문적으로 처리할 수 있도록 하면서 정보 은닉을 제공하지만, recipient의 기능을 해당 엔진 내에서 예상되는 것으로 제한하고 전송되는 데이터의 양을 크게 증가시킬 수 있다.
options 3: 데이터 유형을 설명하는 메타데이터와 원시 데이터를 수신자에게 전달하여 수신자가 원하는 렌더링 엔진을 선택할 수 있게 한다.
: option 3을 적용하면 전송된 바이트를 최소화하고 sender를 단순화하여, 확장 가능하도록하지만 정보 은닉의 이점을 잃고 sender와 recipient가 모두 동일한 데이터 유형을 이해해야 한다.
REST는 metadata를 이용하여 데이터 타입의 공유된 이해에 중점을 두어 3가지 옵션의 하이브리드를 제공한다. 그러나 표준화된 interface를 통해 공개 범위를 제한한다.
REST components는 resource의 표현을 전송하여 통신하는데 이는 recipient의 기능이나 요구에 따라 동적으로 선택된 진화하는 표준 데이터 유형 중 하나와 일치하는 형식으로 이루어진다.
표현이 raw source와 동일한 형식인지, 원본에서 유도된 것인지는 interface 뒤에 숨겨져 있다. mobile object 스타일의 장점은 캡슐화된 렌더링 엔진의 표준 데이터 형식의 명령어로 구성된 표현을 전송함으로써 근사화된다.
따라서 REST는 서버 확장성 문제 없이 client-server 스타일의 관심사 분리를 얻고, 일반 인터페이스를 통해 정보은닉을 허용하여 캡슐화와 서비스의 진화를 가능하게 하고, 다운로드 가능한 기능 엔진을 통해 다양한 기능 세트를 제공한다.
: REST에서 resource 라는 개념을 중심으로 정보를 추상화하며, 이는 시간에 따라 값이 변할 수 있는 개념적 매핑으로, 각 resource는 고유한 식별자를 가지고 있다.
즉, hypertext 참조 대상이 될 수 있는 모든 개념은 리소스의 정의 내에 들어갈 수 있어야한다.
이를 통해 component간 인터랙션에서 resource를 식별하고 접근/조작할 수 있다.
resource identifier를 사용하여 component간 인터랙션에 관련된 특정 리소스를 식별한다.
이는 웹 아키텍처에서 다양한 정보 소스를 포괄하고, contents 협상과 같은 기능 late binding을 허용하여 contents 협상과 같은 기능을 가능하게 하며, resource의 특정 표현에 종속되지 않고 개념을 참조할 수 있는 유연성을 제공한다.
: REST component는 리소스에 대해 특정 상태를 capture하는 표현 (representation) 을 사용하여 작업을 수행하고 component에 전달하여 인터랙션한다.
representation은 바이트 시퀀스와 그 바이트를 설명하는 metadata로 구성되며, document, file, HTTP message entity 등으로 알려진 다양한 형태를 가질 수 있다.
representation은 data와 그 데이터를 설명하는 metadata를 포함하며,
일반적으로 메시지 무결성을 검증하기 위한 목적으로 metadata의 메타데이터가 간혹 있음
metadata는 name-value 형식이다.
제어 데이터는 component간 메시지의 목적을 정의하고 요청과 응답의 동작을 조절한다.
미디어 타입은 representation의 형식을 지정하며, 이는 사용자가 렌더링하거나 시스템이 자동으로 처리할 수 있도록 한다.
미디어 타입 설계는 분산 하이퍼미디어 시스템의 사용자 인식 성능에 직접적인 영향을 미칠 수 있다.
REST는 아래의 요약된 표에서 다양한 connector 타입을 사용하여 resource에 액세스하고 리소스 표현을 전송하는 활동을 캡슐화한다.
connector는 component 통신을 위한 인터페이스 추상화를 제공하여, 우려 사항을 명확하게 구분하고 resource와 통신 메커니즘의 기본 구현을 숨겨 단순성을 향상시킨다. 인터페이스의 일반성은 또한 대체성을 가능하게 한다.
사용자가 시스템에 접근할 수 있는 유일한 방법이 추상 인터페이스라면, 사용자에게 영향을 미치지 않고 구현을 대체할 수 있다.
connector는 component의 네트워크 통신을 관리하므로, 정보는 여러 인터랙션에서 공유되며 효율성과 응답성을 개선할 수 있다.
모든 REST의 인터랙션은 stateless (무상태성)이다. 즉, 각 요청은 connector가 request를 이해하는데 필요한 모든 정보를 포함하며, 이는 이전의 request들과는 무관하다.
이러한 제한은 4가지를 수행한다.
1) connector가 request간에 application의 상태를 유지할 필요가 없어, 물리적 resource를 줄이고 확장성을 개선한다.
2) processing 메커니즘이 인터랙션 의미를 이해할 필요 없이 인터랙션을 병렬로 처리할 수 있도록 허용한다.
3) 중간매체인 intermediary가 request를 격리하여 보고 이해할수 있도록 하며, 이는 서비스가 동적으로 재배치될 때 필요할 수 있다.
4) cach된 request의 재사용성에 영향을 미칠 수 있는 모든 정보가 각 request에 존재하도록 강제한다.
connector interface는 절차적 호출 (procedural invocation)과 유사하지만 매개변수와 결과 전달에 있어 중요한 차이점이 있다.
in-parameters: 요청 제어 데이터
, 요청 대상을 나타내는 리소스 식별자 및 선택적 표현 (optional representation)
으로 구성
out-parameters: 응답 제어 데이터
, 선택적 리소스 메타데이터 및 선택적 표현
으로 구성
추상적인 관점에서 호출은 동기적이지만 in-param과 out-param 모두 데이터 스트림으로 전달될 수 있다.
즉, 매개변수 값을 완전히 알기 전에 처리를 호출할 수 있으므로 대량 데이터 전송을 일괄 처리하는 데 따른 지연을 피할수 있다.
REST에서 주요 connector type은 아래와 같다.
Client: request를 하여 통신을 시작
Server: 연결을 수신하고 요청에 응답하여 서비스 접근을 제공
component에는 client와 server connectors가 모두 포함될 수 있다.
Cache: client나 server connector의 인터페이스에 위치하여, 현재 인터랙션에 대한 캐시 가능한 응답을 저장하여 나중에 요청된 인터랙션에 재사용할 수 있다.
- 캐시는 client에 대해 응답을 재사용할 수 있도록 공유될 수 있으며, 이는 네트워크 트래픽을 줄이는 데 도움이 된다.
- 캐시는 인터페이스가 각 리소스에 특정하지 않고 일반적이기 때문에 response의 캐시 가능성을 결정할 수 있다.
Resolver: 리소스 식별자 (예: URL)를 네트워크 주소로 변환하여 component간에 연결을 설정하는데 필요한 정보를 제공
ex) DNS resolver는 호스트 이름을 IP 주소로 변환함.
Tunnel: 방화벽이나 low-level의 네트워크 gateway와 같은 경계를 통해 통신을 간단히 중계함
ex) HTTP proxy가 CONNECT 메서드 요청을 처리하여 TLS 통신을 위한 터널을 설정하는 등, 활성 component 동작에서 터널링으로 전환할 수 있음.
User Agent는 client connector를 사용하여 request를 시작하고 response를 받는 최종 recipient가 된다. 일반적인 예는 웹 브라우저로, 서비스에 대한 접근을 제공하고 애플리케이션 요구사항에 따라 서비스 응답을 렌더링한다.
Origin Server는 server connector를 사용하여 request된 resource의 namespace를 관리한다. 이는 resource 표현에 대한 궁극적인 소스이며, resource 값을 수정하려는 모든 request의 최종 recipient여야 한다.
각 origin server는 리소스 계층 구조로 서비스에 대한 일반 인터페이스를 제공한다. 리소스 세부구현은 인터페이스 뒤에 hidden 되어 있다.
Intermediary는 request와 response를 모두 전달하기 위해 client와 server의 역할을 모두 수행한다.
proxy component: client가 선택한 중간매체로 다른 서비스의 인터페이스 캡슐화, 데이터 변환, 성능 향상 또는 보안 보호를 제공한다.
gateway component: 네트워크 or origin server에 의해 부과되는 중간매체로 데이터 변환, 성능 향상 또는 보안 적용을 위해 다른 서비스의 인터페이스 캡슐화를 제공한다.
gateway == reverse proxy, 역방향 프록시
Note: proxy와 gateway의 차이점은 client가 proxy를 사용할 때 결정된다.
REST는 전체적으로 적용할 때 component interaction의 확장성, 인터페이스의 일반성, component의 독립적인 배포 및 intermediary component를 강조하여 인터랙션 지연 시간을 줄이고 보안을 강화하며 legacy system을 캡슐화하는 일련의 아키텍처 제약 조건을 제공한다.