"생각의 웹"입니다.


구글에서 Open API 설계를 담당하고 있는 샘 고토의 블로그 중 소개하고 싶은 포스트가 있어 아래와 같이 번역하여 공유합니다. 이 연구의 결과가 기계와 사람 간에 스마트한 웹 세상을 만들어 내고 IoT가 꿈꾸는 스마트한 세상을 만드는 데 도움이 되리라고 생각합니다. 


의역으로 인해 오역의 가능성이 있으니 더 많은 내용이 궁금하시면 아래 원문 글을 참고하시기 바랍니다. ;-)


http://blog.sgo.to/2014/02/rows.html


리소스 지향 웹 서비스 (ROWS)

리소스 지향 웹 서비스 (ROWS)란 리소스들에 대한 프로그램적인 검색, 기술(description) 그리고 호출이 자동으로 수행 되도록 하는 일련의 기술입니다.


이는 휴먼 웹과 프로그래머블 웹을 연결해 주고 웹이 어떻게 동작하는지에  - URL들과 REST라는 일관된(Uniform) 인터페이스. 여기서 URL의 R이 핵심 영역입니다.-  보다 적합하게 설계된 서비스 지향 아키텍쳐의 대안 중 하나입니다.  


이 포스트는 연재 글 중에 하나이며 읽기 전에 이 과 이 을 읽어 보길 권합니다.


이 글은 이 기술 명세를 보다 읽기 쉽도록 하기 위해 쓰였습니다. 


우리가 다시 풀고자 하는 문제는?

우리의 목표는 "휴먼 웹"과 "프로그래머블 웹"을 연결하는 것입니다. 따라서, 현재 우리가 현재 수작업으로 하고 있는 것들을 자동화하는 것에 도전하고자 합니다.

우리는 아직까지 다음 기술들을 도출하지 못했습니다:

  1. 각각 별개의 서비스에 대한 리소스 설계, 표현(representation) 포맷 그리고 리소스 간의 링크를 클라이언트에게 알려줄 수 있는 보편적인 프레임 워크

  2. RESTful 과 하이브리드 서비스들의 다양성을 기술할 수 있는 어휘를 가진 언어. 이 언어로 작성된 문서는 보편적인(generic) 웹 서비스 클라이언트 코드를 커스텀하게 작성된 포장개체(wrapper)처럼 동작하도록 생성할 수 있습니다. 보다 자세하게 말하면 우리는 클라이언트에게 다음과 같은 것들을 알려주어야 합니다:

    • 수행 가능한 동작의 의미(semantic)가 존재하는가?

    • 어떤 HTTP 메소드(method)가 사용되는가?

    • 요청의 형식(entity-body)는 어떻게 구성되었는가?

    • 호출 후 응답되기를 기대하는 것은 무엇인가?

어떻게 시작하는지부터 살펴보자

휴먼 웹은 브라우저를 이용해 URL이라는 리소스를 GET 요청함으로써 시작됩니다. 만일 콜 택시를 요청하기 위해서 필요한 사례를 들어 설명해보죠. 
아래는 브라우저 내부에서 일어나고 있는 일을 보여 줍니다.

GET /mountain-view HTTP/1.1
Host: www.yellowcab.com 

그러면 서버가 다음과 같이 응답하도록 구현할 수 있습니다:


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

  1. <html>
  2. <body>
  3.  
  4. <span>Welcome to Yellow Cab Mountain View!</span>
  5.  
  6. <a href="/moutain-view/reservations">
  7. Click here to book a cab!
  8. </a>
  9.  
  10. </body>
  11. </html>

지금 정도로도 사람에겐 충분한 정보겠지만 컴퓨터가 이 웹 페이지 내용과 개구리에 관련된 웹 페이지와의 구분할 수 없습니다.


JSON-LD, microdata와 Schema.Org 삽입하기

컴퓨터가 이 페이지를 이해하도록 만드는 첫번째 과정은 이 페이지가 무엇인지에 대해 명확히 알려 주는 겁니다.


HTML 내에서 연결 데이터(linked-data)를 전송하기 위한 몇 가지 방안이 있는데 제가 선호하는 방식은 JSON-LD와 microdata*입니다.


