이전 포스팅에서는 REST란 무엇인지를 살펴보았습니다. REST는 총 6개의 제약조건을 가지고 있었죠.
그런데 균일한 인터페이스 제약조건의 경우 만족하기가 매우 어렵다고 했습니다. 이번 포스팅에서는 왜 그렇게 어려운지, 어떤 개념을 내포하고 있는지 살펴보도록 하겠습니다.
균일한 인터페이스
균일한 인터페이스 제약조건의 경우 하위 4개의 제약조건으로 나뉘어집니다. 그러니까, 총 4개의 제약조건을 모두 만족해야 균일한 인터페이스 제약조건을 만족한다! 라고 할 수가 있는 것이죠.
각각의 제약조건은 다음과 같습니다.
- 자원의 식별(identification of resources)
- 표현을 통한 자원의 조작(manipulation of resources through representations)
- 자기서술적인 메세지(self-descriptive messages)
- HATEOAS(Hypermedia As The Engine Of Application State)
균일한 인터페이스 제약조건이 만족하기 어렵다고 일컬어지는 이유는 3번, 4번 제약조건 때문인데요, 이 두 가지 제약조건에 대해서는 조금 더 상세히 다루도록 하겠습니다.
그럼 이제 각각의 제약조건에 대해 하나하나 알아보도록 해보죠.
자원의 식별(identification of resources)
자원의 식별은 클라이언트와 서버 사이에서 고유하게 *자원을 식별할 수 있어야 한다는 제약조건입니다.
REST에서는 정보의 추상화를 자원(resource)이라고 합니다. 어떤 정보든 이름을 지을 수 있다면 자원이라고 볼 수 있습니다. 그것이 추상적인 정보가 되었든, 실제로 존재하는 정보가 되었든 말이죠.
이 제약조건을 만족하는 장바구니 웹 어플리케이션을 사용한다고 가정해봅시다. 그렇다면 우리는 GET /products/1 이나, PUT /products/1이나 같은 자원에 접근할 것이라는 보장을 얻을 수 있습니다. 조금 더 쉽게 생각해서, 이 제약조건을 만족하려면 URI를 통해 자원을 식별할 수 있어야 함을 의미합니다.
표현을 통한 자원의 조작(manipulation of resources through representations)
균일한 인터페이스의 두번째 제약조건은 표현을 통한 자원의 조작입니다. 여기서 표현(representation)이라는 용어가 처음 등장했네요. REST의 R에 해당하는 부분도 바로 여기서 말하는 representation입니다.
표현(representation)이란, 데이터 + 메타데이터를 의미합니다. HTTP에서는 데이터에 해당하는 부분이 HTTP body에, 메타데이터에 해당하는 부분이 HTTP header에 해당합니다.
그리고 이런 표현을 통해 자원을 조작해야 한다는 것이 이 제약조건이 주장하는 바입니다.
자기서술적인 메세지(self-descriptive messages)
균일한 인터페이스의 3번째 제약조건은 자기서술적인 메세지입니다. 앞서 말씀드렸듯이 이 제약조건은 만족하기가 어렵습니다. 도대체 무슨 제약조건이길래 그럴까요?
자기서술적인 메세지는 자원의 표현이 메세지를 처리하기에 충분한 정보를 제공해야 한다는 제약조건입니다. 즉, 메세지 스스로 본인의 의도를 설명할 수 있어야 한다, 자기서술적이어야 한다는 것이죠. 잘 와닿지 않으리라 예상합니다. 예시를 통해 이해해보죠.
위 표현은 우리가 개발을 하다보면 자주 맞닥뜨리는 구조입니다. 가장 일반적인 형태의 JSON 메세지라고 생각할 수 있을 것 같습니다. 자, 이제 생각해봅시다. 위 표현은 자기서술적인가요? 메세지만으로 의도를 표현할 수 있나요?
답은 아니오입니다. 위 표현은 자기서술적이지 않습니다. 왜일까요?
'name' 이라는 key가 상품의 이름이라는 의미를 가진다는 것을 확신할 수 있나요? 만약 API 설계자가 'name'이라는 key를 상품의 이름이 아니라 가게의 이름이라고 정의했다면 어떨까요.
마찬가지로 price라는 key도 가격을 의미하는게 아닐지도 모릅니다. 즉, 우리는 위 메세지에서 name, price에 대한 어떠한 정보도 확신을 내릴 수 없습니다. 그저 유추하는거죠.
그렇다면 어떤게 자기서술적인 메세지일까요? 아래와 같은 메세지가 자기서술적인 메세지입니다.
위 메세지는 헤더를 통해 HTML 데이터임을 명시하고 있고, body를 통해 실제 HTML 데이터를 전달하고 있습니다. 즉, 메세지와 메세지를 해석하기 위한 방법(명세)를 같이 제공하고 있습니다. 이 경우 메세지 자체가 스스로를 설명합니다. <html> 태그에 대한 정보, <a> 태그에 대한 정보를 모르겠다면 HTML 명세를 찾아가면 됩니다. 메세지만 보아도 이게 무슨 내용인지 알 수 있다는 것입니다.
여기서 의문이 듭니다. 우리가 개발을 할 때 일반적으로 사용하는 JSON 메세지는 명세가 존재하지 않는데... 자기서술적일 수 없는 것이 아닐까요?
자기서술적이기 위해서는 메세지를 해석하기 위한 방법을 함께 제공해야 하는데요, 대표적으로 두 가지 방법이 존재합니다.
- IANA라는 기관에서 커스텀 미디어 타입 등록하기
- 메세지 헤더에 명세가 포함된 링크 등록하기
두 가지 방법을 어떻게 수행하는지에 대해 지금 단계에서는 자세히 알 필요는 없다고 생각합니다. 다만 '자기서술적이기 위해서는 메세지를 해석하기 위한 방법을 함께 제공해야 한다'만 기억하면 될 것 같습니다.
HATEOAS(Hypermedia As The Engine Of Application State)
마지막 제약조건은 바로 HATEOAS입니다. 이는 클라이언트가 서버와 상호작용하면서 하이퍼미디어를 통해 동적으로 모든 리소스에 접근할 수 있어야 한다는 제약조건입니다.
설명이 참 어려운데요, 원활한 이해를 위해 예를 들어 설명해보려고 합니다.
우리가 터미널을 통해 구글에 들어갔다고 가정해봅시다. 구글에서는 다양한 서비스를 제공하죠. 지메일, 유튜브, 검색, 계정 정보, 설정 등... 이런 여러 기능을 터미널에서도 사용할 수 있으려면 어떻게 해야할까요? 사용자가 구글에 접속하면, 구글 서버는 다음과 같은 메세지를 응답으로 보내야 할 것입니다.
{
"지메일" : "/gmail",
"유튜브" : "/youtube",
"검색" : "/search",
"계정정보" : "/profile",
"설정" : "setting"
}
이렇게 구글 서버가 응답을 보낸다면, 사용자는 터미널에서도 원하는 서비스에 접근할 수 있게 됩니다. 유튜브에 접근하고 싶다면 /youtube에 GET 요청을 보내면 되겠죠.
이게 바로 HATEOAS의 핵심 개념입니다. 방금 클라이언트가 직접 상태를 변경하지 않았나요? 서버는 단순히 접근할 수 있는 서비스 URI들을 명시해주고, 클라이언트가 직접 상태를 변경한 것입니다.
이처럼 서버는 클라이언트에게 접근할 수 있는 모든 리소스들을 제공하고, 클라이언트가 자신의 상태를 선택하게 하는게 바로 HATEOAS입니다. 우리가 자원을 생성했을 때, Location 헤더에 생성된 자원의 URI를 넣어주는 것도 HATEOAS를 만족하는 한 예시라고 볼 수 있겠네요. 클라이언트는 해당 URI를 이용해 상태를 변경할 수 있으니까요. 만약 생성된 자원을 조회하고 싶다면, Location 헤더의 값을 이용해 GET 요청을 보내면 됩니다.
이런 정의를 생각해보면, 위와 같은 구조는 HATEOAS를 만족하지 않습니다. 클라이언트가 해당 메세지를 통해 상태를 변경할 수가 없으니까요.
반면 위와 같은 구조는 HATEOAS를 만족합니다. 링크를 통해 클라이언트가 자신의 상태를 변경할 수 있으니까요.
이처럼 HATEOAS는 서버가 '너 지금 상태에서는 여기에 접근할 수 있어!' 라고 모든 선택지를 제공해주고 클라이언트가 선택하게 하는 것을 의미합니다. 만약 어떤 API가 HATEOAS를 만족한다면, 클라이언트는 시작점이 되는 하나의 URI만 알아도 모든 자원에 접근 할 수 있어야 합니다. 즉, 'www.google.com' 이라는 URI를 통해 지메일이든, 유튜브든, 설정이든 모든 기능을 사용할 수 있어야 한다는 것이죠.
이렇게 REST의 마지막 제약조건인 HATEOAS까지 알아봤습니다.
마치며
REST의 등장 배경부터 6가지 제약조건들까지 모두 알아보았습니다. 균일한 인터페이스 제약조건의 경우 4가지 하위 제약조건으로 분류되었고, 자기서술적인 메세지와 HATEOAS가 가장 만족시키기가 어렵다고 했습니다.
그렇다면 시중에 REST API라고 불리는 것들은 다 무엇일까요? 자기서술적이지도 않고 HATEOAS를 만족하지도 않는데 말이죠.
엄연히 따지면 REST API, RESTful API로 불리려면 위에서 설명한 모든 제약조건을 만족해야 합니다. 하지만 현실적으로 생각해봅시다. 위 제약조건을 모두 만족시키는 API를 만들 수 있을까요? 어찌저찌 만들 수 있다고 쳐도, 시간 투자 대비 그만큼의 효율이 나올까요?
그래서 많은 사람들, 기업들이 모든 제약조건을 만족하지 않고 일부분만 만족해도 REST API, RESTful API라고 부릅니다. 즉, 지금은 REST API와 HTTP API가 거의 같은 개념으로 사용되고 있습니다.
그럼 만족시키기 어려웠던 제약조건들, 자기서술적인 메세지, HATEOAS를 만족해야 하는 시점은 언제일까요? 다시 REST의 등장 배경으로 돌아가봅시다. REST가 왜 등장했나요? 클라이언트 - 서버의 결합도를 줄이고 자원 관리를 용이하기 위함이었습니다.
반대로 이야기하면, 클라이언트 서버와 결합도가 너무 높고 자원 관리가 어렵다면 모든 제약조건을 지키는, 완전히 RESTful한 API를 만들 시점입니다. 하지만 그런 경우가 드무니까 시중에서는 도통 보이지 않는 것이죠. 그렇지만 AWS S3 같은 Open API는 HATEOAS를 만족하기도 합니다.
추가적으로 한가지 더 덧붙이자면, REST는 추상적인 개념입니다. 로이 필딩의 REST는 'HTTP 메소드는 무엇을 사용해야 하고...' 이런 주장을 하지 않습니다. 시중에 나와있는 RESTful API Guideline은 REST를 각각의 입맛에 맞게 해석한 결과물들입니다. REST는 단지 6가지 제약조건을 주장할 뿐입니다. 그러니 혼동의 여지가 없었으면 좋겠습니다.
감사합니다.
참고문헌
'우테코 5기' 카테고리의 다른 글
[레벨 2 미션] 쇼핑 주문 협업 미션 학습 기록(1) (0) | 2023.06.20 |
---|---|
JDBC, SQL Mapper, ORM (0) | 2023.06.15 |
REST 기본 개념 총정리 2편 - REST의 6가지 제약조건 소개 (2) | 2023.06.11 |
REST 기본 개념 총정리 1편 - REST의 등장 배경 (4) | 2023.06.10 |
[레벨 2 미션] 지하철 미션 학습 기록(2) (0) | 2023.06.08 |