REST API의 정의 - 미정리

김동헌·2024년 1월 19일
0

CS

목록 보기
5/9
post-thumbnail

🙄 포스팅 계기

프로젝트 진행 중에 REST API를 작성하는 과정에서 제가 구현한 것들이 REST API 형식에서 벗어나 보인다. 라고 피드백이 있었습니다.

피드백 과정에서 REST API를 어떻게 작성하는 것이 좋을까요?라고 질문을 드렸고, 돌아온 답변과 제가 찾아본 자료들을 보니 너무 추상적인 느낌이 들었습니다.

그래서 REST API를 알기 위해서 REST가 뭔지에 대한 제 확실한 정의가 있어야 더 나은 개발자가 될 수 있다고 판단해 포스팅이 시작하게 되었습니다.


REST의 정의

위키백과의 REST(REpresentational State Transfer)의 정의

  • REST a way of providing interoperability between computer systems on the internet
  • 컴퓨터 시스템과의 상호 운용성을 제공합니다.

이러한 정의만으로는 이해하기 어려웠습니다.

🙋‍♂️접근법을 조금 달리, 기원과 배경을 이해하는 것이 전체 개념을 파악하는 데 도움이 될 것 같습니다!

그렇다면 REST는 어떤 계기로 나오게 되었을까요 ?


시작

WEB(1991)

기원

  • Q) 어떻게 인터넷에서 정보를 공유할까 ?
  • A) 정보들을 하이퍼텍스트로 연결하자 !
    • 표현 방식: HTML
      • HTML이란 형식으로 정보를 표현하고
    • 식별자: URI
      • 정보들에 대한 식별자로 URI를 이용하고
    • 전송 방법: HTTP
      • 그 정보들을 전송하는 방법으로 HTTP 프로토콜을 이용한다.

HTTP/1.0 (1994-1996)

Roy T.Fielding,

  • "How do I improve HTTP without breaking the Web?"

Roy Fielding은 94년 HTTP/1.0 프로토콜 작업을 참여했습니다.

당시 HTTP 1.0 명세가 나오기 전에 이미 HTTP는 WEB에 전송 프로토콜로 이용되고 있었고, 당시 웹은 급속도로 성장하는 단계였습니다.

이 시점에서 Roy Fielding은 HTTP를 적립하고 명세의 기능을 더하고, 기존의 기능을 고치는 단계에 들어섭니다.

하지만 당시에 문제가 하나 있었었습니다.
HTTP 프로토콜을 고치게 되면 당연히 기존의 WEB과 호환성 문제를 피할 수 없다는 문제였죠.

Roy Fielding은 생각합니다.
어떻게하면 WEB을 망가뜨리지 않고 HTTP를 진보할 수 있을까 ?

HTTP Object Model(1994)

Roy Fielding은 이러한 생각을 바탕으로 HTTP Object Model을 만들었습니다. 이 HTTP Object Model은 4년 이후 Microsoft Research에서 REST라는 이름으로 공개가 됩니다.

Roy T. Fielding, Microsoft Research

  • "Representational State Transfer: An Architectural Style for Distributed Hypermedia Intercation"
  • 분산형 하이퍼미디어 인터커네이션을 위한 아키텍처 스타일

Roy Fielding은 Microsoft Research 발표 2년 뒤, 박사 논문으로 REST를 발표하게 되고 이 논문이 오늘날 알고 있는 REST를 정의하는 논문입니다.

Roy T. Fielding,
- "Architectural Styles and the Design of Network-based Software Architectures"
- 아키텍처 스타일과 네트워크 기반 소프트웨어 아키텍처 설계


API

REST의 등장 배경을 알게 되었으니 API도 알아보겠습니다 !

XML-RPC

1998년 Microsoft가 원격으로 다른 시스템의 메소드를 호출하는 XML-RPC라는 프로토콜을 만들고, 나중에 SOAP로 이름으로 바뀌게 됩니다.


Salesforce API

이후 Salesforce라는 회사에서 API를 공개하는데 거의 최초의 API라고 볼 수 있다.

Salesforce API(2002.2) SOAP

사진의 API는 단순히 어떤 ID로 Object 하나를 가져오는 API의 요청 메시지인데,, 비효율적이고 복잡했습니다.
이러한 이유로 인기가 없었습니다🤦‍♂️


flicker API