* 제 생각엔 JSON-LD가 대용량의 복잡한 사례들에 대응하기 위한 보다 확장성 있는 방식이라고 보는 반면 microdata는 예제가 쉬워 쉽게 이해할 수 있습니다. 그래서 전 여기에서는 microdata를 사용할거지만 실제로는 JSON-LD를 훨씬 선호한다는 사실을 알아주셨으면 합니다.


안타깝게도 microdata나 JSON-LD 만으로는 충분치 않습니다. 택시 정거장에 대한 컴퓨터 처리가 가능한 기술이 필요하기 때문이죠.  이것을 schema.org에서 가져올 수 있습니다: shema.org는 세상에서 컴퓨터가 이해할 수 있는 방식으로 사물을 기술하는 어휘들을 제공하는 사이트입니다.


아래는 이 웹 페이지의 모습을 보여줍니다:


HTTP/1.1 200 OK
Content-Type: text/html
  1. <html>
  2. <body itemscope
  3. itemid="/mountain-view"
  4. itemtype="http://schema.org/TaxiStand" >
  5.  
  6. <span itemprop="description">
  7. Welcome to Yellow Cab Mountain View!
  8. </span>
  9.  
  10. <a itemprop="reservations"
  11. href="/mountain-view/reservations"
  12. itemscope itemtype="http://schema.org/ItemList">
  13. Click here to book a cab!
  14. </a>
  15.  
  16. </body>
  17. </html>

이제 제가 서두에서 필요로 하다고 제시한 기술들을 리마인드 해보죠. 이 JSON-LD / micro-data + schema.org 를 통해 컴퓨터가 이해할 수 있는 방식으로 사물을 기술하기 위한 보편적인 프레임워크를 제공할 수 있습니다. 


그 결과 컴퓨터는 이제 다음을 이해할 수 있습니다:

  • 이 리소스는 TaxiStand (택시 승차장) 입니다.
  • 이 택시 승차장은 기술(description)을 가지고 있습니다.
  • 이 택시 승차장은 예약 아이템 리스트 (ItemList of reservations)를 가지고 있습니다.
그러나 이것으로 할 수 있는 것을 이해하기에는 턱없이 부족합니다.

프로그래머블 웹으로의 연결

API에 존재하는 프로그래머블 웹을 컴퓨터가 발견하도록 하기 어렵습니다. 그래서 이 특정 택시 승차장을 택시 (yellow cab) API에서 찾을 수 있도록 링크를 추가해 보겠습니다:

  1. <body itemscope
  2. itemid="/mountain-view"
  3. itemtype="http://schema.org/TaxiStand" >
  4. <meta itemprop="alternate" itemscope
  5. itemtype="http://schema.org/ApiUrl"
  6. content="http://api.yellowcab.com/moutain-view"/>


이로서 이 택시 서비스가 특정 API에 연결되어 있음을 컴퓨터가 알 수 있게 되었습니다.
만일 저 URL에 GET 요청을 하게 되면 다음과 같은 일이 일어나게 됩니다:

GET /mountain-view HTTP/1.1
Host: api.yellowcab.com

그리고 서버는 다음과 같이 응답합니다:


HTTP/1.1 200 OK
Content-Type: application/json+ld
  1. {
  2. "@context": "http://schema.org",
  3. "@type": "TaxiStand",
  4. "@id": "/mountain-view",
  5. "description": "Welcome to Yellow Cab!",
  6. "reservations": {
  7. "@type": "ItemList",
  8. "@id": "/mountain-view/reservations",
  9. }
  10. }

이 응답은 컴퓨터가 이해할 수 있는 형식에 훨씬 가깝습니다. 

Content-Type 헤더가 있어 컴퓨터가 어떻게 이것을 분석(parse)할 수 있는지 알려주고 또한 내부의 하이퍼미디어가 이 리소스를 컴퓨터가 이해할 수 있는 정보 (machine-readable information)를 제공하기 때문입니다.


하지만, 컴퓨터가 이 리소스들로 무엇을 할 수 있을지 알려 줄수도 있을까요?


만일 예약을 하고 싶다면 HTTP로 어떻게 해야 하지?

HTTP에서 API 검색 기법에 가장 가까운 방식은 OPTIONS 요청을 보내는 것입니다.


