그런 REST API로 괜찮은가

8376 단어 RESTAPIAPI

이 글은 DEVIEW2017 '그런 REST API로 괜찮은가' 강연을 보고 정리한 내용입니다. 링크는 아래에 남기겠습니다.

1. REST의 탄생 배경

1991년에 WEB이 나오면서, 인터넷에서 정보를 공유하기 위해 HTML, URI, HTTP라는 것이 탄생했다. HTTP 개발 과정에 참여한 로이필딩은 "How do I improve HTTP without breaking the web?" 이라는 고민 끝에 REST라는 것을 발표했다.

2. 어떻게 유명해졌나?

인터넷상에 API라는 개념이 도입되면서, 가장 처음 주류가 된 것은 1998년 Microsoft에서 발표한 SOAP이라는 프로토콜이다.

2000년에 Salesforce에서 SOAP을 사용하여 API를 하나 공개했다.

그로부터 4년 후 flickr에서도 API를 발표했는데, SOAP과 REST를 활용하였다.
SOAP 버전
REST 버전

사람들은 이것을 보고 REST는 단순하고 규칙이 적고 쉽다고 느끼고, 그 후로 REST의 인기는 급상승한다.

3. REST API가 아니다?

2016년에 Microsoft에서 REST API Guideline을 발표하였다(그 내용은 흔히 우리가 생각하는 REST API와 같다..). 그러나 REST를 만든 로이필딩은 그것을 보고 그것은 REST가 아니라고 하였다.

4. REST API란?

REST 아키텍처 스타일을 따르는 API 라고 한마디로 정의할 수 있다.
이 때, 아키텍처 스타일이란 제약조건의 집합이며, 집합에 속한 모든 제약조건을 따라야 아키텍처 스타일을 준수하였다고 할 수 있다.

REST는 아래의 6가지 아키텍처 스타일을 가지고 있다.

  1. Client - Server
  2. stateless
  3. cache
  4. layered system
  5. uniform interface
  6. code on demand (optional)

사실 1~4번까지는 http API만 잘 활용해도 지킬 수 있는 문제다. 문제는 흔히 REST API라고 말하는 대부분의 API들이 Uniform interface를 지키지 않는다는 것이다.

Uniform interface는 아래와 같은 4가지의 제약 조건을 가지고 있다.

  1. identification of resouces
  2. manipulation of resource through representations
  3. self-descriptive messages
  4. HATEOAS

3, 4번 제약조건을 거의 모든 REST라 일컫는 API들이 지키지 못하고 있다.

5. Self-descriptive message

그렇다면 self-descriptive message란 무엇일까?
아래의 예제를 통해 알아보도록 하자.

GET / HTTP/1.1

은 self-descriptive 하지 못하다. 어디서 받아오는 것인지 알 수 없기 때문이다.

GET / HTTP/1.1
HOST: www.google.com

은 self-descriptive 하다.
이처럼 message만 보고도 해석이 가능한 것을 self-descriptive라 한다.
다른 예제를 살펴보자.

HTTP/1.1 200 OK

[{ "op": "remove", "path": "/a/b/c"}]

는 self-descriptive 하지 못하다.

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

[{ "op": "remove", "path": "/a/b/c"}]

위의 예시보다는 조금 더 descriptive하지만 이것도 self-descriptive하지 않다. op, path가 뜻하는 것을 알 수 없기 때문이다.

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

[{ "op": "remove", "path": "/a/b/c"}]

이제 이것은 self-descriptive하다. (json-patch가 일종의 media-type 명세같은 거라고 생각)
명세가 명시되어 있기때문에 message를 본 사람은 저 메세지를 파악할 수 있기 때문이다.

6. HATEAOS

HATEAOS란 '애플리케이션의 상태는 Hyperlink를 이용해 전이되어야한다'

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

<html>
<head></head>
<body><a href="/test">test</a></body>
</html>

하이퍼링크를 통해 애플리케이션 상태가 전이될 수 있으므로 HATEAOS를 만족한다.

7. Why Uniform Interface

이렇게 까다로운 Self-Descriptive, HATEAOS 제약조건을 지켜서 Uniform Interface 아키텍쳐 스타일을 사용하려는 이유는 무엇일까?