4년 후 flicker는 API(2004.8)를 여러가지 형태(SOAP, REST)로 만들었습니다.

SOAP 형식

REST 형식

두 개의 API 차이가 어떤가요 ?
REST 형식은 거의 같은 일을 SOAP 형식보다 코드가 훨씬 간결했습니다.

즉, SOAP는 복잡하고, 규칙이 많으며 어려웠지만
REST는 단순하고, 규칙이 적으며 쉬웠습니다.

이러한 이유로 두 형식의 API 사용량이 크게 차이가 나게 됩니다.

  • 2006년, AWS가 자사 API의 사용량의 85%가 REST API라고 발표
  • 2010년, Salesforce.com 조차도 REST API를 추가하게 되었습니다.

이렇게 WEB의 API가 REST로 정착이 되나 싶었는데 CMIS(2008)이 나왔습니다.


CMIS

  • Content Management Interoperability Services의 약자
  • CMS(Content Management System)를 위한 표준으로 콘텐츠 관리 시스템
  • EMC, IBM, Microsoft 등이 함께 작업
  • REST 바인딩 지원

CMIS의 REST 바인딩 지원을 본 Roy Fielding"No REST in CMIS"라고 말했습니다. 다른사람들에게는 충분히 REST로 보였지만 정작 REST를 만든 Roy Fielding은 REST가 아니라고 한거죠.


Microsoft REST API Guidelines

  • uri는 https://{serviceRoot}/{collection}/{id} 형식이어야 한다.
  • GET, PUT, DELETE, POST, HEAD, PATCH, OPTIONS를 지원해야 한다.
  • API 버저닝은 Major.minor로 하고 uri에 버전 정보를 포함시킨다.
  • 등등

하지만 이것 역시 Roy Fielding은 REST API가 아닌 HTTP API라고 해야한다. 라고 했습니다.

또한 Roy Fielding은 아래와 같이 말하였습니다.

  • "REST APIs must be hypertext-driven"
  • "REST API"를 위한 최고의 버저닝 전략은 버저닝을 안 하는 것

사람들이 알고 있던 REST API와 REST를 만든 Roy Fielding이 말하는 REST가 너무 많이 다른 것 같습니다.

뭐가 문제인 걸까요 ?

REST API를 한번 자세히 알아봐야겠습니다 !


REST API

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

그렇다면 REST는 ?

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

아키텍쳐 스타일 ?

  • REST는 아키텍처 스타일이고, 아키텍처 스타일은 제약조건의 집합
  • 이 제약조건을 모두 지켜야 REST를 따른다고 한다.

REST를 구성하는 스타일

REST는 아키텍쳐 스타일이면서 동시에 하이브리드 아키텍쳐 스타일이라고 말합니다.

Why?
아키텍쳐 스타일과 동시에 아키텍쳐 스타일의 집합

구성 스타일
1. client-server
2. stateless
3. cache
4. uniform interface
5. layered system
6. code-on-demand (optional)
ㄴ> 서버에서 코드를 클라이언트로 보내서 실행할 수 있어야 한다. (Java Script)

대체로 오늘날 REST API는 위 구성 스타일을 잘 지키고 있습니다.
Why? HTTP만 잘 따라도 대체로 uniform interface를 제외한 구성은 잘 지킬 수 있습니다.

uniform interface 스타일의 구성 요소를 확인해볼까요 ?


uniform interface 제약조건

Uniform interface의 제약조건은 4가지가 있는데 identification of resourcesmanipulation of resources through representation의 제약 조건은 잘 지켜지고 있습니다.

  1. identification of resources
    • 리소스가 URI로 식별되면 됩니다.
  2. manipulation of resources through representations
    • representations 전송을 통해서 resource를 조작해야한다.
    • 리소스를 만들거나 업데이트 하거나, 삭제하거나 할 때 HTTP 메시지에 표현을 담아 전송을하고 발송하면 됩니다.

아래의 2가지는 거의 모든 REST API는 아래 두가지는 지키지 못하고 있습니다.

