REST
REST(REST: Representational State Transfer)는 리소스의 표현으로 구분하여 해당 리소스의 상태를 주고 받는 아키텍처 스타일입니다.
REST는 2000년 로이 필딩(Roy Fielding)이 정의한 아키텍처 스타일(architectural style)로 아키텍처 스타일이란 아키텍처에 적용되는 제약조건들의 집합을 의미합니다. 로이필딩은 REST를 Starting With the Null Style 방식을 이용하여 아키텍처를 설계하였으며 이는 어떤 제약 조건 없이 시스템의 전반에서 시작하여 점진적으로 제약 조건을 추가하는 방식입니다. 추가한 제약 조건들은 시스템내에서 조화롭고 자연스럽게 동작할 수 있도록 설계되며 이는 시스템 맥락에 대한 이해와 규제를 강조합니다.
REST의 특징을 도출해내기 위해서 설계 과정에서 추가된 제약 조건은 어떤 것이 있는지 알아 보도록 하겠습니다.
제약 조건
Client-Server
클라이언트-서버 제약 조건은 관심사의 분리(Seperation of Concern)에 대한 내용입니다. 데이터의 저장에 대한 관심사와 사용자 인터페이스에 대한 관심사를 분리함으로써 서버와 클라이언트는 독립적으로 수행될 수 있습니다. 즉 클라이언트 측의 코드는 서버의 동작에 영향을 주지 않고 언제든지 변경할 수 있고 서버 측의 코드는 클라이언트의 동작에 영향을 주지 않고 변경할 수 있음을 의미합니다. 이는 서버와 클라이언트의 역할에 맞게 독립적으로 각각 발전시킬 수 있습니다.
Stateless
Stateless 제약 조건은 클라이언트와 서버 사이의 상호 작용입니다. 클라이언트가 서버에 보내는 요청은 상태를 관리하지 않고 모든 요청은 독립적으로 처리됩니다. 클라이언트의 상태 정보는 서버에 저장되지 않으며 필요한 정보는 요청 자체에 포함되어야 합니다.
stateless 통신을 이용함으로써 다음과 같은 이점을 가질 수 있습니다.
- 가시성(Visibility): 서버는 클라이언트가 보낸 요청의 전체 특성을 파악하기 위해서는 해당 요청 외에는 다른 것을 고려하지 않아도 되기 때문에 가시성이 향상됩니다.
- 신뢰성(Reliability): 서버는 장애를 복구하기 위해서 클라이언트의 단일 요청만 고려하기 때문에 복구가 용이하고 서버의 장애 발생 시 다른 서버로 요청을 전달하여 부하 분산이 가능하며 이러한 확장성을 통해 신뢰성을 높일 수 있습니다.
- 확장성(Scalability): 요청 간에 상태를 저장할 필요가 없기 때문에 서버 구성 요소가 리소스를 신속하게 해제할 수 있고 서버가 요청 간에 리소스 사용을 관리할 필요가 없기 때문에 구현이 더욱 간소화되어 확장성이 향상됩니다.
Stateless 통신은 위와 같은 장점을 가지고 있지만 Stateful 통신과 대비되는 단점 또한 존재합니다. 클라이언트의 요청 정보가 서버에 저장되지 않기 때문에 매번 요청을 보낼 때마다 클라이언트의 부가 정보 추가로 전송해야하는 부분은 네트워크 성능을 저하시키는 요인 중 하나입니다.
Cache
캐시 제약 조건은 네트워크 성능을 향상 시키기 위함입니다. HTTP(Hyper Text Transfer Protocol)라는 기존 웹 표준을 사용하는 REST의 특징 덕분에 기본 웹에서 사용되는 인프라를 모두 사용이 가능합니다. 요청에 대한 응답 데이터가 암시적 또는 명시적으로 cacheable한지 non-cacheable한지 지정되어야 하는데 REST는 웹 기본 인프라를 이용해 응답 데이터의 캐시 가능 여부를 처리합니다.
캐시 제약 조건을 통해 지속적인 상호 작용(서버와 클라이언트 간의 통신)을 부분적으로 또는 완전히 제거하여 평균 통신 시간을 줄일 수 있다는 점입니다.
반면 서버가 가지고 있는 데이터와 클라이언트가 가지고 있는 캐시 데이터에 다르거나 오래된 데이터가 포함되어 있다면 요청-응답에 대한 신뢰성이 저하될 수 있다는 단점이 있습니다.
Uniform Interface
Uniform Interface 제약 조건은 REST 디자인의 일관성과 통일성을 유지하기 위한 제약 조건입니다. REST 아키텍처 스타일을 다른 네트워크 기반 스타일과 구별하는 주요한 특징으로 구성요소 간의 균일한 인터페이스에 중점을 둔다는 것입니다. 소프트웨어 공학의 원칙인 일반성(Generality)을 적용함으로써, 전체 아키텍처는 단순화되고 상호 작용의 가시성이 향상됩니다. 모든 컴포넌트들은 서비스로 부터 분리되어 각 컴포넌트 별로 독립적으로 발전할 수 있는 진화 가능성(Evolvability)를 가지게 됩니다.
Uniform Interface를 가지기 위해서는 다음과 같은 제약 조건을 따릅니다.
- Identification of Resources (리소스 식별): 리소스는 고유한 식별자를 가지고 있어야 합니다. 클라이언트는 리소스를 식별하고 요청할 수 있어야 합니다.
- Manipulation of Resources through Representations (표현을 통한 리소스 조작): 클라이언트는 리소스를 요청할 때 서버는 리소스 자체가 아닌 리소스 표현( Representation)을 사용합니다. 표현은 데이터의 형태로 일반적으로 JSON 또는 XML 형식이 사용됩니다.
- Self-Descriptive Messages (자체 기술적인 메세지): 메세지는 그 자체로 충분한 정보를 제공하여 해석될 수 있어야 합니다. 메세지에는 요청 또는 응답에 대한 모든 필요한 정보가 포함되어야 합니다.
- Hypermedia as the Engine of Application State (하이퍼미디어를 응용프로그램 상태의 엔진으로 활용): 서버는 하이퍼미디어를 통해 클라이언트에게 애플리케이션의 상태 전이를 제공합니다. 예를 들어 클라이언트는 특정 리소스를 조회한 후 해당 리소스와 관련된 하이퍼링크를 사용하여 다음 동작을 수행할 수 있습니다.
상태 전이란 해당 URI에서 사용자가 다음 행동으로 취할 수 있는 것을 나타내며 이런 상태 전이가 가능한 것을 응답 본문에 추가해야합니다.
Layerd System
Layerd System은 Internet-scale 요구사항 즉 더 큰 규모의 네트워크를 지원하기 위해 추가된 제약 조건입니다. 아키텍처를 계층적으로 구성한다는 의미는 상호 작용하는 컴포넌트들의 계층 너머로의 동작을 제한하는 것을 의미합니다.
계층 구조는 기존 레거시 서비스를 캡슐화하고, 새로운 서비스를 기존의 클라이언트로부터 보호 할 수 있으며 자주 사용하지 않는 기능을 공유 중개자(shared intermediary)로 이동하여 구성 요소를 간소화할 수 있습니다.
하지만 Layerd System의 주요 단점으로는 데이터 처리의 오버헤드와 지연이 가중돼 성능을 저하시킨다는 점입니다. 또한 각 컴포넌트 간의 인터페이스를 정의해야하므로 추가적인 작업이 필요하지만 캐시 제약 조건을 지원하는 네트워크 기반 시스템의 경우 공유 중개자를 캐싱해 네트워크 성능을 향상시키며 uniform interface를 통해 일관된 인터페이스를 정의하므로 위와 같은 단점들을 상쇄할 수 있습니다.
Code-on-Demand
Code-on-Demand(CoD)는 서버에서 전송되는 리소스의 일부로 실행 가능한 코드를 포함해야한다는 마지막 제약 조건이자 선택적 제약 조건입니다.
코드를 다운로드하고 실행 할 수 있게함으로써 클라이언트 측에서 사전 구현해야할 기능을 감소시켜 클라이언트를 단순화(원문: This simplifies clients) 할 수 있습니다. 또한 배포 후 기능을 다운로드할 수 있으면 시스템 확장성이 향상되지만 동시에 가시성도 감소되므로 선택적 제약 조건입니다.
이런 선택적인 제약 조건의 개념은 모순처럼 보일 수 있으나 다음과 같은 이유로 제한합니다.
- 일부 클라이언트 환경에서 코드 실행 환경으로 인해 서버에서 제공하는 코드를 실행 할 수 없는 경우
- 서버에서 전송되는 코드가 악의적인 코드인지 확인할 수 없는 경우
- 서버에서 제공하는 특정 코드를 이해하고 실행하기 때문에 범용성과 상호 운용성을 해하는 경우
RESTful API
RESTful
RESTful은 일반적으로 REST 아키텍처 스타일을 적용해 만든 웹 서비스를 지칭하는 단어로 웹 서비스의 자원을 고유한 URI(Uniform Resource Identifier)로 표현하고 HTTP 프로토콜을 통해 클라이언트와 상호 작용하는 웹 서비스를 나타내기 위한 용어입니다.
특징
- 리소스(Resources): REST API는 서비스가 제공하는 자원을 나타냅니다. 예를 들어, 사용자, 제품, 주문 등은 각각 개별적인 자원으로 표현될 수 있습니다. 각 자원은 고유한 식별자(URI)를 가지며, 해당 자원에 대한 조작이 이루어집니다.
- URI(Uniform Resource Identifier): URI는 URL(Uniform Resource Locator)와 URN(Uniform Resource Name)을 포함하는 개념으로 자원의 고유 식별자로서 이용됩니다.
- HTTP 메소드: REST API는 웹 기본 인프라인 HTTP 메소드를 활용하여 리소스를 조작합니다. 기본적으로 다음과 같이 활용됩니다.
- GET: 리소스의 조회
- POST: 리소스의 생성
- PUT: 리소스의 수정
- DELETE: 리소스의 삭제
- 표현(Representation): 리소스는 클라이언트에게 표현을 통해 전달됩니다. 여기서 표현은 데이터의 형태로 일반적으로 JSON, XML, HTML 등 다양한 형식으로 사용됩니다.
- 상태 전이(State Transfer): 클라이언트와 서버 간의 상호 작용을 구현해야합니다. 서버는 상태 전이를 위한 응답을 제공하며 클라이언트가 다음 동작을 수행하도록 유도합니다.
로이 필딩의 Architectural Styles and the Design of Network-based Software Architectures 를 참고하여 작성했습니다.
오탈자 및 오류 내용을 댓글 또는 메일로 알려주시면, 검토 후 조치하겠습니다.