독립적 진화 가 가능하기 때문이다.
Self-descriptive하면, 서버나 클라가 변경되더라도 메세지만으로 해석이 가능하기 때문에 문제가 없다.
HATEAOS하면, 동적으로 링크가 변경될 수 있으므로, 서버에서 변화가 일어나도 클라이언트는 수정할 필요가 없다.

결국 서버 클라이언트가 독립적으로 진화하고, 서버의 기능이 변경되어도 클라이언트를 업데이트할 필요가 없다.
REST를 만들게 된 계기 "How do I improve HTTP without breaking the web?"과 일맥상통하다.

8. REST가 잘 지켜진 것이 있나?

바로 웹이다.

웹 페이지를 변경했다고 웹 브라우저를 업데이트 할 필요는 없다.
웹 브라우저를 업데이트했다고 웹 페이지를 변경할 필요도 없다.
HTTP 명세가 변경되어도 웹은 잘 동작한다.
HTML 명세가 변경되어도 웹은 잘 동작한다.

9. 왜 일반 API는 REST가 잘 안될까..?

REST를 잘 지킨 사례인 웹과 비교해보자
HTTP API와 흔한 웹 페이지의 가장 큰 차이는 Media Type이다(JSON v.s HTML)

HTML은 HTML 자체에 명세가 있고 hyperlink를 표현할 수 있는 태그도 있다.

GET /todos HTTP/1.1
HOST: example.org

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

<html>
<body>
    <a href="https://~~~~>todo1</a>
    <a href="https://~~~~>todo2</a>
</html>

위와 같은 메세지가 있으면,

  1. 응답 메세지의 content-type을 보고 media type이 text/html임을 확인
  2. http 명세를 보면 media type은 IANA에 등록되어있다고 적혀있음
  3. 명세를 찾을 수 있고, 그 명세에는 태그를 해석하는 방법이 다 적혀있음
    그러므로 self-descriptive하고, a 태그를 통해 다음 상태로 전이될 수 있으므로 HATEOAS를 만족한다.

그렇다면 흔한 http API 응답 코드를 보자

GET /todos HTTP/1.1
Host: example.org

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

[
	{"id":1, "title": "todo1"},
	{"id":2, "title": "todo2"},
]

똑같은 방식으로, JSON이라는 명세를 찾아서 파싱을 할 수는 있으나, 그 안에 든 "id"가 무엇이고, "title"이 무엇을 의미하는지 알 방법이 없고, 링크도 없어서 self-descriptive와 HATEOAS를 둘다 만족하지 못한다.

REST스럽게 고쳐보자!

먼저 Self-descriptive를 만족시켜보자.

첫번째 방법은 Media type을 지정하는 것이다. 미디어 타입을 정의해서 IANA에 등록하고, Content-type에 명시하는 것이다.

두번째 방법은 http Link Header를 이용하는 것이다. 구체적으로, "id"가 뭐고 "title"이 뭔지에 대한 명세를 작성한 후,

HTTP ~~~
Content-type: ~~~
Link: <명세의 링크>; rel="profile"

이런 형식으로 profile을 기재해 주는 것이다.

물론 꼭 명세를 작성할 필요는 없다. 만약 사내에서 사용하는 경우, 명세가 없어도 사내의 모든 사람들이 이해할 수만 있다면 그것은 self-descriptive라고 간주할 수 있다.

HATEAOS를 만족시켜보자.

그냥 data에다가 LINK를 써주는 것도 하나의 방법이다.
link를 표현할 수 있는 http Link Header나 Location Header를 이용할 수도 있다.
즉, data나 header를 통해 link를 나타내주면 된다.

10. 이렇게 어려운 REST...꼭 써야해?

시스템 전체를 통제할 수 있다고 생각하거나, 진화에 관심이 없다면, REST에 대해 따지느라 시간을 낭비하지 마라.

REST는 웹처럼 서버와 클라이언트를 관리하는 주체가 서로 독립된 어플리케이션 환경을 중점으로 구상되었기에, 현대에 서비스와는 잘 맞지 않을 수도 있다.

외부로 공개되는 API라면 REST 아키텍쳐 스타일을 지킨다면, self-descriptive한 특성때문에 API를 이해하기도 쉽고, 의존성이 생기지 않으므로 적합하다고 생각한다.

어떤 기술이든 그렇지만, 목적에 따라 잘 사용하면 될 것 같다.

출처 https://tv.naver.com/v/2292653#comment_focus
좋은 강의 감사드립니다:)

좋은 웹페이지 즐겨찾기