1. self-descriptive messages

  • 메시지는 스스로를 설명해야 한다.

  • GET / HTTP/1.1 이 HTTP 요청 메시지는 뭔가 빠져있어서 self-descriptive 하지 못합니다.

    • 목적지 Host: www.example.org가 빠져있음.
  • HTTP/1.1 200 OK [ { "op": "remove", "path": "/a/b/c"} ]

    • 어떤 문법으로 작성된건지 모르기에 해석을 할 수 없습니다.. 그러므로 self-descriptive를 하기 위해서는 Content 헤더가 들어가야합니다. Content-Type: application/json 추가
      • 그래도... oppath의 의미를 모릅니다. 즉 정보가 부족하기에 미디어 타입을 정의해줘야 합니다.
        Content-Type: application/json-patch+json
        즉, patch+json라는 형식임을 명시함으로서 jsonPatch라는 명세를 찾아가서 확인하고 해석하면 이 메시지의 의미를 이해할 수 있다.

self-descriptive를 만족하는 코드

HTTP/1.1 200 OK
Content-Type: application/json-patch+json
[ { "op": "remove", "path": "/a/b/c" } ]

self-descriptive messages는 메시지를 봤을 때 메시지의 내용으로 온전히 해석이 가능해야 합니다.

하지만 오늘날의 코드는 미디어 타입에 그냥 json이라고만 되어있지 이걸 어떻게 해석해야 하는가는 알기 어렵기 때문에 self-descriptive message의 제약조건은 지켜지지 않습니다.


2. HATEOAS(hypermedia as the engine of application state)

  • 애플리케이션의 상태는 Hyperlink를 이용해 전이되어야 합니다.

애플리케이션 상태의 전이

  • 상태 전이란? 글 목록 보기, 글 쓰기, 글 저장, 생성된 글 보기, 목록 얻기 등의 과정들로 하이퍼링크를 통해 상태가 바뀌게 되는 것 입니다.

HATEOAS Sample Code

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

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

HTML의 경우 HATEOAS를 만족하는데 a태그를 통해서 하이퍼링크가 나와있고, 이 하이퍼링크를 통해 그 다음 상태로 전이가 가능하기 때문이다.

HTTP/1.1 200 OK
Content-Type: application/json
Link:
	</articles/1>; rel="previouse",
	</articles/3>; rel="next";
{
  "title": "The second article",
  "contents": "bbb...bbb..."
}

json도 링크 헤더를 이용해 HATEOAS를 만족할 수 있다.

왜 Uniform Interface가 필요할까 ?

독립적 진화

  1. 서버와 클라이언트가 각각 독립적으로 진화한다.
  2. 서버의 기능이 변경되어도 클라이언트를 업데이트할 필요가 없다.
  3. REST를 만들게 된 계기: "How do I improve HTTP without breaking the Web"

독립적 진화란 ?

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

서버가 기능이 바뀌고, 기능이 새로 추가되고 기존 API가 변경되고, API가 삭제되고 URI가 바뀌고의 변경이 있을 때 Client는 업데이트 할 필요가 없다. 이것이 독립적인 진화 -> REST를 만들게 된 계기 "How do I improve HTTP without breaking the Web" --> 로이필딩이 HTTP 1.0을 만들 때 고민했던 것

즉, REST가 목적하는 바가 독립적 진화이다.

독립적 진화를 달성하기 위해서는 Uniform Interface가 반드시 만족이 돼야한다.


그렇다면 REST는 지켜지고 있는가 ?
--> 사례로 WEB이다. (Safari, chrome 등...)

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

단 (모바일로 접속 시) UI 페이지가 깨질 수 있지만 동작은 한다.

