진정한 rest란?

진정한 REST란?

REST란?

Representational State Transfer의 줄임말로 Roy T. Fielding에 의해 만들어진 개념이다!

이는 분산 하이퍼 미디어 시스템을(웹) 위한 아키텍쳐 스타일이고 제약조건의 집합이라고 볼 수 있어!!

즉 rest를 만족하기 위한 조건들이 존재하고 이를 만족하였을 때 rest 구조를 따른다라고 이야기할 수 있는거지

각 제약조건들의 핵심은 결국 interoperability를 만족하자! 라고 생각할 수 있어. 즉 상호운영성을 가지게 하자라는거지.

조금 더 깊이 이해하기위해 발생하게 된 역사를 한번 보자!



REST는 왜 등장하게 된 것일까?

1991년에 WEB이 등장했지. 그리고 이에 맞게 정보를 주고받는 규약들이 만들어졌지.

결과적으로 모든 정보들을 하이퍼텍스트로 연결을 시켰어.

그리고 URI라는 식별자를 통해 HTTP를 이용하여 HTML을 주고받는거지!!

Rest의 탄생의 시초는 Roy T. Fielding의 Http Object Model에서 나왔어. 그리고 이는 당시에 존재하던 web architecture sytle에서 조금 더 좋은 구조를 만들기 위해 제약조건들을 추가해 나갔고 그렇게해서 만들어진게 REST라는 개념이 된거야.




REST의 제약조건

그럼 제약조건들에 대해 알아보자



Client - Server

첫번째로 추가된 조건은 client-server architectural style이야. 해당 조건의 핵심은 관심사의 분리야. User Interface의 문제를 Data Storage 문제와 분리를 시켜 여러 플랫폼에서 User Interface 즉 사용자 인터페이스의 이식성을 개선한거지. 그리고 분리를 해줌으로써 서버의 구성요소가 간단해지며 그에 따른 확장성을 얻기 쉬워진거야.

이렇게 분리를 해줌으로써 독립적인 발전을 가능하게 만들어 주었어.



Stateless

다음으로 추가된 조건은 Client-Server의 Interaction 즉 상호작용에 추가된거야! 커뮤니케이션은 Stateless 해야한다!

이말은 Client에서 서버로가는 각 request 들은 그 request안에 필요한 모든 정보를 포함하고 있어야지, 이 정보들이 Server에 저장된 어떠한 context에 의해 도움을 받아선 안된다는거야. 쉽게 설명하면 Server는 각 Client의 상태, 정보등을 저장하여 요청을 처리하는데 이점을 받으면 안된다는거지.

이렇게 해줌으로써 Visibility, Reliability, Scalability 측면에서 이점을 얻을 수 있ㄷ어.

  1. Visibility - Monitoring System이 request 전체의 특성을 파악하기 위해서 단일 request를 넘어서 볼일이 없어. 즉 request 하나만 보아도 request 마다 상태를 server에서 저장하는 것이 아니니 알 수 있다는거지.
  2. Reliability - 부분적인 failures 로부터 복구작업을 쉽게 해줘.
  3. Scalability - server 측에서 요청 사이에 state를 저장할 필요가 없으니 resource에 대한 free 즉 해제가 쉬워지고 요청사이에 state를 저장할 필요가 없다는 이점은 구현을 간단화 시켜주게 되는거야.



Cache

network의 efficiency 즉 효율성을 높이기 위해 cache constraint를 추가!

이는 response에 담겨있는 data에 cacheable의 여부를 담고 cacheable의 경우 client에서는 동일한 request에 대해 data를 재사용할 권한을 갖게하는거지!

user가 느끼는 performance 측면에서 분명 큰 효과가 있으나 trade-off 관계인 것이 cache의 data가 server 측 실 data와 일치한지에 대한 reliability 측면에서는 또 떨어뜨리는 효과가 발생할 수 있어. (물론 그런 reliability를 처리하는 방안까지 현재 conditional get 처럼 나와있기는 하지)



