본문 바로가기

Data Layter

그런 Rest Api로 괜찮은가?

Rest란

- REpresentational State Transfer

- a way of providing interoperability(상호 운용성)

  between computer systems on the Internet.

 

역사

WEB(1991) 

Q: 어떻게 인터넷에서 정보를 공유할 것인가?

A: 정보들을 하이퍼 텍스트로 연결한다.

표현방식 : HTML

식별자 : URI

전송방법 : HTTP

 

HTTP/1.0(1994-1996)

Roy T. Fielding: "How do I improve HTTP without breaking the Web?"

 

해결책 : HTTP Object Model --> Rest Api

 

API

XML-RPC(1998) -> SOAP

by Microsoft 

 

SOAP를 사용한 API

Salesforce API(2000.2)

 

flickr API(2004. 8)

SOAP

- 복잡하다

- 규칙많다

- 어렵다

REST

- 단순하다

- 규칙적다

- 쉽다

 

CMIS(2008)

- CMS를 위한 표준

- EMC, IBM, Microsofit 등이 함께 작업

- REST 바인딩 지원

 

Roy T. fielding: "No REST in CMIS"

 

Microsoft REST API Guidelines (2016)
- uri는 https://{serviceRoot}/{collection}/{id} 형식이어야 한다.

- GET, PUT, DELETE, POST, HEAD, PATCH, OPTIONS를 지원해야한다.

- API 버저닝은 Major.minor로 하고 uri에 버전 정보를 포함시킨다.
- ...

 

Roy T. fielding : "REST APIs must be hypertext-driven"

"REST API를 위한 최고의 버저닝 전략은 버저닝 안 하는 것"

 

뭐가 문제인 걸까?

REST API

REST 아키텍쳐 스타일을 따르는 API

 

REST

분산 하이퍼미디어 시스템(예: 웹)을 위한 아키텍처 스타일

 

아키텍처 스타일

제약조건들의 집합

 

REST를 구성하는 스타일

- client-server

- stateless

- cache

- uniform interface

  - 구성 제약 조건

    - identification of resources : 리소스가 uri로 식별되면 된다.

    - manipulation of resources through representations : 리소스를 CRUD를 메시지에 표현해야 한다.

    - self-descriptive messages : 메시지는 스스로를 설명해야 한다.

    - hypermedia as the engine of application state(HATEOAS) : 애플리케이션의 상태는 Hyperlink를 통해서 전이되어야 한다.

  - 필요한 이유

    - 독립적 진화

      - 서버와 클라이언트가 각각 독립적으로 진화한다.

      - 서버의 기능이 변경되어도 클라이언트를 업데이트 할 필요가 없다.

      - REST를 만들게 된 계기 : "How do I improve HTTP without breaking the Web."

- layered system

- code-on-demand(optional) : 서버에서 코드를 클라이언트에 보내서 실행할 수 있어야 한다(javascript)

 

실제 적용 케이스

- 웹 페이지를 변경했다고 웹 브라우저를 업데이트 할 필요는 없다.

- 웹 브라우저를 업데이트 했다고 웹 페이지를 변경할 필요도 없다.

- HTTP 명세가 변경되어도 웹은 잘 동작한다.

- HTML 명세가 변경되어도 웹은 잘 동작한다.

 

- W3C Working groups : HTML

- IETF Working group : HTTP

- 웹 브라우저 개발자들

- 웹 서버 개발자들

 

HTML5 초안에서 권고안 6년, HTTP/1.1 기능추가없이 명세 개정판만 7년

상호운용성(interoperability)에 대한 집착

- Referer 오타지만 안 고침

- charset 잘못 지은 이름이지만 안 고침 : encoding이라는 이름으로 지어야하는데 안고침