OPTIONS /mountain-view/reservations HTTP/1.1
Host: api.yellowcab.com

그러면 다음과 같이 응답할 수 있겠죠:

HTTP/1.1 200 OK
Allow: OPTIONS, GET, HEAD, POST

POST 요청은 많은 일들을 할 수 있도록 설계되었기에 "RESTful Web API"의 저자들 (리처드슨, 샘 그리고 마이크, 이후 LSM으로 명기)이 앞서 지적했던 것처럼 이로써는 충분하지 않습니다. 어떻게 이런 것들을 알 수 있을까요:

  1. POST 요청의 내용(entity-body)은 무엇을 채워야 하는가?
  2. POST 요청이 중첩된 POST 요청(예를 들어 RPC-형태의 POST)인지을 어떻게 구분할 수 있을까?

액션 (Actions)를 추가하기

액션은 리소스로 무엇을 할 수 있는지 알려주는 어휘입니다. 이것은 추가 요청을 하는 것이 아닌 리소스에 추가 삽입(attached inline)하는 형태입니다.

이것은 중요한 세 가지의 기법으로 구성됩니다:
  1. 사물에 액션을 연결하는 기법

  2. 액션을 분류하고 요청을 강제하기 위한 잘 정의된 의미(semantics)

  3. 매개 변수가 어떻게 생겼는지를 기술하는 어휘
JSON-LD 응답이 어떻게 생겼는지 보시죠:


HTTP/1.1 200 OK
Content-Type: application/json+ld
  1. {
  2. "@context": "http://schema.org",
  3. "@type": "TaxiStand",
  4. "@id": "/mountain-view",
  5. "description": "Welcome to Yellow Cab!",
  6. "reservations": {
  7. "@type": "ItemList",
  8. "@id": "/mountain-view/reservations",
  9. "operation": {
  10. "@type": "CreateAction",
  11. "expects": {
  12. "@type": "SupportedClass",
  13. "subClassOf": "http://schema.org/TaxiReservation",
  14. }
  15. }
  16. }
  17. }

이 정보와 동일한 정보를 HTML 마크업에서도 찾을 수 있습니다:

  1. <a itemprop="reservations"
  2. href="/mountain-view/reservations"
  3. itemscope itemtype="http://schema.org/ItemList">
  4. <meta itemprop="alternate" itemscope
  5. itemtype="http://schema.org/ApiAppUrl"
  6. content="http://api.yellowcab.com/moutain-view/reservations" />
  7. <div itemprop="operation" itemscope
  8. itemtype="http://schema.org/CreateAction"/>
  9. <meta itemprop="expects" itemscope
  10. itemtype="http://schema.org/SupportedClass"
  11. content="http://schema.org/TaxiReservation"/>
  12. </div>
  13. </div>
  14. Click here to book a cab!
  15. </a>
* 이 형태가 꽤나 복잡해 보인다는 점 인정합니다만 이후에 이걸 더 요약하는 법 또한 소개하도록 하겠습니다. 힌트는 링크드 데이터와 연관되어 있습니다.

이제 컴퓨터가 이해하는 데 필요한 *모든 것*을 알려줄 수 있습니다:

  • 이것은 택시 승차장입니다.
  • 여기에 API 시작 위치가 있습니다. http://api.yellowcab.com/moutain-view/
  • 이 택시 승차장은 예약 아이템 리스트를 가지고 있습니다.
  • 이 예약 아이템 리스트에는 *매우* 상세한 의미(semantics)를 갖는 - 이 요청이 갖는 의미 뿐 아니라 세부 상세 내용까지 포함된 - 액션 생성(CreateAction)이라는 동작을 갖습니다. 예를 들어 이렇게 정의된 동작은 엄격한 POST 요청이 되겠지요.
  • 예약을 하기 위해서는 택시 예약 객체(TaxiReservation)를 전달합니다.
즉, 이 정보를 통해 컴퓨터는 다음과 같은 요청을 보낼 수 있게 됩니다:

POST /mountain-view/reservations HTTP/1.1
Host: api.yellowcab.com
Content-Type:application/json+d;charset=utf-8
Content-Length:207
  1. {
  2. "@context": "http://schema.org/",
  3. "@type": "TaxiReservation",
  4. "pickUpLocation":
  5. "1600 Amphitheatre Parkway, Mountain View, CA",
  6. "pickUpTime": "2pm",
  7. "numberOfPassengers": "1"
  8. }