Uniform Interface

uniform interface 는 구성요소간의 균일한 인터페이스를 가진다는 것이 주된 내용이야. 이를통해 전체 시스템 아키텍쳐가 단순화되는 효과를 볼 수 있으며 상호작용의 가시성 또한 좋아지지!

그리고 이를통해 제공하는 서비스와는 분리된 상태로 implementation을 발전시킬 수 있어. 한마디로 독립적인 발전을 가능하게 해준다는거지.

이러한 Uniform Interface를 만족시키기 위해서는 component들의 behavior에 대해 여러 제한들이 더 요구되어져

  • identification of resources - resource가 uri로 식별되면 된다
  • manipulation of resources through representations - http message에 resource에 대한 동작의 표현을 담아 전송을 하여 동작하게 끔 한다
  • self-descriptive messages
  • hypermedia as the engine of application state (HATEOAS)



Layered System

internet-scale의 요구사항들에 대한 동작, 즉 규모가 큰 구조에서 성능 향상을 위해 Layered System Constraints를 추가했어. 각 layer는 자신들의 knowledge 즉 담당하는 정도가 제한되어져있고 여기서 오는 이점이 전체적인 시스템의 복잡도를 제한시키고 독립성을 높여줘.

그리고 이를 통해 legacy service들에 대해 캡슐화가 가능해지고 legacy client로 부터 새로운 서비스를 보호할 수 있데.

그리고 intermediary 즉, 중개자 역할을 하는 layer 에서 로드밸런싱을 수행해 scalability를 높일 수도 있으며 서비스에서 자주 사용되지 않는 기능들에 대해서도 해당 layer에 넣어 component들을 단순화 시키는 등의 이점을 볼 수 있지.



Code On Demand (optional)

서버에서 코드를 클라이언트로 보내서 실행할 수 있어야한다. (Javascript)




현재의 REST API

REST API는 말그대로 REST 구조를 따라가는 api야. 현재 REST를 지키지 않으면서 REST API라고 이야기하는 경우가 많데. Roy T. Fiedling 아저씨가 이를 싫어한다고 하시네.. ㅠㅠ

우선 HTTP만 만족시켜도 위의 대부분 조건들을 잘 지킬 수 있으나 Uniform Interface 조건을 지키기가 어려워.

Uniform Interface의 제약사항들 중에서도 self-descriptive-messages 와 hateoas…

  • self-descriptive messages - 메시지가 스스로를 설명해야해. 메시지를 봤을 때 그 내용만으로 전체 해석이 가능해야해
  • hypermedia as the engine of application state(hateoas) - 어플리케이션의 상태는 항상 하이퍼링크를 이용해 전이되어야해. (html의 a태그, json의 Link헤더 등..)

위의 두가지에 대해 조금 더 설명을 하자면 self-descriptive는 확장 가능한 커뮤니케이션을 제공해줘. 서버나 클라이언트가 변경되더라도 오고가는 메시지는 언제나 self-descriptive하기에 언제나 해석이 가능해.

hateoas는 어플리케이션 상태 전이의 late binding을 가능하게 해줘. 즉 어디서 어디로 전이가 가능한지 미리 결정되지 않는거야. 어떤 상태로 전이가 완료되고 나서야 그 다음 전이될 수 있는 상태가 결정되는거지. 결과적으로 링크는 동적으로 변경될 수 있게 되는거야!



그럼 위의 Uniform Interface를 꼭 지켜야하는가??

rest를 지키려한다면 지켜주는게 맞아!!

uniform interface는 독립적인진화를 위해 필요해. 서버와 클라이언트는 독립적으로 진화하며 서버의 기능이 변경되더라도 클라이언트를 업데이트할 필요가 없지.