어떻게 가능할까 ? --> 엄청난...노력

  • HTML5 첫 초안에서 권고안 나오는데까지 6년이 걸림
  • HTTP/1.1 명세 개정판 작업하는데 7년
    • 기능은 추가되지 않고 문서를 다듬는 시간만 7년이 소요
      • 하위호환성을 깨트리면 안되기 때문에.

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

  • Referer 오타지만 수정하지 않음
  • charset 잘못 지은 이름이지만 수정하지 않음 -> 인코딩이라고 이름을 지어야 했는데 당시에 인코딩의 개념을 잘 알지 못해서 charset으로 지음 -> 이름을 고치면 상호운용성이 꺠짐
  • HTTP 상태 코드 416 포기함 (I'm a teapot) -> HTTP 상태 코드가 하나씩 추가되면서 415까지 왔음 -> 이후 416 상태 코드를 추가하다가 문제가 생김 -> 옛날 만우절 때 만든 이상한 스펙 HTCP(HTTP가 아닌 HTCPC)가 416 상태 코드를 갖고 있음.
    -> 수많은 서버 구현(node, golang)이 HTTP 상태 코드로 구현을 해버림(HTTP가 아님에도 불구하고) -> 처음에는 HTTP 의장이 프로젝트마다 돌아다니며 416 지원을 제거해야한다는 이슈를 올렸는데 맹비난을 받고 포기, 416은 HTTP 상태 코드에서 영구 결변을 만드는 드래프트가 나왔고, HTTP 상태코드는 415다음 417로 간다. WHY? 이미 그런 구현체가 세상에 존재하고 그런 잘못 만들어진 구현체들과의 상호운용성 역시 지켜주어야 하기 떄문에 안그러면 웹이 깨짐.
  • HTTP/0.9 아직도 지원함 (크롬, 파이어폭스)
    --> 크롬에서 HTTP/0.9를 빼지 않냐는 의견이 나옴 -> 결국 빼지 못함.(94~96)년에 나온 기술이지만 지원을 포기하지 못하고 있음. -> 한번 뺴봤더니 몇몇 일부 프록시에서 오동작하는 것이 발견되어서 포기함. -> why? 웹을 깨트릴 수 없으니까.
    --> 고치는 순간 WEB이 깨지므로 고칠 수 없다.

이런 노력이 없다면 웹도 아래처럼 될 수 있다

웹 서버가 브라우저 호환성을 고려하지않고 구현했을 때 발생할 수 있는 현상

만약 HTML명세나 hTTP 명세를 만드는 사람들이 상호운용성을 위한 노력을 하지 않았다면 위의 현상을 자주 발견할 수 있을 것이다.


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

  • HTTP에 지속적으로 영향을 줌
  • Host 헤더 추가
  • 길이 제한을 다루는 방법이 명시 (414 URI Too Long 등)
  • URI에서 리소스의 정의가 추상적으로 변경됨: "식별하고자 하는 무언가"
    • 과거에는 문서의 위치를 정의했으나 추상적으로 변경
  • 기타 HTTP와 URI에 많은 영향을 줌
  • HTTP/1.1 명세 최신판에서 REST에 대한 언급이 들어감.
    • HTTP1.1에 Representation에 대한 개념이 정의되어 있는데 이 개념은 REST에서 온 것이다. REST의 박사학위 논문에 대한 링크가 되어 있다.

이렇게 된 것은 HTTP나 URI를 만드는 사람들이 REST에 영향을 많이 받은 것도 있곘지만 그사람이 그사람이다.
로이필딩이 REST를 만들며 HTTP와 URI 명세의 저자 중 한명이기 때문에

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


그럼 REST는 성공했는가 ?

  • REST는 웹의 독립적 진화를 위해 만들어졌다.
  • 웹은 독립적으로 진화하고 있다.
    성공 !

그런데 REST API는 ?

  • REST API는 REST Architecture Style을 따라야한다.
  • 오늘날 스스로 REST API라고 하는 API들은 대부분이 REST 아키텍쳐 스타일을 따르지 않는다.

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

An API that provides network-based access to resources via a uniform interface of self-descriptive messages containing hypertext to indicate potential state transitions might be part of an overall system that is a RESTful application
-- Roy T. Fielding

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

다시 SOAP과 REST를 보면...

SOAP는 복잡하고, 규칙이 많고, 어렵다.
REST는 단순하고 규칙이 적고, 쉽다.

고 알았는데,, 사실은 REST도 어렵다..

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

RST API가 아니여도 상관이 없다.

"REST emphasizes evolvability sustain on uncontrollable system. If you think you have control over the system or aren't interested in evolvability, don't waste your time arguing about REST. - Roy T. Fielding

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

시스템 전체를 통제한다 ?

서버 개발자가 클라이언트 개발자를 통제할 수 있는 상황 & REST Clinet와 Server을 한명의 개발자가 다 만들 경우

진화에 관심이 없다 ?

최근 업데이트가 쌓이더라도 신경쓰지 않아도 된다. (진화하지 않는다.)
오랜 시간에 걸쳐 진화하는 시스템을 설계하고 싶을 경우 REST를 따라야한다.


그럼 이제 어떻게 할까 ?

  1. REST API를 구현하고 REST API라고 부른다.
  2. REST API 구현을 포기하고 HTTP API라고 부른다.
  3. REST API가 아니지만 REST API라고 부른다. -> 현재 상태

"I am getting frustrated by the number of people calling any HTTP-base interface a REST API... Please try to adhere to them or choose some other buzzword for your API." - Roy T. Fielding

로이필딩 : 제약조건을 따르던지 아니면 다른 단어를 써라.

  1. REST API를 구현하고 REST API라고 부른다. (도전 해보자 !)

API는 왜 REST가 잘 안될까 ? 일반적인 웹과 비교를 해보자 !

흔한 웹 페이지HTTP API
ProtocolHTTPHTTP
커뮤니케이션사람ㆍ기계기계ㆍ기계
Media TypeHTMLJSON

HTTP API는 기계가 해석하기 때문에 Media Type이 다르다(JSON)
기계가 이해할 수 있는 format을 사용하게 된다.

문제의 원인이...Media Type이다 !

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

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

간단한 TodoList로 HTML과 JSON의 문서를 비교해보자 !

HTML을 Self-descriptive를 비교해보면
1. 응답 메시지의 Content-Type을 보고 media type이 text/html임을 확인한다.
2. HTTp 명세에 media type은 IANA에 등록되어있다고 하므로, IANA에서 text/html의 설명을 찾는다.
3. IANA에 따르면 text/html의 명세는 http://www.w3.org/TR/html이므로 링크를 찾아가 명세를 해석한다.
4. 명세에 모든 태그의 해석방법이 구체적으로 나와있으므로 이를 해석하여 문서 저자가 사용자에게 온전히 의미를 전달해 줄 수 있다.

HATEOAS로 보면 a 태그를 이용해 표현된 링크를 통해 다음 상태로 전이될 수 있으므로 HATEOAS를 만족한다.

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은 Self-descriptive를 보면
1. 응답 메시지의 Content-Type을 보고 media type이 application/json 임을 확인한다.
2. HTTP 명세에 media type은 IANA에 등록되어 있어있다고 하므로, IANA에서 application/json의 설명을 찾는다.
3. IANA에 따르면 application/json의 명세는 draft-ietf-jsonbis-rfc7159bis-04 이므로 링크를 찾아가 명세를 해석한다.
4. 명세에 json 문서를 파싱하는 방법이 명시되어있으므로 성공적으로 파싱에 성공한다. 그러나 "id"가 무엇을 의미하고, "title"이 무엇을 의미하는지 알 방법은 없다. --> 온전한 해석에 실패하기 때문에 Self-descriptive가 되지 못한다.
HATEOAS 측면에서 볼 경우 다음 상태로 전이할 링크가 없다. --> HATEOAS도 실패하게 된다.

HTML은 HATEOAS와 Self-descriptive를 만족하지만
JSON은 둘 다 만족하지 못한다.

GET /todos HTTP/1.1
Host: example.org

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

{
  {"id": 1, "title": "회사 가고 싶어요"},
  {"id": 2, "title": "집에 안갈거예요"}
}

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

Self-descriptive는 확장 가능한 커뮤니케이션

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

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

  • 어디서 어디로 전이가 가능한지 미리 결정되지 않는다. 어떤 상태로 전이가 완료되고 나서야 그 다음 전이될 수 있는 상태가 결정된다. 쉽게 말해서: 서버가 링크를 바꾸더라도 클라이언트는 문제가 없다. 동적으로 변경될 수 있다.

전이가 완료되고 나서야 그 다음 전이될 수 있는 상태가 결정된다. -> 어떤 링크를 따라서 그 페이지로 간다. 그 페이지에 가서 하이퍼링크들을 보고 나서야 확장이 된다. -> late binding이 되기 때문에 서버가 링크를 마음대로 동적으로 바꿀 수 있다. 따라서 동시적인 진화가 가능하다.

그럼 REST API로 바꿔보자

여러가지 방법이 있는데 첫 번째 Media type를 바꾸는 방법이다.

  1. 미디어 타입을 하나 정의한다.
  2. 미디어 타입 문서를 작성한다. 이 문서에 "id"가 뭐고 "title"이 뭔지 의미를 정의한다.
  3. 그 다음 IANA에 미디어 타입을 등록한다. 이 때 만든 문서를 미디어 타입의 명세로 등록한다.
  4. 이제 이 메시지를 보는 사람은 명세를 찾아갈 수 있으므로 이 메시지의 의미를 온전히 해석할 수 있다.
    Content-Type: application/json -> Content-Type: application/vnd.todos+json

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

다음 방법은 Profile을 쓴다.
1. "id"가 뭐고 "title"이 뭔지 의미를 정의한 명세를 작성한다.
2. Link 헤더에 profile relation으로 해당 명세를 링크한다.
3. 이제 메시지를 보는 사람은 명세를 찾아갈 수 있으므로 이 문서의 의미를 온전히 해석할 수 있다.
4.

Content-Type: application/json의 밑에
Link: <https://example.org/docs/todos> rel="profile" => 이 방법

단점
1. 클라이언트가 Link 헤더(RFC5988)와 profile(RfC6906)을 이해해야한다.
2. Content negotiation을 할 수 없다.
- 클라이언트가 지원하지 못하는 상황을 서버가 알 수 없다. 미디어타입을 판단하는 것이 아닌 링크 헤더를 판단하기 때문에.

HATEOAS 처리 방법

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

GET /todos HTTP/1.1
Host: example.org

HTTP/1.1 200 OK
Content-Type: application/json
Link: <https://example.org/docs/todos> rel="profile"
{
  {
  	"Link": "https://example.org/todos/1", -> 이 부분
  	"title": "회사 가고 싶어요"
  },
  {
  	"Link": "https://example.org/todos/2", -> 이 부분
  	"title": "회사 가고 싶어요"
  },
}

단점 : 이 링크가 어떻게 표현되는지 직접 정의해야한다.

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

GET /todos HTTP/1.1
Host: example.org

HTTP/1.1 200 OK
Content-Type: application/json
Link: <https://example.org/docs/todos> rel="profile"
{
  "Link": {
    "todo" "https://example.org/todos/1", -> 이 부분
  },	
  "data" [{
  	"id": 1,
  	"title": "회사 가고 싶어요"
  },
	"id": 2,
	"title": "집에 가기 싫어요"
  }]
}

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

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

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 -> 이 부분
Link: <https://example.org/docs/todos> rel="profile"
{	
  "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를 많이 고쳐야한다. (침투적)

HATEOAS

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


POST /todos HTTP/1.1
Content-Type: application/json

{
  "title" "점심 약속"
}
HTTP/1.1 204 No Content
Location: /todos/1 -> 이 부분
Link: </todos/>; rel="collection" -> 이 부분

단점: 정의된 relation만 활용한다면 표현에 한계가 있다.

결론 : HATEOAS는 data, 헤더 모두 활용하면 좋다.


궁금한 점 !

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

종류
urihttp//example.org/user/heondong
uri reference (absolute)/users/heondong
uri reference (relative)user
uri template/users/{username}

다 괜찮음

Media type 등록은 필수인가 ?

NO

"A REST API should be entered with no prior knowledge beyond the initial URI (bookmark) and set of standardized media types that are appropriate for the intended audience (i.e., expected to be understood by any client that might use the API).
-- Roy. T. Fielding

의도한 저자가 이해할 수 있으면 상관 없다.
ex) 회사 내에서만 쓰는 API고 이 Media type을 모두 이해한다면 굳이 IANA에 등록할 필요는 없다.

그래도 IANA에 등록하면 좋다.
Media type을 누구나 쉽게 사용할 수 있게 되고, 이름 충돌을 피할 수 있으며, 등록이 별로 어렵지 않다(고 주장함)


정리

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

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

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

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

    • Self-descriptive는 custom media type*이나 profile link relation** 등으로 만족시킬 수 있다.
    • HATEOAS는 HTTP 헤더나 본문에 링크를 담아 만족시킬 수 있다.
  • REST를 따르지 않겠다면, "REST를 만족하지 않는 REST API"를 뭐라고 부를지 결정해야 할 것이다.

    • HTTP API라고 부를 수도 있고
    • 그냥 이대로 REST API라고 부를 수도 있다. (roy가 싫어한다..)
      • 마이크로 소프트의 경우에도 REST를 HTTP로 고치는 PR을 올렸지만 무시했다. -> 우리(마이크로 소프트)는 REST가 틀렸다는 것을 알고 있지만 그래도 REST라고 부를 것이다. -> 스스로 결정할 수 있다면 괜찮다 !

참고 자료

그런 REST API로 괜찮은가

profile
백엔드 기록 공간😁

0개의 댓글