기계와 기계, 소프트웨어와 소프트웨어 사이의 정보 요청과 교환을 위한 창구
소프트웨어가 다른 소프트웨어에게 지정된 형식으로 요청, 명령 받을 수 있는 수단을 Application Programming Interface (API)라 합니다. 꼭 네트워크 상에서만 API가 존재하는 것은 아니고 브라우저는 Web API를 통해 JavaScript로부터 특정 동작을 지시받기도 합니다. 윈도우에는 개발자들이 프로그램을 개발할 때 시스템이나 하드웨어에 대한 세세한 지식 없이도 지정된 명령어로 윈도우가 동작을 수행하도록 소프트웨어를 구성할 수 있는 Windows API를 제공합니다.
정보의 송수신에 널리 쓰이는 일종의 형식
REST API가 뭔가요? - 얄팍한 코딩사전
프론트엔드 웹에서 서버에 데이터를 요청하거나 배달 앱에서 서버에 주문을 넣는 등의 서비스에서 오늘 날 널리 사용되는 형식이 REST API입니다. 과거의 SOAP이라는 복잡한 형식을 대체하여 만들어졌습니다. REST의 가장 중요한 특성은 각 요청이 어떤 동작이나 정보를 위한 것인지를 그 요청의 모습 자체로 추론 가능하다는 것입니다. 바꾸어 말하면, RESTful하게 만든 API는 요청을 보내는 주소만으로도 대략적으로 어떤 요청인지 파악이 가능하다는 것입니다.
https://(도메인)/classes // 모든 class 목록 정보 요청
https://(도메인)/classes/2 // index가 2인 class에 대한 정보 요청
https://(도메인)/classes/2/students // index가 2인 class의 학생들에 대한 정보 요청
https://(도메인)/classes/2/students/15 // index가 2인 class의 학생들 중 index가 15인 학생의 정보 요청
위와 같은 조회 작업 뿐만 아니라 정보를 새로 추가하거나, 수정하거나, 삭제하는 작업도 필요합니다. 이들을 통틀어서 CRUD (Create, Read, Update, Delete)라 부릅니다.
서버에 REST API로 요청을 보낼 때는 HTTP (HyperText Transfer Protocol)이라는 규약에 따라 신호를 전송하는데, 아래와 같은 메서드를 통해 요청을 보낼 수 있습니다.
Image source: MDN Web Docs - mozilla
POST, PUT, PATCH 메서드는 body라는 공간이 마련되어 있어 GET이나 DELETE와 같은 메서드 보다 안전하게 많은 정보들을 감추어서 실어보낼 수 있습니다. 또한, 특정 메서드가 특정 용도로 사용하게끔 제한되어 있지는 않지만, 누구든 각 요청의 의도를 쉽게 파악할 수 있도록 RESTful하게 API를 만들기 위해서는 이들을 목적에 따라 구분해서 사용하는 것이 좋습니다.
GET https://(도메인)/classes/2/students
-> 2 반 학생들을 조회하는 요청POST https://(도메인)/classes/2/students
-> 2 반에 새로운 학생 추가 요청PATCH https://(도메인)/classes/2/students/15
-> 2 반 15 번 학생의 정보 수정 요청항상 요청의 내용을 구분 가능하도록 적합한 메서드로 요청하며, 특별한 경우를 제외하고는 URI의 이름을 명사형으로 짓습니다 (메서드 + URI -> 요청의 의미 파악 가능).
분산 하이퍼미디어 시스템 (예: 웹)을 위한 아키텍쳐 스타일
그런 REST API로 괜찮은가 - Naver Deview 17
아키텍쳐 스타일은 제약조건의 집합입니다.
위 아키텍쳐 스타일 중 uniform interface를 가장 만족시키지 못하고 있습니다.
메시지는 스스로를 설명할 수 있어야 한다는 개념입니다. GET / HTTP/1.1
와 같은 HTTP 요청 메시지는 무엇인가 빠져있어서 self-descriptive하다고 할 수 없습니다. 하지만 아래와 같이 목적지를 추가하면 self-descriptive 하다고 할 수 있습니다.
GET / HTTP/1.1
Host: www.example.org
아래는 self-descriptive한 response의 예입니다.
HTTP/1.1 200 OK
Content-Type: application/json-patch+json
[ { "op": "remove", "path": "/a/b/c"} ]
애플리케이션의 상태는 hyperlink를 통해 전이되어야 한다는 개념입니다.
아래 예시에서는 a 태그의 하이퍼 링크를 통해 다음 상태로 전이가 가능하기 때문에 HATEOAS를 만족합니다.
HTTP/1.1 200 OK
Content-Type: text/html
<html>
<head></head>
<body><a href="/test">test<a/></body>
</html>
아래의 또 다른 예시는 JSON을 통해 HATEOAS를 만족시키는 방법을 보여주고 있습니다. 링크 헤더를 통해 해당 리소스와 연결되어 있는 다른 리소스를 가리킬 수 있습니다.
HTTP/1.1 200 OK
Content-Type: application/json
Link: </articles/1>; rel="previous",
</articles/3>; rel="next";
{
"title": "The second article",
"contents": "blah blah..."
}
독립적 진화를 하기 위해 필요합니다. 독립적 진화란 아래를 의미합니다.
웹의 경우에는 아래와 같은 특징들로 비추어 보아 REST가 지켜지고 있다고 볼 수 있습니다.
아래와 같이 일부 깨지는 현상은 있을 수 있지만 동작은 합니다.
하지만 우리가 만드는 모바일 앱은 항상 아래와 같은 컴플레인을 받습니다. 서버가 변경된 경우 클라이언트쪽에서 업데이트가 필요한 경우 이런 일이 발생할 수 있습니다.
성공!
"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
그렇다고 합니다.
일반적인 웹과 비교해보겠습니다.
흔한 웹 페이지 | HTTP API | |
---|---|---|
Protocol | HTTP | HTTP |
커뮤니케이션 | 사람-기계 | 기계-기계 |
Media type | HTML | JSON |
HTML vs JSON
HTML | JSON | |
---|---|---|
Hyperlink | 됨 (a 태그 등) | 정의되어있지 않음 |
Self-descriptive | 됨 (HTML 명세) | 불완전* |
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>
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
1. a 태그를 이용해 표현된 링크를 통해 다음 상태로 전이될 수 있으므로 HATEOAS를 만족한다.
GET /todos HTTP/1.1
Host: example.org
HTTP/1.1 200 OK
Content-Type: application/json
[
{"id": 1, "title": "회사 가기"},
{"id": 2, "title": "집에 가기"},
]
https://bit.ly/32XfeMi
createdDateTime
updatedDateTime
주는 타입, 저장하는 타입
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"이 무엇을 의미하는지 알 방법은 없다.
HATEOAS
1. 다음 상태로 전이할 링크가 없다.
Content-Type: application/json
-> Content-Type: application/vnd.todos+json
1. 미디어 타입을 하나 정의한다.
2. 미디어 타입 문서를 작성한다. 이 문서에 "id"가 무엇이고 "title"이 무엇인지 의미를 정의한다.
3. IANA에 미디어 타입을 등록한다. 이 때 만든 문서를 미디어 타입의 명세로 등록한다.
Link: <https://example.org/docs/todos>; rel="profile"
1. "id"가 무엇이고 "title"이 무엇인지 의미를 정의한 명세를 작성한다.
2. Link 헤더에 profile relation으로 해당 명세를 링크한다.
3. 이제 메시지를 보는 사람은 명세를 찾아갈 수 있으므로 이 문서의 의미를 온전히 해석할 수 있다.
[
{
"link": "https://example.org/todos/1",
"title": "회사 가기"
},
{
"link": "https://example.org/todos/2",
"title": "집에 가기"
}
]
// or Use URI Template
{
"links": {
"todo": "https://example.org/todos/{id}"
},
"data": [{
"id": 1,
"title": "회사 가기"
}, {
"id": 2,
"title": "집에 가기"
}]
]
// use other specs
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" }
}
POST /todos HTTP/1.1
Content-Type: application/json
{
"title": "점심 약속"
}
HTTP/1.1 204 No Content
Location: /todos/1
Link: </todos/>; rel="collection"
그렇지 않다.
"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
그렇지 않다. 사용자가 이해할 수만 있으면 된다. 하지만 하면 좋다.
IANA에 Media type을 등록하면 좋은 점