일관성 있는 웹 서비스 인터페이스 설계를 위한 REST API 디자인 규칙
1. REST 소개
1.1 Hello World Wild Web
웹은 스위스 제네바의 유럽입자물리연구소CERN 산하 ‘데이터 수집과 제어’ 그룹에 근무하던 컴퓨터 프로그래머가 새로운 소프트웨어 프로젝트를 진행하기 위해 낸 기발한 아이디어에서 시작되었다.
1990년 12월, 지식을 쉽게 공유하고자 월드와이드웹WorldWideWeb01이라는 비영리 소프트웨어 프로젝트를 시작한 팀 버너스리Tim Berners-Lee는 약 1년간 작업한 후 다 음과 같은 내용을 고안하고 구현했다.
- URIUniform Resource Identifier : 모든 웹 도큐먼트에 할당된 유일한 주소
- HTTPHyper Text Transfer Protocol : 인터넷을 통해 컴퓨터가 통신하기 위한 메시지 기반 언어
- HTMLHyper Text Mark-up Language : 정보를 제공하는 도큐먼트를 표현하기 위한 하이퍼텍스트 마크업 언어. 도큐먼트는 관련된 다른 도큐먼트에 대한 링크를/ 포함할 수 있음
- 최초의 웹 서버
- WorldWideWeb과 Nexus : 버너스리는 최초의 웹 브라우저를 ‘WorldWideWeb’ 이라 불렀으나 이후에 웹 자체와의 혼동을 피하기 위해 Nexus라고 이름 붙임
- 웹 브라우저에 탑재된 최초의 위지윅(WYSIWYG)04 HTML 에디터
1991년 8월 6일, 버너스리는 최초의 웹 페이지에 다음과 같이 썼다.
WorldWideWeb(W3)은 전 세계에 있는 모든 도큐먼트에 접근하는 것을 목표로 하는 광범위한 하이퍼미디어 정보검색의 시작이다.
1.2 웹 아키텍쳐
1993년 말에 공동으로 ‘아파치 HTTP 서버 프로젝트’를 시작한 로이 필딩은 웹 확장성에 관심이 있었다. 필딩은 제약점들을 여섯 가지 범주로 묶어 웹의 구조적 스타일(Web’s architectural style) 이라고 불렀다. 언급한 웹의 구조적 스타일은 다음과 같다.
- 클라이언트/서버 Client/Server
- 균일한 인터페이스 Uniform Interface
- 계층 시스템 Layered System
- 캐시 Cache
- 상태 없음 Stateless
- 주문형 코드 Code-on-demand
클라이언트/서버 웹은 클라이언트/서버 기반 시스템으로, 클라이언트/서버 규약의 핵심 사항은 관 심사의 분리다. 그래서 시스템 내에서 클라이언트와 서버의 역활은 분명하게 나뉜 다. 웹의 일관된 인터페이스를 따른다는 전제하에, 클라이언트와 서버는 각자의 언 어 및 기술을 사용하여 독립적으로 구현되고 배포될 수 있다.
균일한 인터페이스 웹을 구성하는 클라이언트, 서버, 네트워크 등의 매체 간 인터페이스는 각 인터페 이스의 일관성에 기반한다. 이러한 웹 컴포넌트들 중 하나라도 기존에 구축된 표준 에서 벗어나면, 웹 커뮤니케이션 체계는 붕괴된다. 웹 컴포넌트들은 필딩이 구분한 다음 네 가지의 인터페이스 제약에 따라 서로 일관 성 있게 상호 운영된다.
- 리소스 식별
- 표현을 통한 리소스 처리
- 자기-서술적 메시지Self-descriptive messages
- 애플리케이션 상태 엔진으로서의 하이퍼미디어(HATEOAS07)
계층 시스템 계층 시스템이라는 제약조건은 프락시 또는 게이트웨이 같은 네트워크 기반의 중 간매체를 사용할 수 있게 한다. 웹의 일관된 인터페이스를 사용하면 중간매체를 클 라이언트와 서버 사이에 마치 없는 것처럼 배치할 수 있다. 일반적으로 네트워크 기반의 중간매체는 특별한 목적을 위해 클라이언트와 서버 간 통신을 가로챌 수 있다. 네트워크 기반의 중간매체는 보통 보안을 강화하거나, 응답을 캐싱하거나, 부하를 분산하는 용도로 사용한다.
캐시 캐시는 웹 구조의 중요 제약조건 중 하나다. 캐시라는 제약조건에 의해 웹 서버가 응답 데이터마다 캐시 여부를 선언한다. 캐싱 응답 데이터는 클라이언트가 느끼는 지연을 감소시키고 애플리케이션의 전체적인 이용 가능성과 안정성을 향상시키 며, 웹 서버의 부하를 제어한다. 다시 말해, 캐싱08은 웹의 전체적인 비용을 낮출 수 있는 중요한 방법이다. 캐시는 클라이언트와 서버 사이의 네트워크 경로라면 어디 에라도 위치할 수 있다. 웹 서버단, 콘텐츠 전송망CDN단, 또는 클라이언트 내에도 가능하다.
상태 없음 상태 없음 제약조건은 웹 서버가 클라이언트의 상태를 관리할 필요가 없다는 의미 다. 따라서 각 클라이언트는 웹 서버와 상호작용하는 관련 상황 정보를 직접 관리 해야 한다. 웹 서버는 웹 애플리케이션과의 복잡한 커뮤니케이션을 위해 필요한 상 태 관리를 클라이언트에 맡김으로써 더 많은 클라이언트에 서비스할 수 있다. 이러 한 트레이드오프는 웹 구조적인 스타일의 확장성에 이바지하는 주요 요소다.
주문형 코드 웹은 주문형 코드(Code-On-Demand)를 아주 많이 사용한다. 이 제약조건은 스크립트나 플러그인 같은 실행 가능한 프로그램을 일시적으로 클라이언트에 전송하여, 클라 이언트가 실행할 수 있도록 한다. 주문형 코드는 웹 서버와 클라이언트 사이에 기술적 결합을 만들어내기도 하는데, 클라이언트는 필요할 때마다 서버에서 내려받은 실행 코드를 이해해야 하기 때문 이다. 이러한 이유로 주문형 코드는 웹의 구조적 스타일에서 유일한 선택사항이다. 주문형 코드 제약사항의 예로 자바 애플릿, 자바스크립트, 플래시 같은 웹 브라우 저 기반의 기술들이 있다.
1.3 웹표준
필딩은 팀 버너스리를 비롯한 다른 개발자들과 함께 웹 확장성을 높이는 작업 을 했다. 이런 작업을 통해 표준 설계안을 만들었고, HTTP의 새로운 버전인 HTTP/1.1 스펙을 작성하였다. 또한, URI 문법 형식도 (RFC 3986)으로 규정하 였다. 이렇게 정리된 표준은 웹을 통해 급속히 확산되었고, 웹이 지속적으로 성장하 는 기틀을 마련했다.
1.4 REST
필딩은 자신의 박사학위 논문에 서 ‘웹의 구조적 스타일’이라고 이름 붙인 이 문제에 대해 설명하였다. 필딩이 ‘Representational State Transfer(표현 상태 전이, REST)’이라는 이름을 붙인, 웹의 구조적 스타일에 대한 설명은 제약조건들로 이루어져 있다.
1.5 REST API
웹 서비스는 특정한 목적을 위해 만들어진 웹 서버로, 다른 사이트나 다른 애플리 케이션이 필요로 하는 것을 제공한다. 클라이언트 프로그램은 웹 서버에서 제공하 는 API를 이용하여 웹 서비스와 통신한다. 보통 API는 데이터와 기능의 집합을 제 공하여 컴퓨터 프로그램 간 상호작용을 촉진하며, 서로 정보를 교환할 수 있게 해 준다. REST API를 제공하는 웹 서비스를 ‘RESTful’하다고 할 수 있다. REST API는 상 호 연결된 리소스의 결합체며, 이 리소스 집합을 일컬어 REST API의 리소스 모델 이라고 한다.
1.6 REST API 설계
EST API 설계의 몇 가지 모범 사례는 HTTP 표준에 포함되어 있지만, 지난 몇 년 동안 표준과 같은 몇 가지 접근 방법이 새롭게 부각되었다. 여전히 우리는 다음과 같은 질문들에 대한 답을 찾아야 한다.
- URI 경로path 세그먼트는 언제 복수로 써야 하는가?
- 리소스의 상태를 업데이트하려면, 어떤 메서드를 사용해야 하는가?
- CRUD12가 아닌 연산을 어떻게 URL에 매핑하는가?
- 특정한 시나리오에 가장 적합한 HTTP 응답은 무엇인가?
- 리소스 상태 표현의 버전은 어떻게 관리할 수 있는가?
- JSON에 포함된 하이퍼링크는 어떻게 구조화하는가?
1.7 정리
2. URL 식별자 설계
2.1 URI
팀 버너스리는 그가 정의한 웹 구조의 원칙(Axioms of Web Architecture)에서 URI의 불투 명성에 대해 다음과 같이 설명하였다.
식별자로 할 수 있는 유일한 일은 대상을 나타내는 것이다. 역참조를 할 때가 아니라면 다른 정보를 얻기 위해서 URI의 내용을 들여다보지 말아야 한다.
2.2 URI 형태
RFC 3986 에서 는 일반적인 URI 문법을 다음과 같이 정의하였다.
URI = scheme “ :// ” authority “ / ” path [“ ? ” query] [“ # ” fragment ]
규칙: 슬래시 구분자(/)는 계층 관계를 나타내는 데 사용한다 포워드 슬래시(/)는 경로(path) 내에서 리소스 간의 계층 관계를 나타내는 데 사용한다.
규칙: URI 마지막 문자로 슬래시(/)를 포함하지 않는다 URI 경로 마지막에 있는 슬래시는 아무런 의미가 없지만, 혼란을 초래할 수 있다. 그러므로 REST API의 마지막 글자에 슬래시가 와서는 안 되고 클라이언트에 제공 하는 링크에도 그런 API를 포함하면 안 된다.
규칙: 하이픈(-)은 URI 가독성을 높이는 데 사용한다 URI를 쉽게 읽고 해석하기 위해, 긴 URI 경로에 하이픈을 사용해서 가독성을 높 인다. URI에서는 문장 내 공백을 하이픈으로 바꿀 수 있다.
규칙: 밑줄( _ )은 URI에 사용하지 않는다 텍스트 뷰어 애플리케이션은 클릭할 수 있다는 표시로 URI에 밑줄을 긋는다. 글꼴 에 따라 다르긴 하지만, 밑줄은 보기 어렵거나 밑줄 때문에 문자가 완전히 가려지 기도 한다.
규칙: URI 경로에는 소문자가 적합하다 URI 경로에 대문자를 사용하면 문제가 될 수 있으므로 소문자를 사용한다. RFC 3986은 URI 스키마와 호스트를 제외하고는 대소문자를 구별하도록 규정한다.
규칙: 파일 확장자는 URI에 포함시키지 않는다 웹에서 점(.) 문자는 URI에서 파일 이름과 확장자를 구분하는 데 사용한다. 하지 만 REST API에서는 메시지 바디 내용의 포맷을 나타내기 위한 파일 확장자를 URI 안에 포함하지 않아도 된다. 대신 이 확장자는 미디어 타입에 의존하는데, Content-Type 헤더를 통해 전달되고 메시지 바디의 내용을 어떻게 처리할지 결 정한다.
2.3 URI 권한 설계
규칙: API에 있어서 서브 도메인은 일관성 있게 사용해야 한다 API 최상위 도메인과 1차 서브 도메인 이름(예, soccer.restapi.org)으로 서비스 제공자를 식별해야 한다. API의 전체 도메인 이름에 api라는 서브 도메인을 다음 과 같이 붙여야 한다.
규칙: 클라이언트 개발자 포탈 서브 도메인 이름은 일관성 있게 만들어야 한다 보통 REST API는 개발자 포탈DEVELOPER PORTAL이라는 개발자들을 위한 웹 사이트를 지원한다. 이 포탈은 웹 사이트의 문서, 포럼, 포탈 내에서 직접 제공하는 안전한 API 접근키를 이용하여 새로운 클라이언트를 만드는 데 도움을 준다. API가 이러 한 개발자 포탈을 제공하는 경우, 관습적으로 DEVELOPER라는 이름의 서브 도메인 을 만든다.
2.4 리소스 모델링
URI 경로는 REST API의 리소스 모델을 다루는데, 포워드 슬래시(/)로 경로 구문 을 나눈다. 이 경로 구문은 리소스 모델 계층에서 유일한 리소스에 해당된다. 리소스 모델링은 API의 주요 개념을 확실하게 잡는 훈련과도 같다. 이 과정은 마치 관계형 데이터베이스 스키마를 정의하기 위한 데이터 모델링이나, 객체 지향 시스 템에서의 클래스 모델링과 유사하다.
2.5 리소스 원형
API 리소스를 모델링할 때, 기본적인 리소스 원형 몇 개를 가지고 시작할 수 있다.
-
도큐먼트 도큐먼트 리소스는 객체 인스턴스나 데이터베이스 레코드와 유사한 단일 개념이 다. 일반적으로 도큐먼트의 상태 표현은 값을 가진 필드와 다른 관련 리소스와의 링크 둘 다를 가지게 된다. 기본적인 필드와 링크 기반 구조로 인해, 도큐먼트 타입 은 다른 리소스 원형들의 기반 원형이 된다. 즉, 서로 다른 리소스 원형 세 개는 도 큐먼트 원형에서 분리된 것이라 볼 수 있다.
-
컬렉션 컬렉션 리소스는 서버에서 관리하는 디렉터리라는 리소스다. 클라이언트는 새로 운 리소스를 제안해서 컬렉션에 포함시킬 수 있다. 그러나 새로운 리소스를 생성할 지는 컬렉션에 달려 있다. 컬렉션 리소스에 포함하고 싶은 것을 선택하고, 포함된 각 리소스의 URI를 결정한다.
-
스토어 스토어는 클라이언트에서 관리하는 리소스 저장소다. 스토어 리소스는 API 클라 이언트가 리소스를 넣거나 빼는 것, 지우는 것에 관여한다. 스토어 스스로 새로운 리소스를 생성하지 못하기 때문에, 새로운 URI를 만들지는 못한다. 대신 리소스는 스토어에 처음 저장될 때, 클라이언트가 선택한 URI를 가진다.
-
컨트롤러 컨트롤러 리소스는 절차적인 개념을 모델화한 것이다. 컨트롤러 리소스는 실행 가 능한 함수와 같아서 파라미터(입력 값)와 반환 값(출력 값)이 있다. 전통적인 웹 애플리케이션이 ‘HTML form’을 사용하듯이, REST API는 CRUD라 고 알려진 표준적인 메서드와는 논리적으로 매핑되지 않는 애플리케이션 고유의 행동을 컨트롤러 리소스의 도움을 받아 수행한다.
2.6 URI 경로 디자인
슬래시(/)로 구분된 각 URI 경로 부분은 다양한 형태로 설계할 수 있다. URI 경로 각 부분에 의미 있는 값들을 줌으로써 REST API 리소스 모델 디자인의 계층적 구 조를 분명하게 표현할 수 있다.
규칙: 도큐먼트 이름으로는 단수 명사를 사용해야 한다
- http://api.soccer.restapi.org/leagues/seattle/teams/trebuchet/players/claudio
규칙: 컬렉션 이름으로는 복수 명사를 사용해야 한다
- http://api.soccer.restapi.org/leagues/seattle/teams/trebuchet/players
규칙: 스토어 이름으로는 복수 명사를 사용해야 한다
- http://api.music.restapi.org/artists/mikemassedotcom/playlists
규칙: 컨트롤러 이름으로는 동사나 동사구를 사용해야 한다 프로그램에 사용하는 함수처럼, 컨트롤 리소스를 나타내는 URI는 동작을 포함하는 이름으로 지어야 한다. 예를 들면 다음과 같이 짓는다.
- http://api.college.restapi.org/students/morgan/register
- http://api.example.restapi.org/lists/4324/dedupe
- http://api.ognom.restapi.org/dbs/reindex
- http://api.build.restapi.org/qa/nightly/runTestSuite
규칙: 경로 부분 중 변하는 부분은 유일한 값으로 대체한다
- REST API의 클라이언트에서는 URI가 하나의 유의미한 리소스 식별자임을 고 려해야 한다. 백엔드 시스템의 식별자(이를 테면, 데이터베이스의 ID와 같은)가 URI 경로에 표시될 수 있지만, 이는 클라이언트 코드 입장에서는 별로 의미가 없 다. URI를 유일한 ID로 사용해야만 기존 클라이언트에 영향을 미치지 않고, REST API의 백엔드 시스템을 개선할 수 있다.
규칙: CRUD 기능을 나타내는 것은 URI에 사용하지 않는다
- URI는 리소스를 식별하 는 데만 사용해야 하고, 위에서 설명한 내용을 바탕으로 설계되어야 한다
2.7 URI Query 디자인
RFC 3986에서 URI 쿼리 는 선택사항이고 경로와 다른 선택사항인 프래그먼트fragment 사이에 온다.
URI = scheme “://” authority “/” path [ “?” query ] [ “#” fragment ]
쿼리 구성요소는 클라이언트에 검색이나 필터링 같은 추가적인 상호작용 능력을 제공한다. 그러나 URI의 다른 구성요소와는 달리, 쿼리 부분은 REST API 클라이 언트에 반드시 필요한 것은 아니다.
규칙: URI 쿼리 부분으로 컬렉션이나 스토어를 필터링할 수 있다
규칙: URI 쿼리는 컬렉션이나 스토어의 결과를 페이지로 구분하여 나타내는 데 사용해야 한다
- GET /users?pageSize=25&pageStartIndex=50 (50페이지부터 최대 75페이지까지만)
- URI 쿼리로 클라이언트의 페이지나 필터링의 요구 사항에 대응할 수 없다면, 컬렉 션이나 스토어의 파트너가 될 수 있는 특별한 컨트롤러를 생각해봐야 한다. 예를 들어, 다음 컨트롤러는 URI 쿼리 파트 대신 리퀘스트의 바디 부분에 좀 더 복잡한 입력을 받을 수 있다.
POST /users/search 이 디자인으로 맞춤 범위 형태나 특별한 소팅 순서 등이 클라이언트 리퀘스트 메시 2장 URI 식별자 설계 25 This eBook is licensed to 김현진(khjzzm@gmail.com). Personal use only 지 바디에 쉽게 기술될 수 있다.
2.8 정리
3. HTTP를 이용한 인터랙션 설계
3.1 HTTP/1.1
REST API는 요청 메서드, 응답 코드, 메시지 헤더 등 HTTP 버전 1.101의 모든 측 면을 수용한다.
3.2 요청 메서드
클라이언트는 상호작용하려는 메서드를 HTTP 요청 메시지의 Request-Line 부 분에 명시한다. RFC 2616에서는 Request-Line 문법을 다음과 같이 정의한다.
Request-Line = Method SP Request-URI SP HTTP-Version CRLF (SP: Space, CRLF: Carriage Return Line Feed)
규칙: GET 메서드나 POST 메서드를 사용하여 다른 요청 메서드를 처리해서 는 안 된다 터널링tunneling은 메시지의 원래 의도를 감추거나 잘못 표현하는 것, 프로토콜의 투 명성을 훼손하는 것 등의 HTTP 오용을 의미한다. 한정된 HTTP 문법으로 클라 이언트에 대응하기 위해서 HTTP 요청 메서드를 원래의 의미와 다르게 사용하는 REST API를 설계해서는 안 된다.
규칙: GET 메서드는 리소스의 상태 표현을 얻는 데 사용해야 한다 클라이언트의 GET 요청 메시지는 바디 없이 헤더 로만 구성된다. 웹은 구조상 GET 메서드의 특성에 많이 의존한다. 클라이언트에서 GET 요청을 반복해도 문제가 없어야 하며, 캐시는 리소스를 제공하는 원래 서버와 통신하지 않 고도 캐시된 내용을 제공할 수 있어야 한다.
규칙: 응답 헤더를 가져올 때는 반드시 HEAD 메서드를 사용해야 한다 클라이언트는 HEAD 메서드를 사용하여 헤더 정보만 가져온다. 즉, HEAD 메서드 는 GET 메서드와 동일한 응답을 주지만, 바디가 없다. 클라이언트는 HEAD 메서 드를 사용하여 리소스 존재 여부를 확인하거나 메타데이터만 읽을 수 있다.
규칙: PUT 메서드는 리소스를 삽입하거나 저장된 리소스를 갱신하는 데 사용해 야 한다 PUT 메서드는 클라이언트가 기술한 URI로 스토어에 새로운 리소스를 추가하는 데 사용한다. 이미 스토어에 저장된 리소스를 갱신하거나 다른 것으로 대체하는 데 도 PUT 메서드를 사용한다.
규칙: PUT 메서드는 변경 가능한 리소스를 갱신하는 데 사용해야 한다 클라이언트는 PUT 요청 메서드를 사용해서 리소스를 변경한다. PUT 요청 메시지 에는 원하는 형태로 변경된 메시지 바디를 포함할 수 있다.
규칙: POST 메서드는 컬렉션에 새로운 리소스를 만드는 데 사용해야 한다 클라이언트는 POST 메서드를 사용해서 컬렉션 안에 새로운 리소스를 만든다. POST 요청 바디는 새로운 리소스를 위해 제안된 상태 표현을 포함하는데, 이것은 서버 소유의 컬렉션에 추가된다.
규칙: POST 메서드는 컨트롤러를 실행하는 데 사용해야 한다 클라이언트는 POST 메서드를 사용해서 기능 지향적인 컨트롤러 리소스를 동작시 킨다. POST 요청 메시지는 컨트롤러 리소스 기능의 입력 값을 헤더나 바디에 포함 할 수 있다. HTTP 표준에서는 POST 메서드에 의미상의 제한을 두지 않으며, 반복이나 부작 용과 상관없이 어떤 액션도 수행할 수 있다. 이런 특징 때문에, POST 메서드를 제 한 없는 컨트롤러 리소스로 사용할 수 있다. REST API 디자인은 컨트롤러 리소스로 모든 동작을 실행하기 위해 POST 메서드 를 사용하는데, 각 기능 및 동작은 직관적으로 HTTP 메서드들과 매핑되지 않는 다. 다시 말해, POST 메서드는 리소스를 가지고 오거나, 저장하거나, 지우는 데 사 용하지는 않는다(HTTP는 이런 기능에 대해서는 각각 다른 메서드를 사용한다).
규칙: DELETE 메서드는 그 부모에서 리소스를 삭제하는 데 사용해야 한다 클라이언트는 DELETE 메서드 요청을 사용하여 컬렉션이나 스토어인 부모에서 리 소스를 완전히 제거한다. 주어진 리소스에 DELETE 요청이 수행되면, 클라이언트는 그 리소스를 볼 수 없게 된다. 따라서 GET 메서드나 HEAD 메서드로 리소스의 현재 상태를 가져오려는 어떤 API 시도도 404(“Not Found”) 상태로 끝나게 된다. DELETE 메서드는 HTTP에서 매우 명확한 의미로 사용되며, REST API 디자인 에 오버로드되거나 확장될 수 없다. 어떤 경우에도, 클라이언트에서 사용할 수 있 는 리소스나 URI로 삭제하지 않는 기능에 DELETE 메서드를 사용하여 원래 의미 를 왜곡해서는 안 된다
규칙: OPTIONS 메서드는 리소스의 사용 가능한 인터랙션을 기술한 메타데 이터를 가져오는 데 사용해야 한다 클라이언트는 OPTIONS 메서드를 사용하여 Allow 헤더에 포함된 리소스 메타 데이터를 가져온다.REST API는 OPTIONS 메서드 요청에 대한 응답으로 각 인터랙션 항목의 세부 사 항을 바디에 포함할 수 있다.
3.3 응답상태코드
규칙: 200(“OK”)는 일반적인 요청 성공을 나타내는 데 사용해야 한다 200은 클라이언트가 요청한 어떤 액션이었든지 REST API가 성공적으로 수행했 음을 나타내는 코드로, 클라이언트는 이 코드를 받길 원한다. 또한 더 이상의 할당 된 ‘2xx’계열의 응답코드가 없다는 뜻이기도 하다. 204 상태 코드와는 달리, 200 응답은 응답 바디가 포함된다.
규칙: 200(“OK”)는 응답 바디에 에러를 전송하는 데 사용해서는 안 된다 항상 이 부분에 기술한 규칙을 사용하여 적절한 HTTP 응답 상태 코드를 사용한다. 특히, REST API는 부실한 HTTP 클라이언트에 부합하려는 그 어떤 타협도 해서는 안 된다.
규칙: 201(“Created”)는 성공적으로 리소스를 생성했을 때 사용해야 한다 REST API는 클라이언트의 요청으로 새로운 리소스를 이용하여 컬렉션에 생성했 거나 스토어에 추가했을 때 201 상태 코드로 응답한다. 컨트롤러의 행동으로 새로 운 리소스가 생겨났을 경우에도 201 상태 코드로 응답한다.
규칙: 202(“Accepted”)는 비동기 처리가 성공적으로 시작되었음을 알릴 때 사용해야 한다 202 응답은 클라이언트의 요청이 비동기적으로 처리될 것임을 나타낸다. 이 응답 상태 코드는 유효한 요청이었지만, 최종적으로 처리되기까지는 문제가 생길 수도 있다는 것을 클라이언트에게 알려준다. 보통 202 응답은 처리 시간이 오래 걸리는 액션에 사용된다. 컨트롤러 리소스는 202 응답을 보낼 수 있지만 다른 리소스 타 입은 보낼 수 없다.
규칙: 204(“No Content”)는 응답 바디에 의도적으로 아무것도 포함하지 않 을 때 사용한다 204 상태 코드는 보통 PUT, POST, DELETE 요청에 대한 응답으로 이용하는데, REST API가 응답 메시지의 바디에 어떠한 상태 메시지나 표현을 포함해서 보내지 않을 때 사용한다. API는 GET 요청에 204로 응답할 수 있는데, 요청된 리소스는 존재하나 바디에 포함시킬 어떠한 상태 표현도 가지고 있지 않다는 것을 나타낸다.
규칙: 301(“Moved Permanently”)는 리소스를 이동시켰을 때 사용한다 301 상태 코드는 REST API 리소스 모델이 상당 부분 재설계되었거나 계속 사용할 새로운 URI를 클라이언트가 요청한 리소스에 할당하였다는 것을 나타낸다. REST API는 응답의 Location 헤더에 새로운 URI를 기술해야 한다.
규칙: 302(“Found”)는 사용하지 않는다 많은 프로그래머가 302 응답 코드의 원래 의미를 잘못 이해하고 HTTP 버전02 1.0 이래로 부정확하게 구현하고 있다. 이러한 혼란의 중심에는 클라이언트에서 최초 의 요청 메서드와 무관하게 응답 메시지의 Location 헤더에 있는 URI로 연이어 GET 요청을 자동으로 보내는 것이 적절한지에 대한 논란이 존재한다. 302의 공식 적인 의도는 이러한 자동 재전송은 클라이언트가 GET이나 HEAD를 사용하여 최 초 요청을 한 경우에만 적용하는 것이다. HTTP 1.1에서는 이 문제를 해결하기 위해 302대신 303(“See Other”)과 307(“Temporary Redirect”)을 도입했다.
규칙: 303(“See Other”)은 다른 URI를 참조하라고 알려줄 때 사용한다 303 응답은 처리가 끝난 컨트롤러 리소스가 잠재적으로 원하지 않는 응답 바디를 보내는 대신, 응답 리소스의 URI를 보냈음을 나타낸다. 이것은 임시 상태 메시지 의 URI일 수도 있고, 이미 존재하는 영구적인 리소스의 URI일 수도 있다. 303 상태 코드는 일반적으로 REST API가 클라이언트에 상태 다운로드를 강요 하지 않으면서 참조 리소스를 보내는 것을 허용한다. 대신 클라이언트는 응답 Location 헤더에 있는 값으로 GET 요청을 보낼 수 있다.
규칙: 304(“Not Modified”)는 대역폭을 절약할 때 사용한다 이 상태 코드는 응답 바디에 아무것도 없어야 한다는 측면에서 204(“No Content”) 와 유사하다. 주요 차이점은 204는 바디에 보낼 내용이 없을 때 사용하는 반면, 304는 리소스에 대한 상태 정보가 있긴 하지만 클라이언트에 이미 해당 상태의 최신 버전이 있다는 걸 의미할 때 사용한다. 이 상태 코드는 조건부 HTTP 요청과 함께 사용하는데, 4장에서 자세히 살펴볼 것 이다.
규칙: 307(“Temporary Redirect”)는 클라이언트가 다른 URI로 요청을 다시 보내게 할 때 사용해야 한다 HTTP/1.1은 최초의 302(“Found”) 상태 코드 의미를 반복하기 위해 307 응답 코 드를 도입하였다. 307 응답은 REST API가 클라이언트의 요청을 처리하지 않을 것임을 나타낸다. 클라이언트는 응답 메시지의 Location 헤더에 기술된 URI로 요 청을 다시 보내야 한다. REST API는 요청된 클라이언트의 리소스에 임시 URI를 할당하여 상태 코드를 사 용할 수 있다. 예를 들면, 307 응답은 클라이언트 요청을 다른 호스트로 바꾸는 데 사용한다.
규칙: 400(“Bad Request”)는 일반적인 요청 실패에 사용해야 한다 400은 다른 적절한 ‘4xx’ 오류 값이 없을 때 사용하는 일반적인 클라이언트의 에러 상태다.
‘4xx’ 범주의 오류는 클라이언트의 오류를 기술하는 도큐먼트를 응답 바디에 포함할 수 있다 (요청 메서드가 HEAD일 경우는 제외). 오류 응답 바디 디자인은 5장의 ‘오류 표현’을 참고한다.
규칙: 401(“Unauthorized”)는 클라이언트 인증에 문제가 있을 때 사용해야 한다 401 오류 응답은 클라이언트가 적절한 인증 없이 보호된 리소스를 사용하려고 할 때 발생한다. 인증을 잘못하거나 아예 인증하지 못할 경우 발생한다.
규칙: 403(“Forbidden”)은 인증 상태에 상관없이 액세스를 금지할 때 사용 해야 한다 403 오류 응답은 클라이언트의 요청은 정상이지만, REST API가 요청에 응 하지 않는 경우를 나타낸다. 즉, 403 응답은 클라이언트의 인증에 문제가 있 어서 발생하는 것이 아니다. 만약 클라이언트 인증 자체에 문제가 있다면 401(“Unauthorized”)를 사용한다. REST API에서 애플리케이션 수준의 접근 권한을 적용하고자 할 때 403을 사용한 다. 예를 들어, 클라이언트는 REST API 리소스의 전체가 아니라 일부에 대한 접근 만 허가된 경우가 있다. 클라이언트가 허용된 범위 외의 리소스에 접근하려고 할 때 REST API는 403으로 응답해야 한다.
규칙: 404(“Not Found”)는 요청 URI에 해당하는 리소스가 없을 때 사용해 야 한다 404 오류 상태 코드는 말그대로 클라이언트가 요청한 URI에 해당하는 리소스가 존재하지 않을 때 사용한다.
규칙: 405(“Method Not Allowed”)는 HTTP 메서드가 지원되지 않을 때 사용해야 한다 클라이언트가 허용되지 않은 HTTP 메서드를 사용하려 할 때, API는 405 오류 응 답을 한다. 읽기 전용 리소스는 GET 메서드와 HEAD 메서드만 지원하며, 컨트롤 러 리소스는 PUT 메서드와 DELETE 메서드를 제외한 GET 메서드와 POST 메서 드만 허용할 것이다. 405 응답에는 Allow 헤더가 포함되어야 하며, 그 값으로 리소스가 지원하는 HTTP 메서드를 다음 예와 같이 나타내야 한다.
Allow: GET, POST
규칙: 406(”Not Acceptable”)은 요청된 리소스 미디어 타입을 제공하지 못 할 때 사용해야 한다 406 오류 응답은 클라이언트의 Accept 요청 헤더에 있는 미디어 타입 중 해당하 는 것을 만들지 못할 때 발생한다. 예를 들어, API가 json(application/json) 데 이터 포맷만 지원한다면, xml(application/xml) 포맷 데이터를 요청한 클라이언 트는 406 응답을 받는다.
규칙: 409(“Conflict”)는 리소스 상태에 위반되는 행위를 했을 때 사용해야 한다 409 오류 응답은 클라이언트 요청에 의해 REST API 리소스가 불가능 또는 모순 상태가 될 수 있는 경우에 사용한다. 예를 들어, 클라이언트가 비어 있지 않은 스토 어 리소스를 삭제하라고 요청하면, REST API에서 이 응답 오류를 보낸다.
규칙: 412(“Precondition Failed”)는 조건부 연산을 지원할 때 사용한다 412 오류 응답은 특정한 조건이 만족될 때만 요청이 수행되도록 REST API로 알려 준다. 클라이언트가 요청 헤더에 하나 이상의 전제 조건을 지정할 경우 발생하며, 이러한 조건이 만족되지 않으면 412 응답은 요청을 수행하는 대신에 이 상태 코드 를 보낸다. “규칙: 스토어는 조건부 PUT 요청을 지원해야 한다”에서 설명된 412 상태 코드 사 용의 예를 참고한다.
규칙: 415(“Unsupported Media Type”)은 요청의 페이로드에 있는 미디 어 타입이 처리되지 못했을 때 사용해야 한다 415 오류 응답은 요청 헤더의 Content-Type에 기술한 클라이언트가 제공한 미 디어 타입을 처리하지 못할 때 발생한다. 예를 들어, API가 json(application/ json)으로 포맷된 데이터만 처리할 수 있을 때, 클라이언트가 xml(application/ xml)로 포맷된 데이터로 요청하면 415 응답을 받는다.
규칙: 500(“Internal Server Error”)는 API가 잘못 작동할 때 사용해야 한다 500은 일반적인 REST API 오류 응답이다. 웹 프레임워크는 대부분 예외 사항을 발생시키는 요청 핸들러 코드가 실행될 경우 자동적으로 이 응답 코드를 발생시킨 다. 500 오류는 클라이언트의 잘못으로 발생한 것이 아니기 때문에, 클라이언트가 이 응답을 발생시킨 것과 같은 요청을 다시 시도하면 다른 응답을 받을 수도 있다.
4. 메타데이터 디자인
4.1 HTTP 헤더
HTTP 요청 메시지와 응답 메시지에 포함된 헤더를 통해 여러 형태의 메타데이터 가 전달된다. HTTP는 표준 헤더 집합을 정의하고 그 중 일부는 요청된 리소스 관 련 정보를 제공한다. 그리고 몇몇 헤더는 메시지에 전달되는 표현 관련 정보를 나 타내며, 중간 캐시를 조절하는 지시자 역할을 하기도 한다. 이 장에서는 REST API를 설계하는 입장에서, HTTP 표준 헤더를 다룰 때 도움이 되는 몇 가지 규칙을 제시한다.
규칙: Content-Type을 사용해야 한다 Content-Type 헤더는 요청이나 응답 메시지 바디에 있는 데이터 타입을 나타낸다. 이 헤더의 값은 미디어 타입으로 알려진 특별하게 정의된 문자열이다(‘미디어 타입’ 참고). 클라이언트와 서버는 이 헤더 값을 참조하여 메시지 바디에 있는 바이 트열 처리 방법을 결정한다.
규칙: Content-Length를 사용해야 한다 Content-Length 헤더는 바이트 단위로 바디의 크기를 나타낸다. 응답에서 이 헤 더는 두 가지 이유에서 중요하다. 첫째, 클라이언트는 이 값을 이용하여 바이트의 크기를 올바로 읽었는지 알 수 있다. 둘째, HEAD 요청을 사용하여 데이터를 다운 로드하지 않고도 바디가 얼마나 큰지 알 수 있다.
규칙: Last-Modified는 응답에 사용해야 한다 Last-Modified 헤더는 응답 메시지에만 사용한다. 이 응답 헤더의 값은 타임스탬 프로, 리소스의 표현 상태 값이 바뀐 마지막 시간을 나타낸다. 클라이언트와 캐시 중간자는 이 헤더 값을 이용하여 클라이언트에 저장되어 있는 리소스 상태 표현의 갱신 여부를 결정한다.
규칙: ETag는 응답에 사용해야 한다 ETag 값은 응답 엔티티에 포함된 표현 상태의 특정 버전을 나타내는 일련의 문자 열이다. 이 엔티티는 HTTP 메시지의 페이로드인데, 메세지가 헤더와 바디로 구성 되어 있다. 태그 값은 리소스의 상태에 따라 바뀔 수 있으며 어떤 문자열이라도 될 수 있다. 이 헤더는 항상 GET 메서드 요청에 대한 응답으로 보내져야 한다. 클라이언트는 조건부 If-None-Match 요청 헤더의 값에 따라, ETag 헤더 값을 나 중에 사용할 GET 요청을 위해 저장할 수도 있다. REST API가 엔티티 태그 값이 바뀌지 않았다는 것을 알면, 표현을 다시 보내지 않음으로써 시간과 대역폭을 절약 할 수 있다.
규칙: 스토어는 조건부 PUT 요청을 지원해야 한다 스토어 리소스는 PUT 메서드를 사용하여 리소스를 새로 추가하거나 갱신할 수 있다. 이렇게 두 가지 용도로 사용되기 때문에 REST API는 클라이언트가 사용한 PUT 메서드가 무엇을 위한 요청이었는지를 파악하기 쉽지 않다. HTTP는 헤더를 통해 이러한 모호함을 해결하는 데 필요한 기능을 제공한다. REST API는 클라이 언트의 If-Unmodified-Since와 If-Match 요청 헤더를 통해서 클라이언트의 의 도를 알 수 있다. If-Unmodified-Since 요청 헤더는 API에게, 리소스의 상태 표 현이 헤더 값에 표현된 타임스탬프 시간 이후로 바뀌지 않았을 경우에만 동작하도록 요구한다. If-Match 헤더 값은 엔티티 태그인데, 클라이언트가 받은 이전 응답의 ETag 헤더 값이다. If-Match 헤더는 요청을 조건부로 만드는데, 헤더에 제공된 엔티티 태그 값과 REST API에 의해 저장되거나 계산된 표현 상태의 현재 태그 값 의 정확한 비교에 기초한다.
클라이언트 프로그램인 client#1과 client#2는 REST API의 /objects 스토어 리 소스를 이용하여 데이터를 공유한다. client#1은 URI 경로 /objects/2113으로 식별되는 새로운 데이터를 저장하기 위해 PUT 요청을 보낸다. 이 새로운 URI는 스토어에 저장되어 있지 않은 REST API로서는 처음 보는 데이터다. 따라서 이 요 청을 삽입으로 해석한 REST API는 클라이언트가 제공한 상태 표현에 따라 새로운 리소스를 생성하고 응답으로 201(“Created”)를 보낸다.
시간이 지난 후, client#2는 데이터를 공유하려고 같은 스토리지 URI인 /objects/ 2113을 요청한다. REST API는 URI가 이미 있는 리소스라는 것을 알지만, 클라이 언트의 요청 의도가 생성인지 갱신인지를 알 수 없다. client#1의 저장된 리소스 상태에 client#2의 새로운 데이터를 덮어쓸 것인지 결정하는 충분한 정보를 REST API가 받지 못했기 때문이다. 이 시나리오에서 API는 client#2의 요청에 대한 응 답으로 409(“Conflict”)를 주어야 한다. 덧붙여 오류에 대한 부가 정보를 응답 바 디에 제공해야 한다.
client#2가 저장된 데이터를 갱신하고자 할 때는, If-Matched 헤더를 포함해 서 재요청할 수 있다. 제공된 헤더 값이 현재의 엔티티 태그 값과 같지 않을 경우, REST API는 412(“Precondition Failed”) 오류 응답 코드를 보낸다. 제공된 조 건이 일치한다면, REST API는 저장된 리소스의 상태를 갱신하면서 200(“OK”)나 204(“No Content”) 응답을 줄 수 있다. 응답에 리소스 상태의 갱신된 표현이 응답에 포함되어 있으면, API는 Last-Modified와 ETag 헤더 값을 포함해서 갱신 여 부를 반영한다.
규칙: Location은 새로 생성된 리소스의 URI를 나타내는 데 사용해야 한다 Location 응답 헤더의 값은 클라이언트의 관심 범위에 있는 리소스를 식별하는 URI다. 컬렉션이나 스토어에 성공적으로 리소스를 생성했다는 응답이며, REST API는 Location 헤더를 포함해서 새로 생성된 리소스의 URI를 나타내야 한다. 202(“Accepted”) 응답 안에 있는 이 헤더 값은 비동기 컨트롤러 리소스의 연산 상 태를 클라이언트에 정확히 알려주는 데 사용할 수 있다.
규칙: Cache-Control, Expires, Date 응답 헤더는 캐시 사용을 권장하는 데 사용해야 한다 캐싱은 HTTP의 매우 유용한 기능으로, 클라이언트의 대기 시간을 줄일 수 있고 신뢰성을 향상시키며 API 서버의 부하를 감소시키는 장점이 있다. 캐시는 어디에 나 존재할 수 있다. API의 서버 네트워크나 콘텐츠 전달 네트워크CDN에 있을 수도 있고 클라이언트의 네트워크에도 있을 수 있다.
상태 표현을 제공할 때, Cache-Control 헤더와 초 단위의 max-age 값이 같은 갱신 주기freshness lifetime를 함께 제공해야 한다. 예를 들면 다음과 같다.
Cache-Control: max-age=60, must-revalidate
기존의 HTTP 1.0 캐시를 지원하려면, REST API는 만료일를 나타내는 Expires 헤더를 포함해야 한다. 이 값은 API 표현이 만들어진 시간에 갱신 주기가 더해진 날짜다. 또한 REST API는 시간으로 표시되는 Date 헤더를 포함해서 API의 응답 시간을 나타낸다. 클라이언트는 이 값을 이용해 Expires와 Date 헤더 값의 차이로 서 갱신 주기를 계산할 수 있다. 예를 들면, 다음과 같다.
Date: Tue, 15 Nov 1994 08:12:31 GMT
Expires: Thu, 01 Dec 1994 16:00:00 GMT
규칙: Cache-Control, Expires, Pragma 응답 헤더는 캐시 사용을 중지하 는 데 사용해야 한다 REST API 응답을 캐시에 저장하지 않도록 하려면, Cache-Control 헤더 값을 no-cache나 no-store로 설정하면 된다. 이 경우에 기존 HTTP 1.0 캐시와의 상 호 운영을 고려한다면 “Pragma: no-cache”와 “Expires: 0” 헤더를 추가한다.
규칙: 캐시 기능은 사용해야 한다 no-cache 지시자는 캐시 응답이 제공되는 것을 막는다. REST API는 꼭 필요한 경우가 아니면 캐시를 사용하지 않는다. no-cache 지시자를 추가하는 대신 값이 작은 max-age를 사용하면, 클라이언트는 갱신에 관계없이 짧은 시간 내 캐시에 저장된 복사본을 가져올 수 있다.
규칙: 만기 캐싱 헤더는 200(“OK”) 응답에 사용해야 한다 만기 캐싱 헤더는 성공적인 GET 메서드와 HEAD 메서드의 요청에 대한 응답으로 설정해야 한다. 실제로 POST 메서드는 캐시에 저장 가능하지만, 대부분의 캐시는 이 메서드를 캐시에 저장하기 불가능한 것으로 취급한다. 다른 메서드에 만기 헤더 를 지정해서는 안 된다.
규칙: 만기 캐싱 헤더는 ‘3xx’ 와 ‘4xx’ 응답에 선택적으로 사용될 수 있다 200(“OK”) 응답 코드를 보낸 성공적인 응답에, 추가로 ‘3xx’와 ‘4xx’ 응답에 대한 캐싱 헤더를 추가하는 것을 고려해보자. 이 방법은 ‘네거티브 캐싱’이라 하는데, 리 다이렉트 횟수와 REST API에 오류에 따른 부하를 감소시킨다.
규칙: 커스텀 HTTP 헤더는 HTTP 메서드의 행동을 바꾸는 데 사용해서는 안 된다 커스텀 헤더custom header는 정보 전달이 목적일 때만 선택적으로 사용할 수 있다. 클라이언트와 서버에서 커스텀 헤더에 대해 처리하지 못하는 경우라도, 클라이언 트와 서버 양쪽에서 문제가 없도록 구현해야 한다. 커스텀 HTTP 헤더로 전송하려는 정보가 응답이나 요청을 적절하게 처리하는 데 중요한 정보라면, 그 정보는 요청이나 응답의 바디에 포함하거나 요청 URI에 포함 시켜야 한다. 커스텀 헤더를 이같이 사용하는 것은 피해야 한다.
4.2 미디어 타입
요청이나 응답의 메시지 바디 안에 있는 데이터 형태를 식별하기 위해, Content-Type 헤더 값을 미디어 타입이라고 한다.
미디어 타입의 문법은 다음과 같다.
type “/” subtype( “;” parameter)
type 값으로 application, audio, image, message, model, multipart, text, video 중 하나를 사용할 수 있다. 전형적인 REST API는 application 타입 범주 의 미디어 타입과 종종 결합된다. 계층적인 형태로서 미디어 타입의 서브 타입 값은 type의 부차적인 값이 된다.
type/subtype 다음에 ‘attribute=value’와 같은 형태로 파라미터를 쓸 수 있는 데, 이런 경우에는 세미콜론( ; )으로 분리한다. 미디어 타입의 명세는 파라미터를 필수 값이나 선택 값으로 규정할 수 있다. 파라미터 이름은 대소문자를 구분하지 않으나, 파라미터 값은 보통 대소문자를 구분하고 큰따옴표(“ ”) 안에 쓴다. 파라미 터를 하나 이상 사용할 경우, 순서는 중요하지 않다. 다음 예제는 charset 파라미 터 하나를 가지는 미디어 타입의 Content-Type 헤더 값을 보여준다.
- Content-type: text/html; charset=ISO-8859-4
- Content-type: text/plain; charset=”us-ascii”
등록된 미디어 타입
IANAInternet Assigned Numbers Authority02는 등록된 미디어 타입을 관리하고, 각 타입 의 RFC로 발표된 명세의 링크를 제공하는 기관이다. 누구나 ‘Application for Media Type’에 새로운 미디어 타입을 작성해서 IANA에 제안할 수 있다. 널리 사용하는 등록된 미디어 타입을 아래에서 소개한다.
text/plain
- 특별한 콘텐츠 구조나 마크업이 없는 평문 포맷
text/html
- HTML로 포맷된 콘텐츠
image/jpeg
- JPEG(Joint Photographic Experts) Group에서 표준화한 이미지 압축 방법
application/xml -XML(Extensible Markup Language)로 구조화된 콘텐츠
application/atom+xml
- feed로 알려진 구조적인 데이터를 XML 기반의 리스트로 포맷팅한 Atom을 사 용하는 콘텐츠
application/javascript
- 자바스크립트 프로그래밍 언어로 작성된 소스 코드
application/json
- 구조화된 데이터를 교환하는 프로그램에서 주로 사용되는 텍스트 기반의 JSON 포맷
-
벤더 고유 미디어 타입
벤더 고유 미디어 타입은 서브 타입의 접두어로 ‘vnd’를 사용하며, 특정 업체에서 소유 및 관리하고 있음을 의미한다. 이 미디어 타입은 메시지 콘텐츠의 세부적인 내용을 프로그램에 전달하므로, 프로그램은 메시지 콘텐츠의 의미를 쉽게 이해할 수 있다. 벤더 고유 미디어 타입은 공통 미디어 타입과는 달리 애플리케이션 고유 의 메타데이터를 전달한다. 이는 웹 컴포넌트에 보다 의미 있는 메시지를 전달하는 것이다. 벤더 고유 미디어 타입은 IANA에 등록할 수 있다. 아래에 예로 든 벤더 고유 타입 은 IANA(http://www.iana.org/assignments/media-types)에 등록된 미디어 타입들이다.
- application/vnd.ms-excel
- application/vnd.lotus-notes
- text/vnd.sun.j2me.app-descriptor
4.3 미디어 타입 설계
클라이언트 개발자들은 REST API의 자기-서술적 특성을 활용하는 것이 좋다. 다 시 말해서, 클라이언트 프로그램에는 특정 API의 세부 사항에 대한 하드코딩된 부 분이 가능한 한 적은 것이 좋다. 이러한 목표는 REST API 설계에 큰 영향을 미쳤 는데 불투명한 URI, 리소스 상태를 인지하는 하이퍼미디어 기반의 액션, 서술적인 미디어 타입 등이 그것이다.
규칙: 애플리케이션 고유 미디어 타입을 사용해야 한다 REST API는 HTTP 요청 및 응답 바디를 애플리케이션의 고유한 상호작용의 한 부분으로 취급한다. JSON과 XML을 사용해서 바디의 내용을 정리하지만, 작성된 언어 문법을 단순히 해석하는 것 이상으로 특별한 처리를 요청하는 의미가 있다.
규칙: 리소스의 표현이 여러 가지 가능할 경우 미디어 타입 협상을 지원해야 한다 클라이언트에서 원하는 미디어 타입을 Accept 헤더에 추가하여 특정 포맷과 스키 마를 협상할 수 있게 해야 한다.
규칙: query 변수를 사용한 미디어 타입 선택을 지원할 수 있다 단순 링크와 쉬운 디버깅이 가능하도록 REST API는 Accept HTTP 요청 헤더 값 과 동일한 쿼리 파라미터 accept를 통해 미디어 타입을 선택하도록 할 수 있다.
규칙: 리소스의 표현이 여러 가지 가능할 경우 미디어 타입 협상을 지원해야 한다 클라이언트에서 원하는 미디어 타입을 Accept 헤더에 추가하여 특정 포맷과 스키 마를 협상할 수 있게 해야 한다. 예를 들면 다음과 같다.
4.4 정리
5. 표현 디자인
5.1 메시지 바디 포맷
REST API는 요청 메시지가 지정한 리소스의 상태를 응답 메시지의 바디를 이용해 서 전달하는데, 주로 텍스트 기반의 포맷을 이용하여 리소스 상태를 표현한다. 현 재 가장 많이 사용하는 텍스트 포맷은 XML과 JSON이다.
규칙: 리소스의 표현이 여러 가지 가능할 경우 미디어 타입 협상을 지원해야 한다 클라이언트에서 원하는 미디어 타입을 Accept 헤더에 추가하여 특정 포맷과 스키 마를 협상할 수 있게 해야 한다. 예를 들면 다음과 같다.
규칙: JSON은 문법에 잘 맞아야 한다 JSON 객체는 키-값 쌍으로 구성되며, 순서와 무관한 집합이다. JSON 객체 문법 은 키 값을 문자열로 정의하며, 이 문자열은 항상 큰따옴표 안에 넣는다. 이 규칙은 자바스크립트의 오브젝트 리터럴에 사용되는 규칙에 비해 엄격하지 않아서, 종종 잘못된 JSON을 만들어낸다.
- JSON은 숫자 값을 지원하기 때문에 숫자는 문자열로 처리하지 않아도 된다.
- JSON은 시간과 날짜 값은 지원하지 않기 때문에 문자열로 표현해야 한다. JSON에서 이름을 붙일 때는 소문자를 섞어서 사용해야 하고, 특수 문자는 피해 야 한다.
규칙: XML과 다른 표현 형식은 선택적으로 지원할 수 있다 앞서 언급한 “규칙: JSON 리소스 표현을 지원해야 한다”에서 JSON은 클라이언트 용으로 표현 포맷을 지원해야 한다고 설명했다. REST API는 XML, HTML 등의 리소스를 표현하기 위해 선택적으로 대체 포맷을 사용하여 다른 언어를 지원할 수 있다. 4장 “규칙: 미디어 타입 협상은 리소스의 여러 가지 표현이 가능할 경우 지원 해야 한다”에서 설명했듯이, 미디어 타입 협상 과정을 통해 클라이언트에서는 사 용하고자 하는 표현 방법을 나타내야 한다.
규칙: 추가 봉투는 없어야 한다 REST API는 HTTP가 제공한 메시지 봉투01를 이용해야 한다. 다시 말해서, 바디는 추가적인 래퍼02 없이 리소스 상태의 표현을 포함해야 한다.
5.2 하이퍼미디어 표현
HTML 기반의 링크와 폼처럼, REST API도 하이퍼미디어를 채택하여 표현한다. REST API 응답 메시지 바디에 포함된 링크는 리소스의 연관성과 액션을 나타낸다. 리소스의 상태 표현에서 다른 필드 값을 가지고, 링크는 리소스 간 관련성을 전 달하며, 클라이언트에 상황에 맞는 리소스 관련 액션 메뉴를 제공한다.
5.3 미디어 타입 표현
4장 ‘미디어 타입 디자인’에서 소개한 application/wrml 미디어 타입은 format 과 schema라는 파라미터 두 개를 가진다. 이 파라미터는 URI 값을 가지는데, 서 로 다른 도큐먼트를 참조한다. 그리고 각각은 Content-Type과 Accept HTTP 헤 더에 있는 메타데이터의 의미를 강화할 수 있다. 이 부분의 규칙들은 두 도큐먼트 타입(format과 schema)의 표현을 기술한다.
5.4 오류 표현
규칙: 오류는 일관성 있게 표현한다 이 규칙은 REST API의 오류 응답 메시지에 포함될 수 있는 오류에 대해 설명한다. 미디어 타입은 다음처럼 정의하여 완성도를 높이지만, 응답의 Content-Type 헤 더에서는 사용되지 않는다
규칙: 오류 응답은 일관성 있게 표현한다 요청을 처리할 때 하나 이상의 오류가 발생하면 메시지 바디 안에 오류 응답 표현 을 반환한다. 이 방법을 사용할 때 응답의 상태 코드는 ‘4xx’ 또는 ‘5xx’ 중 하나여 야 한다.
규칙: 일반적인 오류 상황에서는 일관성 있는 오류 타입을 사용해야 한다 API의 다양성으로 말미암아 일반적 오류 타입은 중요해진다. 오류 타입은 한 번 정 의되면 서비스를 제공하는 오류 스키마 문서를 통해 모든 API에 공유되어야 한다. 4장 ‘미디어 타입 스키마 디자인’에서 논의하였듯이, 스키마 확장을 통해 기본 타 입에 추가 항목을 넣어서 새로운 오류 타입을 정의한다.
5.5 정리
6. 클라이언트 영역
6.1 개요
웹 페이지에 포함된 스크립트, 휴대용 게임, 서버 팜에서 실행되는 비즈니 스 애플리케이션 등 어떤 컴퓨터 프로그램이라도 REST API의 클라이언트가 될 수 있다. REST API는 클라이언트 프로그램이 필요로 하는 것이 무엇이든 간에 그 필 요를 맞춰주기 위해 설계된다.
6.2 버전을 정의하는 방법
규칙: 새로운 개념을 도입하려면 새로운 URI를 사용해야 한다 리소스는 마치 어떤 사물에 대한 개념과 같은, 일종의 의미론적인 모델이다. 리소 스의 표현 형식과 상태는 시간이 지나면서 변하지만, 식별자는 다른 URI로는 대치 할 수 없는 ‘개념’을 일관되게 나타내야 한다. 그뿐만 아니라 리소스 URI를 표현하 는 문자 하나하나는 리소스의 정체성을 형성한다. 그러므로 REST API 버전 또는 해당 버전의 리소스에 속하는 어떤 것이라도 일반적인 URI에 표현해서는 안 된다.
규칙: 표현 형태의 버전을 관리하기 위해서는 스키마를 사용해야 한다 4장 ‘미디어 타입 스키마 버저닝’에서 설명했듯이, REST API 리소스 표현의 형태 버전은 이를 관리하는 스키마 문서를 통해서 처리해야 한다. 클라이언트는 미디어 타입 협상을 통해 그들의 필요를 잘 맞춰주는 표현 폼에 묶인다.
새로운 스키마 버전에 항목과 링크를 추가하는 것은 하위 호환성에 영향을 주지 않 고 REST API에 새로운 특징을 소개하는 좋은 방법이다.
규칙: 엔티티 태그는 표현 상태 버전을 관리하기 위해 사용한다 4장의 “규칙: ETag는 응답에 사용해야 한다”에서 ETag HTTP 헤더 사용을 다루 었듯이, ETag는 리소스 표현 상태의 버전을 전달한다. 개별적인 리소스와 연관된 엔티티 태그값은 REST API의 가장 작은 단위의 버저닝 시스템이다.
6.3 보안
REST API에서는 특정 클라이언트나 사용자와 관련된 리소스를 외부로 드러내는 경우가 많다. 예를 들어, REST API의 도큐먼트에 개인 정보가 포함되거나 REST API의 컨트롤러에서 제한된 사용자만 수행하도록 의도한 처리 방법이 외부로 드 러날 수 있다. 이 부분의 규칙들은 REST API의 민감한 리소스 보호에 대해 다 룬다.
규칙: 리소스 보호를 위해 OAuth를 사용할 수 있다 OAuth(Open Authorization)는 모든 클라이언트에 대해 일관된 접근을 사용해서 안전한 권한을 제공하는 공개 표준이다. 다른 사이트에 사용자 id나 비밀번호와 같은 개인 정보를 알려주지 않고, 저장된 사진이나 주소록과 같은 개인 리소스를 공유할 수 있도록 해주는 것으로 잘 알려져 있다.
OAuth는 어떤 조직이 프로토콜 스펙을 소유하거나 조정할 수 없는 IETF 산하 OAuth 워킹 그룹이 관리하는 공개 표준이다. 워킹 그룹은 구글, 마이크로소프트, 페이스북, 트위터, 야후 및 여러 인터넷 선도 기업으로 구성되어 있다.
규칙: 리소스 보호를 위해 API 관리 솔루션을 사용할 수 있다 API 리버스 프록시(reverse proxy)는 비교적 새로운 타입의 네트워크 기반 중간자로 서, REST API의 자원을 보호하는 데 사용할 수 있다. Apigee와 Mashery 같은 API 관리 솔루션 제공 업체는 고품질의 REST API 제공이나 사용과 관련된 여러 복잡한 문제를 해결할 수 있는 리버스 프록시 기반의 서비스를 제공한다. 이들 업 체의 솔루션은 OAuth 및 다른 독창적인 보안 프로토콜을 지원한다.
6.4 응답표현조합
REST API 클라이언트의 요구 사항은 시간이 지남에 따라 변하게 된다. 새로운 기 능이 추가되면 클라이언트는 지원하는 REST API에 새로운 리소스를 요청할 수 있다. 클라이언트의 변화는 때때로 급격하지 않아서, 약간 다른 방식으로 모델링된 API의 기존 리소스를 요청할 수 있다. 대부분의 REST API는 여러 종류의 클라이 언트를 지원하는데, 이들 클라이언트의 요구 사항을 대부분 수용해야 한다.
REST API는 클라이언트를 배려하기 위한 방법으로 응답 표현의 조합을 제어할 수 있는 측정 방법을 제공한다. 이 부분에서 설명하는 규칙은 REST API에서 리소스 모델을 일관성 있게 유지하면서 클라이언트의 요청에 맞춰 응답을 조절할 수 있는 방법을 제공한다.
규칙: URI의 쿼리 부분은 부분 응답을 지원할 때 사용해야 한다 5장에서 설명한 것처럼, 리소스의 현재 상태는 필드와 링크의 집합으로 표현된다. REST API는 클라이언트가 요청한 데이터보다 더 많은 정보를 포함하는 리소스 상태 모델을 제공해야 할 경우가 있다. 대역폭을 절약하거나 전체적인 상호작용을 가 능한 한 빠르게 하기 위해, REST API 클라이언트는 쿼리 부분의 fields 파라미터 를 사용하여 응답 데이터를 줄일 수 있다.
규칙: URI의 쿼리 부분은 부분 응답을 지원할 때 사용해야 한다 5장에서 설명한 것처럼, 리소스의 현재 상태는 필드와 링크의 집합으로 표현된다. REST API는 클라이언트가 요청한 데이터보다 더 많은 정보를 포함하는 리소스 상 태 모델을 제공해야 할 경우가 있다. 대역폭을 절약하거나 전체적인 상호작용을 가 능한 한 빠르게 하기 위해, REST API 클라이언트는 쿼리 부분의 fields 파라미터 를 사용하여 응답 데이터를 줄일 수 있다.
규칙: URI 쿼리 부분은 연결된 리소스를 포함할 때 사용해야 한다 ‘웹 구조에 대한 주석’에서 팀 버너스리는 두 종류의 링크에 대해 지적했다.
기본적으로 HTML에서 웹에 있는 것들을 서로 연결하는 방법은 세 가지다. 앵커(HTML 의 ‘A’ 요소)를 사용하는 하이퍼텍스트 링크, 도큐먼트 안의 특정한 소스 앵커가 없는 일반적 링크(‘HTML link’ 요소), 오브젝트나 이미지(IMG, OBJECT) 등이 그것이다. 두 도큐먼트를 이동할 때 사용자에게 보이는 ‘A’와 ‘LINK’를 ‘일반 링크normal link’라 부르자. 도큐먼트와 포 함된 이미지, 오브젝트, 서브다큐먼트 사이의 링크를 ‘포함 링크embedding link’라고 부르자.
REST API는 각 클라이언트 요청에 대해 연결된 리소스를 일반 링크로 둘 것과 어 떤 것을 포함하게 할 것인지를 조정하는 것을 허용해야 한다. 이 요청-시간 조합 접 근 방법은 REST API에서 잘 정의된 리소스 모델을 일관성 있게 제공함으로써, 각 클라이언트에 개별 유스 케이스에 대응할 수 있는 권한을 준다.
6.5 하이퍼미디어 처리
5장에서 두 종류의 하이퍼미디어 구조인 링크와 링크 관계를 소개했다. 이들 구조 는 클라이언트에서 일관된 알고리즘을 사용하여 처리하기 쉽도록 디자인된 것이다. 클라이언트의 하이퍼미디어 처리 루틴은 관계 이름을 사용하는 링크를 찾는 것으로 시작한다. 그 다음에는 적절한 HTTP 요청 메서드를 사용하여 링크와 상호작용하기 위해, 클라이언트 코드는 링크 관계 도큐먼트 리소 스의 method 필드를 조사한다. 링크 상호작용이 요청 메시지 바디에 제출된 콘 텐츠를 허용하거나 요청하면, 링크 관계 도큐먼트는 requestTypes 필드를 통해 가능한 미디어 타입 옵션을 나타낼 수 있다.
6.6 자바스크립트 클라이언트
오늘날 어디에나 사용되면서 점점 영향력이 커지고 있는 웹 브라우저는 클라이언 트 애플리케이션을 위한 플랫폼으로 자연스럽게 받아들여지고 있다. 이 부분에서 제공하는 규칙들은 웹 브라우저의 동일 사이트 정책(same origin policy) 에 따라, 제한된 공간에서 실행되는 자바스크립트 기반 클라이언트를 지원하기 위한 REST API에 적용된다. 동일 사이트 정책은 동일 도메인 원칙이 라고도 하며, 웹 브라우저 기반의 자바스크립트 클라이언트에서 그 코드의 출처가 아닌 다른 웹 서버의 리소스에 접근하는 것을 제한한다. 웹 브라우저에서도 사용자 데이터의 유출을 막기 위해서 이러한 동일 사이트 정책을 사용한다. 리소스의 출처 06는 URI의 스킴, 호스트, 포트까지로 정의된다.