그러면 서버는 다음과 같이 응답을 하게 되겠지요:

HTTP/1.1 201 Created
Location:
http://api.yellowcab.com/moutain-view/reservations/32523325225


이렇게 다시 하이퍼 미디어가 도래합니다.

하이퍼미디어는 정말 엄청나게 위력있는 개념입니다. 이 개념을 통해 하나의 리소스에서 다음 리소스 링크로 이동할 수 있게 됩니다. 정말 대단한 거죠.

방금 하나의 리소스를 생성했다면 이걸로 해볼 수 있는 최선을 한번 고려해 봅시다:

OPTIONS /mountain-view/reservations/32523325225 HTTP/1.1
Host: api.yellowcab.com


그럼 서버는 이렇게 응답할 수 있겠죠:

HTTP/1.1 200 OK
Allow: OPTIONS, GET, HEAD, PATCH
Accept-Patch: application/json+ld

이 응답의 PATCH HTTP 메소드로 인해 이 리소소는 변경되기 쉬운 (mutable) 리소스라는 걸 알 수 있다는 것이 꽤 흥미로운 점이죠. 또한 이 리소스는 추가로 JSON-LD 패치 문서를 가지고 있다고 알려 주기때문에 이 역시 꽤 유익한 정보가 될 겁니다.


그러나, POST 요청이 그렇듯 PATCH 동작의 어플리케이션 의미(semantics)가 무엇인지
 충분히 알 수는 없습니다. 예를 들어 "패치"가 pick up 시간을 업데이트하는 것인지 아니면
location을 전달(drop off) 하는지 말이죠.


액션으로 되돌아 가보죠. 이 리소스를 GET 요청합시다:


GET /mountain-view/reservations/32523325225 HTTP/1.1
Host: api.yellowcab.com

그러면 서버는 이렇게 응답해 줄 수 있습니다:

HTTP/1.1 200 OK
Content-Type: application/json+ld
Accept: application/json+ld
  1. {
  2. "@context": "http://schema.org",
  3. "@type": "TaxiReservation",
  4. "@id": "/mountain-view/reservations/32523325225",
  5. "reservationStatus": "CONFIRMED",
  6. "operation": {
  7. "@type": "CancelAction"
  8. }
  9. }

여기에 취소(CancelAction) - "미래의 사건이나 행위가 더 이상 일어나지 않도록 하는 행위" - 라는 매우 명확한 어플리케이션 의미를 가지고 있고 이 리소스를 "취소" 하는 의미가 매우 명확히 정의(HTTP 용어에서는 "취소"의 정의에 관련된 것은 PATCH 요청입니다.)되어 있으며 따라서 컴퓨터는 다음과 같이 PATCH 요청을 보낼 수 있기 때문입니다:

PATCH /mountain-view/reservations/32523325225 HTTP/1.1
Host: api.yellowcab.com
Content-Type:application/json+d;charset=utf-8
Content-Length:100
Accept: application/json+ld

  1. {
  2. "@context": "http://schema.org/",
  3. "@type": "CancelAction"
  4. }

이제 취소된 예약 상태를 알 수 있습니다:


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

  1. {
  2. "@context": "http://schema.org",
  3. "@type": "TaxiReservation",
  4. "@id": "/mountain-view/reservations/32523325225",
  5. "reservationStatus": "CANCELLED",
  6. }

마지막으로 덧붙이면 취소를 완료하게 되면 취소된 예약에는 적용되지 않기 때문에 "취소" 요청의 내용은 사라지게 됩니다.


남은 숙제들...

"악마는 디테일에 있다"는 말처럼 아직 모음(collections), 인증(authentication), 상이한 전송 기법 - 예를 들면 모바일 앱, 이메일 메세지 - 등이 어떻게 되어야 하는지는 숙제로 남겨져 있습니다. 이 하나 하나 모두 풀기에 매우 까다로운 것들이기 때문이죠.


추후 올릴 포스팅에도 계속적으로 관심 가져 주시기를 바랍니다. 감사합니다.

+ Recent posts