해당 post는 DEVIEW 2017 '그런 REST API로 괜찮은가'에 기반하여 작성되었습니다
REpresentational State Transfer
a way of providing interoperability between computer systems on the Internet
Q: 어떻게 인터넷에서 정보를 공유할 것인가?
A: 정보들을 하이퍼텍스트로 연결한다.
HTTP 1.0 이 나오기 전에 이미 웹이 급속도로 성장하고 수많은 웹서버들이 존재하였다.
HTTP 명세의 저자중 한명인 Roy T. Fielding
Q : "How do I improve HTTP without breaking the Web?"
A: HTTP Object Model
이것이 4년후에 REST(1998)란 이름으로 발표가 된다
Roy T. Fielding, Microsoft Research에서 발표 ("Representational State Transfer: An Architectural Style for Distributed Hypermedia Interaction")
2년뒤 2000년에 박사 논문으로 발표 ("Architectural Styles and the Design of Network-based Software Architectures")
1<?xml version="1.0" encoding="utf-8"?> 2<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"3 xmlns:urn="urn:enterprise.soap.sforce.com">4 <soapenv:Header>5 <urn:SessionHeader>6 <urn:sessionId><b>QwWsHJyTPW.1pd0_jXlNKOSU</b></urn:sessionId>7 </urn:SessionHeader>8 </soapenv:Header>9 <soapenv:Body>10 <urn:fieldList><b>Id, Name, Website</b></urn:fieldList>11 <urn:sObjectType><b>Account</b></urn:sObjectType>12 <!--Zero or more repetitions:-->13 <urn:ids><b>001D000000HS2Su</b></urn:ids>14 <urn:ids><b>001D000000HRzKD</b></urn:ids>15 </urn:retrieve>16 </soapenv:Body>17</soapenv:Envelope>
SOAP
1<?xml version="1.0" encoding="utf-8" ?>2<s:Envelope xmlns:s="http://www.w3.org/2001/06/soap-envelope">3 <s:Body>4 <s:Fault>5 <faultcode>flickr.error.[error-code]</faultcode>6 <faultstring>[error-message]</faultstring>7 <faultactor>http://www.flickr.com/services/soap/</faultactor>8 <details>Please see http://www.flickr.com/services/docs/ for more details</details>9 </s:Fault>10 </s:Body>11</s:Envelope>
REST
1<?xml version="1.0" encoding="utf-8" ?>2<rsp stat="fail">3 <err code="[error-code]" msg="[error-message]" />4</rsp>
SOAP과 REST의 직관적 비교
SOAP | REST |
---|---|
복잡하다 | 단순하다 |
규칙이 많다 | 규칙이 적다 |
어렵다 | 쉽다 |
1Roy T. Fielding2"No REST in CMIS"
https://{serviceRoot}/{collection}/{id}
형식이어야 한다1"s/REST API/HTTP API/"2-- Roy T. Fielding
1"REST APIs must be hypertext-driven"2
3Q: REST API를 위한 최고의 버저닝 전략은 무엇인가?4A: "REST API를 위한 최고의 버저닝 전략은 버저닝을 안 하는 것"5-- Roy T. Fieldinga
대부분 조건들은 잘 지켜지지만 Uniform interface 를 잘 지키지 못하고 있다
1GET/ HTTP/1.1
1GET/ HTTP/1.12Host: www.example.org
self-descriptive
또 다른 예 )
1HTTP/1.1 200 OK2
3[ { "op": "remove", path: "/a/b/c" } ]
Content-type header
추가1HTTP/1.1 200 OK2Content-Type: application/json3
4[ { "op": "remove", path: "/a/b/c" } ]
1HTTP/1.1 200 OK2Content-Type: application/json-patch+json3
4[ { "op": "remove", path: "/a/b/c" } ]
json-pathc+json의 명세를 보고 메시지를 해석할 수 있다.
따라서, 대부분의 REST API라 부르는 것은 이 조건을 만족하지 못한다
1HTTP/1.1 200 OK2Content-Type: text/html3
4<html>5<head></head>6<body><a href="/test">test</a></body>7</html>
1HTTP/1.1 200 OK2Content-Type: application/json3Link: </articles/1>; rel="previous", </articles/3>; rel="next";4
5{6 "title": "The second article",7 "Contents": "blah blah..."8}
독립적 진화를 위해
사례
HTML5 첫 초안에서 권고안 나오는데까지 6년
HTTP/1.1 명세 개정판 작업하는데 7년
상호운용성 (interoperability)에 대한 집착
문서의 위치
-> 식별하고자 하는 무언가
1An API that provides network-based access to resources via a uniform interface of 2self-descriptive messages containing hypertext to indicate potential state 3transitions might be part of an overall system that is a RESTful application4-- Roy T. Fielding
1REST emphasizes evolvability to sustain an uncontrollable system. 2If you think you have control over the system or aren’t interested in evolvability, 3don’t waste your time arguing about REST.4
5시스템 전체를 통제할수 있다고 생각하거나, 진화에 관심이 없다면, REST에 대해 따지느라 시간을 낭비하지 마라6-- Roy T. Fielding
1I am getting frustrated by the number of people calling any HTTP-based interface a REST API.2...3Please try to adhere to them or choose some other buzzword for your API.4
5제발 REST를 지키던지 아니면 다른단어를 써라.6-- Roy T. Fielding
일단 왜 API는 REST가 잘 안되나 일반적인 웹과 비교를 해보자
흔한 웹 페이지 | HTTP API | |
---|---|---|
Protocol | HTTP | HTTP |
커뮤니케이션 | 사람-기계 | 기계-기계 |
Media Type | HTML | JSON |
HTML | JSON | |
---|---|---|
Hyperlink | 된다 ( a 태그 등 ) | 정의되어 있지 않음 |
Self-descriptive | 된다 ( HTML 명세 ) | 불완전 * |
1GET /todos HTTP/1.12Host: example.org3
4HTTP/1.1 200 OK5Content-Type: text/html6
7<html>8 <body>9 <a href="https://todos/1">회사 가기</a>10 <a href="https://todos/1">집에 가기</a>11 </body>12</html>
Self-descriptive (o)
HATEOAS (o)
1GET /todos HTTP/1.12Host: example.org3
4HTTP/1.1 200 OK5Content-Type: application/json6
7[8 {"id": 1, "title": "회사 가기"},9 {"id": 2, "title": "집에 가기"},10]
Self-descriptive (x)
HATEOAS (x)
Self-descriptive
확장 가능한 커뮤니케이션
HATEOAS
애플리케이션 상태 전이의 late binding
방법 1: Media type
1GET /todos HTTP/1.12Host: example.org3
4HTTP/1.1 200 OK5Content-Type: application/vnd.todos+json6
7[8 {"id": 1, "title": "회사 가기"},9 {"id": 2, "title": "집에 가기"},10]
단점: 매번 media type을 정의해야한다.
방법2: profile
1GET /todos HTTP/1.12Host: example.org3
4HTTP/1.1 200 OK5Content-Type: application/json6Link: <https://example.org/docs/todos>; rel="profile"7
8[9 {"id": 1, "title": "회사 가기"},10 {"id": 2, "title": "집에 가기"},11]
단점:
방법1: data로
1GET /todos HTTP/1.12Host: example.org3
4HTTP/1.1 200 OK5Content-Type: application/json6Link: <https://example.org/docs/todos>; rel="profile"7
8[9 {10 "link": "https://example.org/todos/1",11 "title": "회사 가기"12 },13 {14 "link": "https://example.org/todos/2",15 "title": "집에 가기"16 }s17]
1GET /todos HTTP/1.12Host: example.org3
4HTTP/1.1 200 OK5Content-Type: application/json6Link: <https://example.org/docs/todos>; rel="profile"7
8{9 "links": {10 "todo": "https://example.org/todos/{id}"11 },12 "data": [13 {"id": 1, "title": "회사 가기"},14 {"id": 2, "title": "집에 가기"}15 ]16}
data에 다양한 방법으로 하이퍼링크를 표현한다.
단점:
1GET /todos HTTP/1.12Host: example.org3
4HTTP/1.1 200 OK5Content-Type: application/vnd.todos+json6
7{8 "data": [{9 "type": "todo",10 "id": "1",11 "attributes": { "title": "회사 가기" },12 "links": { "self": "https://example.com/todos/1" }13 },{14 "type": "todo",15 "id": "2",16 "attributes": { "title": "집에 가기" },17 "links": { "self": "https://example.com/todos/2" }18 }]19}
JSON으로 하이퍼링크를 표현하는 방법을 정의한 명세들을 활용한다.
단점: 기존 API를 많이 고쳐야한다.
방법2: HTTP 헤더로
1POST /todos HTTP/1.12Content-Type: application/json3
4{5 "title": "점심 약속"6}7
8HTTP/1.1 204 No Content9Location: /todos/110Link: </todos/>; rel="collection"
단점: 정의된 relation만 활용한다면 표현에 한계가 있다.
따라서, data, 헤더 모두 활용하면 좋습니다.
Spring을 사용한다면 Spring HATEOAS를 사용해보자
Media type 등록은 필수 인가?
media type을 IANA에 등록하기