interoperability 즉 상호운용성을 굉장히 중요하게 생각하기에 이전에 잘못 지었던 오타들이나 415 상태코드 등 잘못된 부분들을 고치는 것을 포기하는거야. 그만큼 이런 상호적인 측면을 중요하게 생각해. 어떤 변경이 있을 때 전체적인 상호작용에 문제가 생기는 것을 굉장히 싫어해.

이러한 이유들로 REST라면 Uniform Interface를 지켜주는 것이 맞아.



현재는 왜 지켜지기 어려운 것이며 지키기 위해서는 어떻게 해야할까?


web vs api

우선 Rest를 잘 적용했다는 web과 api의 차이점을 보자

HTTP API
Protocol HTTP HTTP
커뮤니케이션 사람-기계 기계-기계
Media Type HTML JSON

위에서 볼 수 있듯이 가장 큰 차이는 media type 즉 데이터 포맷이야. 웹피이지의 경우 사람과의 상호작용으로 html을 통해 정보를 보여주지만 http api의 경우 기계와 기계간의 상호작용이고 그렇기에 기계가 알아들을 수 있는 json을 써!

그럼 이 둘은 무엇이 다를까?

HTML JSON
Hyperlink 가능(a tag) 정의되어 있지 않다
Self-Descriptive 가능(HTML 명세) 불완전 해

html은 hyperlink(a태그), self-descriptive(html 명세)가 돼!!
json은 hyperlink 정의되어있지 않고, self-descriptive가 불완전해.(어떻게 파싱할지는 정해져있으나 그안에 값의 의미는 알 수 없어). 그래서 우리가 맨날 api 문서를 만드는 것이지


HTML VS JSON

  • HTML
    1. HTML은 Self-Descriptive를 만족해. 응답 메시지의 content-type을 보고 media type이 text/html임을 확인할 수 있지
    2. HTTP 명세에 media type은 INNA에 등록되어 있다 하므로, INNA에서 text/html에 대한 설명을 찾을 수 있어.
    3. 이렇게 타고타고 들어가면 결국 모든 태그의 설명들을 하고있는 명세를 볼 수 있거 해당 응답을 해석하는 것이 가능하게 되는거야!!
    4. hateoas 측면에서도 a태그로 표현된 링크를 통해 다음 상태로 전이할 수 있기에 만족해
1
2
3
4
5
6
7
8
9
10
11
12
GET /todos HTTP/1.1
Host: example.org

HTTP/1.1 200 OK
Content-Type: text/html

<html>
<body>
<a href="https://todos/1">회사 가기</a>
<a href="https://todos/2">집에 가기</a>
</body>
</html>
  • JSON
    1. 명세를 통해 json을 파싱할 수는 있겠지만 결국 아래 데이터에서 id가 뭔지 title이 뭔지 그 의미를 알 수는 없어. 그렇기에 self-descriptive하지 못한거지
    2. hateoas 또한 불만족해
1
2
3
4
5
6
7
8
9
10
GET /todos HTTP/1.1
Host: example.org

HTTP/1.1 200 OK
Content-Type: application/json

[
{"id": 1, "title": "회사 가기"},
{"id": 2, "title": "집에 가기"}
]

그럼 json을 이용하여 rest api를 만들고자 한다면

  • media type을 등록하는 방법이 있어. INNA에 직접 media type과 그 명세를 작성하여 등록하는 것이지.
  • 혹은 json 데이터의 의미를 정의한 명세를 작성하고 link 헤더에 profile relation으로 해당 명세를 링크해. 그럼 메시지를 보는 사람은 명세를 찾아갈 수 있으니 문서의 의미를 온전히 해석 가능하게 되는거지
  • hateoas를 만족하기 위해서는 그 다음 이동해야하는 하이퍼링크를 data에 넣어서 표현해버리면 돼!! 혹은 헤더를 활용할 수도 있고!!!







https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm

https://www.youtube.com/watch?v=RP_f5dMoHFc

https://velog.io/@codemcd/RESTREpresentational-State-Transfer-hgk2muj4l2