- HTTP 상태 코드 416 포기함 (I'm a teapot)

- HTTP/0.9 아직도 지원함(크롬, 파이어폭스)

 

모바일

- 서버가 가능이 변경되면 클라이언트가 지원해주는데 한계가 있어서 업데이트를 한다.

 

REST가 웹의 독립적 진화에 도움을 주었나

- HTTP에 지속적으로 영향을 줌

- Host 헤더 추가

- 길이 제한을 다루는 방법이 명시(414 URI Too Long 등)

- URI에서 리소스의 정의가 추상적으로 변경됨 : "식별하고자 하는 무언가"

- 기타 HTTP와 URI에 많은 영향을 줌

- HTTP/1.1 명세 최신판에서 REST에 대한 언급이 들어감

- Reminder: Roy T. Fielding이 HTTP와 URI 명세의 저자 중 한명입니다.

 

그럼 REST는 성공했는가?

- REST는 웹의 독립적 진화를 위해 만들어졌다.

- 웹은 독립적으로 진화하고 있다

 

그런데 REST API는?

- REST API는 REST 아키텍처 스타일을 따라야 한다.

- 오늘날 스스로 REST API라고 하는 API들은 대부분이 REST 아키텍처 스타일을 따르지 않는다.

 

REST API도 저 제약조건들을 다 지켜야 하는가?

- 하이퍼 텍스트를 포함한 self-descriptive한 메세지의 uniform interface를 통해 리소스에 접근하는 API

 

원격 API가 꼭 REST API여야 하는건가?

- 시스템 전체를 통제할 수 있다고 생각하거나,  → 내가 다만들거나, 클라이언트가 하위부서인 경우

  진화에 관심이 없다면, → 오랜시간을 가지고 진화하는 시스템을 설계하는 경우가 아니면

  REST에 대해 따지느라 시간을 낭비하지 마라

 

그럼 이제 어떻게 할까?

1. REST API를 구현하고 REST API라고 부른다.

2. REST API 구현을 포기하고 HTTP API라고 부른다.

3. REST API가 아니지만 REST API라고 부른다.(현재 상태)

 

Roy T. fielding : "제발 제약조건을 따르던지 아니면 다른 단어를 써라"

 

일단 왜 API는 REST가 잘 안되나?

일반적인 웹과 비교

  흔한 웹 페이지 HTTP API
Protocol HTTP HTTP
커뮤니케이션 사람 - 기계 기계 - 기계
Media Type HTML JSON

HTTP API의 경우 미디어 타입이 다르다.

 

HTTP vs JSON

  HTML JSON
Hyperlink 됨(a 태그 등) 정의되어 있지 않음
Self-descriptive 됨(HTML 명세) 불완전

문법 해석은 가능하지만, 의미를 해석하려면 별도의 문서(API 문서 등) 필요하다.

 

Self-descriptive와 HATEOAS가 독립적 진화에 어떻게 도움이 될까요?

Self-descriptive

확장 가능한 커뮤니케이션

서버나 클라이언트가 변경되더라도 오고가는 메시지는 언제나 self-descriptive하므로 언제나 해석이 가능하다.

 

HATEOAS

애플리케이션 상태 전이의 late binding

어디서 어디로 전이가 가능한지 미리 결정되지 않는다. 어떤 상태로 전이가 완료되고 나서야 그 다음 전이될 수 있는 상태가 결정된다.

즉, 링크는 동적으로 변경될 수 있다.

 

그럼 REST API로 고쳐보자

Self-descriptive

 

방법 1 : Media type

GET /todos HTTP/1.1
Host: example.org

HTTP/1.1 200 OK
Content-Type: application/vnd.todos+json

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

1. 미디어 타입을 하나 정의한다.

2. 미디어 타입 문서를 작성한다. 이 문서에 "id"가 뭐고 "title"이 뭔지 의미를 정의한다.

3. IANA에 미디어 타입을 등록한다. 이 때 만든 문서를 미디어 타입의 명세로 등록한다.

4. 이제 이 메시지를 보는 사람은 명세를 찾아갈 수 있으므로 이 메시지의 의미를 온전히 해석할 수 있다.

 

단점 : 매번 media type을 정의해야 한다.

 

방법 2 : Profile

GET /todos HTTP/1.1
Host: example.org

HTTP/1.1 200 OK
Content-Type: application/vnd.todos+json
Link: <https:///example.org/doc/todos>; rel="profile"
[
  {"id":1, "title":"회사 가기"},
  {"id":2, "title":"집에 가기"}
]

1. "id"가 뭐고 "title"이 뭔지 의미를 정의한 명세를 작성한다.

2. Link 헤더에 profile relation으로 해당 명세를 링크한다.

3. 이제 메시지를 보는 사람은 명세를 찾아갈 수 있으므로 이 문서의 의미를 온전히 해석할 수 있다.

 

단점

1. 클라이언트가 Link 헤더(RFC 5988)와 Profile(RFC 6906)을 이해해야 한다.

2. Content negotiation을 할 수 없다.

 

HATEOAS

 

방법 1 : data

 

data에 다양한 방법으로 하이퍼링크를 표현한다.

GET /todos HTTP/1.1
Host: example.org

HTTP/1.1 200 OK
Content-Type: application/vnd.todos+json
[
  {
    "Link":"https://example.org/todos/1", 
    "title":"회사 가기"
  },
  {
    "Link":"https://example.org/todos/2", 
    "title":"집에 가기"
  },
]

 

단점

링크를 표현하는 방법을 직접 정의해야 한다.

GET /todos HTTP/1.1
Host: example.org

HTTP/1.1 200 OK
Content-Type: application/vnd.todos+json
[
  "links":{
    "todo":"https://example.org/todos/{id}"
  },
  "data":[{
    "id":1,
    "title":"회사 가기"
  },
  {
    "id":2,
    "title":"집에 가기"
  }]
]

JSON으로 하이퍼링크를 표현하는 방법을 정의한 명세들을 활용한다.

 - JSON API

 - HAL

 - UBER

 - Siren

 - Collection+json

 - ...

GET /todos HTTP/1.1
Host: example.org

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json
[
  "data":[{
    "type":"todo",
    "id":1,
    "attributes":{"title":"회사 가기"},
    "links":{"self":"http://example.com/todos/1"}
  },
  {
    "type":"todo",
    "id":2,
    "attributes":{"title":"집에 가기"},
    "links":{"self":"http://example.com/todos/2"}
  }]
]

단점

기존 API들을 많이 고쳐야 한다.(침투적)

 

방법 2 : HTTP 헤더로

Link, Location 등의 헤더로 링크를 표현한다.

GET /todos HTTP/1.1
Content-Type: application/json
{
  "title":"점심 약속"
}

HTTP/1.1 204 No Content
Location: /todos/1
Link: </todos/>; rel="collection"

몇가지 궁금한 점

Hyperlink는 반드시 uri여야 하는건 아닌가?

종류
uri https://toss.im/users/eungjun
uri reference(absolute) /users/eungjun
uri reference(relative) eungjun
uri template /users/{username}

Media type 등록은 필수인가?

No

 

Media type을 IANA에 등록하기

- 누구나 쉽게 사용할 수 있게 된다.

- 이름 충돌을 피할 수 있다.

- 등록이 별로 어렵지 않다(고 주장함)

 

정리

오늘날 대부분의 "REST API"는 사실 REST를 따르지 않고 있다.

REST의 제약조건 중에서 특히 Self-descriptive와 HATEOAS를 잘 만족하지 못한다.

REST는 긴 시간에 걸쳐(수십년) 진화하는 웹 애플리케이션을 위한 것이다.

REST를 따를 것인지는 API를 설계하는 이들이 스스로 판단하여 결정해야 한다.

REST를 따르겠다면, Self-descriptive와 HATEOAS를 만족시켜야 한다.

  - self-descriptive는 custom media type이나 profile link relation 등으로 만족시킬 수 있다.

  - HATEOAS는 HTTP 헤더나 본문에 링크를 담아 만족시킬 수 있다.

REST를 따르지 않겠다면, "REST를 만족하지 않는 REST API"를 뭐라고 부를지 결정해야 할 것이다.

  - HTTP API라고 부를 수도 있고

  - 그냥 이대로 REST API라고 부를수도 있다(roy가 싫어함)

 

출저 : https://www.youtube.com/watch?reload=9&v=RP_f5dMoHFc