안녕하세요, "생각의 웹"입니다.


앞서 아두이노 보드와 Node.js를 이용해 RESTful Web API와 JavaScript API를 제공하는 Do IoT Yourself 프로젝트를 소개한 바 있습니다.

문득 누군가 이와 유사한 프로젝트를 이미 하지 않을까 하는 생각이 들어 'arduino rest api'로 구글링해 보았습니다.

(친절한 구글 신은 자동 완성 기능을 통해 이런 프로젝트가 존재할 것이라는 제 예상에 힘을 실어 주었습니다.)


그 결과 발견한 프로젝트가 바로 aREST - arduino REST의 축약으로 보입니다. - 입니다.


http://arest.io/


상세 내용에 앞서 이 프로젝트를 통해 가능한 데모 영상 하나 보시죠. 




아직 사이트의 컨텐츠가 모두 완성되지 않은 상태로 보이나 (docs 메뉴에 가보면 under construction으로 되어 있습니다)
공개된 소스 코드의 README 파일이나 블로그에 포스팅 된 내용으로 보아 충분히 사용 가능한 수준으로 보입니다.

간략하게 정리하면 먼저 이 프로젝트는 다음과 같은 특성을 가지고 있습니다.



- REST API를 통한 아두이노 제어 가능

// 1. Connect a LED & resistor to pin number 8 of your Arduino board
GET 192.168.2.2/mode/8/o  // 2. Set the pin 8 as an output
GET 192.168.2.2/digital/8/1 // 3. Turn on LED

- 다양한 아두이노 보드 지원

  : Uno, Mega, Due, Yun and Teensy 3.x.

  

- 다양한 connectivity 지원

  : USB나 XBee를 통한 Serial 통신

  : CC3000 WiFi chip를 통한 HTTP 통신

  : Ethernet shield를 통한 HTTP 통신

  : nRF8001 chip를 통한 Bluetooth Low Energy 통신


- multicast DNS 프로토콜 지원으로 discovery 가능

  : Bonjour 서비스 필요


http://arest.io/ 를 보면 arduino library, Node.js module, JavaScript client 세 프로젝트로 구분되어 있는데 각각의

코드를 상세 검토(deep dive) 해 보면 다음과 같이 요약할 수 있습니다.


- arduino library: aREST의 핵심 모듈입니다. arduino IDE 프로젝트 파일 (*.ino)로 다양한 connectivity 하에서 

http server 기능을 C/C++로 구현하고 있습니다. 


- Node.js module: serial 통신을 통해 연결된 arduino 보드와의 gateway server 역할


- JavaScript client: aREST의 API를 호출하는 AJAX 코드


마무~으리로 이 프로젝트의 장/단점을 정리해 보겠습니다.  


- 장점

  : 다양한 connectivity를 지원합니다. 필요한 요구사항에 맞춰 가져다 쓸 수 있다는 점은 매우 매력적입니다.

  : 아두이노 보드(+ Ethernet or WiFi chip) 만으로도 독립된 인터넷 노드를 만들 수 있습니다.

  : 통신 시 전송량이 적은 JSON respresentation를 사용합니다.


- 단점

  : 보다 복잡한 기능을 추가하기 위해서는 arduino IDE를 통해 펌웨어를 업데이트해야 합니다.

    아두이노 펌웨어에 올릴 수 있는 코드 용량이 한정되어 있는 것으로 알고 있기에 제한을 받으리라 보입니다.

  : 제공하는 REST API의 성숙도 수준이 낮습니다. 

    상태를 변경시키는 unsafe 행위(e.g. LED를 켬)를 GET 명령으로 수행하고 있습니다.

    앞서 포스팅한 리처드슨 REST 성숙도 모델에 따르면 Level 1에 해당하며 클라이언트 프로그래밍 시 오류를

    야기시킬 수 있습니다.

  : 라이센스가 GPL입니다. 상업적인 목적으로 사용하시려는 분은 GPL이 모든 소스코드와 함께 빌드 방법까지 공개해야 하는 점을 유념하시기 바랍니다.  



이번 포스팅은 여기까지 입니다.

감사합니다.

  1. 생각의 웹 WebofThink 2014.11.15 00:49 신고

    자세한 개발 사례는 다음 블로그 포스팅을 참고하시기 바랍니다. https://learn.adafruit.com/a-rest-api-for-arduino-and-the-cc3000-wifi-chip/overview

안녕하세요, 

생각의 웹입니다.



지난 2번의 Do IoT Yourself 세미나에 이어 오는 10월 18일에 발표할 세 번째 강연의 슬라이드를 아래와 같이 선 공개 합니다.

혹시 참석하지 못하신 블로거 분들은 지난 세미나 관련 정보를 아래 링크를 통해 확인하실 수 있습니다.




이번 강의에서 다룰 내용은 웹을 구성하는 기술들에 대한 배경 지식과 개념들이 필요하기 때문에 이 분야에 경험이 전무하신 분들에게 조금 난해할 수 있겠다는 생각을 합니다. (특히 프로그래밍 경험이 전무한 비전공자 분들에게는요.)

이 자료의 초기 버전 (initial draft version)을 지인에게 공유했을 때에도 이해하기 힘들다는 피드백이 있어 개념을 전달하기 위해 몇 장의 슬라이드를 추가 보강했습니다.

혹시 자료를 보시고 난해한 부분이 있다면 댓글로 의견 주시면 추가 반영하여 보다 이해하기 쉽도록 개선하겠습니다.

(강의 중 Q&A 로 슬라이드에 잘 표현되지 않은 부분이 있다는 의견이 있어 추가 반영한 버전으로 슬라이드를 교체했습니다. ;-) )


짧은 시간에 내용을 제대로 전달하는데 무리가 있을 것 같은 우려에도 불구하고 이 내용을 포함시키고자 하는 이유는 이것이 사물 인터넷의 핵심 중 하나이기 때문입니다.

많은 미래학자들이나 관련 연구를 하시는 오피니언 리더 분들의 의견을 들어보면 사물 인터넷은 '사물'이 아닌 '인터넷'에 주안점을 두어야 하기에 특히, 다양한 사물 간의 대화를 가능케 하는 표준화된 인터페이스(interface)와 API의 중요성을 강조합니다.


History Does Not Repeat Itself, But It Rhyme


역사는 스스로 반복되지 않지만 운율이 있다는 뜻입니다.


이 격언을 인용한 이유는 인터넷을 보급한 핵심 서비스는 다름 아닌 웹이였고 웹의 HTTPURLHTML 세가지 기술은 전 세계 사람들을 연결하는 데 그 역할을 훌륭히 해 냈습니다. 따라서 사 반세기를 통해 검증되고 보급된 이 웹 기술들이 이제는 그 운율이 되어 사물 간, 그리고 만물 간의 인터넷에도 적용될 것이라는 기대와 확신이 저에게는 있습니다.


또한 여기서 설명하고 있는 RESTful Web API는 웹 서비스를 위해 도입된 다소 무겁고 폐쇄적인 WS-* 기술이 아닌 기존의 HTTP만으로도 웹 서비스가 가능하도록 만든 API 설계 원칙이고 이런 하위 호환성의 장점을 기반으로 사람 뿐 아니라 기계가 이해하고 사용할 수 있는 형태의 hypermedia API로 진화하는 중에 있기에 그 미래가 밝다라고 봅니다.


REST API에 대한 보다 기술적이고 자세한 내용이 궁금하신 분들은 이 블로그의 다음 포스팅을 참고하시기 바랍니다.



가진 지식을 나누며 생각을 키워 가는 것이 참 즐거운 일임을 오프라인 세미나를 통해서 다시 깨닫습니다.
온라인에서도 다양한 블로거 분들과 즐겁게 소통하며 함께 성장해 나가길 기대합니다.


읽어 주시고 관심가져 주셔서 감사합니다.

행복한 하루 되시길!


P.S. github의 DIoTY 프로젝트에 대한 설치 가이드자주 나온 질문들을 위키 페이지로 정리했습니다. 참고하시기 바랍니다.

안녕하세요, 생각의 웹입니다.


오늘은 REST API에 대해 검색하다가 우연히 발견한 좋은 포스팅이 있어 기록 겸해서 이렇게 링크를 공유합니다.


1. 개념 소개

2. API 설계 가이드

3. API 보안


방대한 내용을 이렇게 잘 정리해 주셔서 덕분에 더 많은 것을 배웠습니다.

특히 API 보안에 관한 부분은 기존 Web Service 1.0 (SOAP)에 비해 취약하다는 논란이 있어서 좀 더 공부해 봐야 겠다는 찰나에 좋은 글을 만나게 되었습니다.


열린 마음으로 좋은 내용들을 공유해 주시는 고수님들을 본받아 저도 열심히 수련하고 잘 나눠야 겠다는 마음을 품습니다.

 

감사합니다.

행복한 하루 되시길!

올해 한국에서 최초로 열린 WWW 2014 컨퍼런스의 Web API 워크숍에 제출한 논문의 국문 초안을 공유합니다. 한국인에겐 역시 한국말이죠. ;-)


발표 슬라이드는 아래와 같습니다.


영문 논문은 아래 링크에서 확인하실 수 있습니다.


http://ws-rest.org/2014/program


웹 API로 사람과 사물 그리고 모든 것이 연결되는 세상을 꿈꿉니다.

  



클라이언트 개발 효율화를 위한 REST API에서 JavaScript API 로 설계하기

ABSTRACT

Web-centric era의 도래로 web 서비스와 융합(mashup)이 가능하도록 RESTful web service가 탑재된 다양한 embedded system가 등장하고 있다. 
RESTful web service는 기존 web service (WS-* technology)에 비해 가볍고 쉬우며 별도의 추가 protocol 없이 HTTP를 지원하는 모든 형태의 platform에서 사용할 수 있다는 장점이 있다. 대신 개발자는 친숙하지 않은 개념인 GET, PUT, POST, DELETE 같은 표준 HTTP method를 이용해 URI가 가리키는 리소스의 상태 전이(State Transfer)라는 형태로 action을 표현하는 REST API 개념을 이해해야만 한다. 이런 난이함 때문에 모든 도메인의 API 설계에 적용 가능한 완전히 (fully) RESTful API 설계 방법론이 존재하지 않기에 현재 system이 제공하는 REST API 불완전하고 추후 변경될 소지가 많다. 또한 RESTful web service 설계를 돕는 WADL, WSDL 2.0, RDF 와 같은 도메인 언어가 존재하고 이를 이용한 자동화 도구도 소개되고 있으나, 주로 API를 제공(expose)하는 server 개발 측면에 집중되어 있다. 반면에 mediocre client 개발자는 해당 서비스의 도메인 지식이나 RESTful web service 이해가 부족해 개발에 어려움을 겪고 있다. 본 논문에서는 client 개발자 입장에서 어려움을 해결하기 위해서 REST API를 역 분석(reverse engineering)하여 사용하기 쉬운 JavaScript API로 재설계하는 방법을 고안하였다. 이 방법에 따라 REST API 대신 JavaScript API를 도입하고 이를 구현한 wrapper를 client 개발자에게 제공한 사례를 소개한다. 이를 통해 얻을 수 있었던 client 개발 효율화 이득을 설명한다. Future work으로 추가 발생하는 wrapper 개발 비용을 낮추기 위해 stub code를 자동 생성하는 방안 및 server side JavaScript에서도 사용할 수 있는 방안을 연구하려고 한다.



1. INTRODUCTION

모든 기기가 인터넷을 통해 연결되어 상호 연동하는 시대를 맞이하여 embedded system에서 인터넷을 접속하여 정보를 이용하는(information consumer) 형태 뿐만 아니라 마치 웹 서버 처럼 정보를 제공하는 (information producer) 형태가 등장하기 시작했다. 클라우드 컴퓨팅 시대가 본격화 되면서 개인이 가진 단말기에서는 주로 입/출력 작업만 이뤄지고 클라우드라 불리는 가상의 공간에서 정보 분석 및 처리, 저장, 관리, 유통 등의 작업이 이뤄지는 형태가 보편화 될 것으로 보았으나, 반면 단말기 내에 각종 센서가 탑재되고 계산 능력 (computing power)이 비약적으로 향상되어 단말기 자체가 클라우드 공간의 서비스 제공자 (service provider)의 역할을 수행하는 형태도 등장한다. 이를 기반으로 인간의 개입 없이 혹은 최소한의 개입으로 기기 간 협력하여 센싱, 정보 처리 및 교환, 네트워킹 하면서 상호 지능적 관계를 형성하고 서비스화 되는 사물 공간 연결망인 Internet of Things1 (a.k.a. IoT) 가 새로운 시대의 페러다임으로 등장하고 있다.


device vendor는 embedded system에서 인터넷의 정보 제공자 역할을 수행하기 위해 RESTful architecture style2의 web server를 탑재하고 있다. SOAP, WSDL, UDDI 표준을 사용하는 기존 web service architecture 는 embedded system에 구현하기에는 무겁고 복잡하기 때문에, Hypertext Transfer Protocol (HTTP) 기반으로 REST API를 제공하는 웹 애플리케이션 서버(WAS)가 채택 되었다. REST API는 RESTful architecture style에 따라 Uniform Resource Identifiers (URI), HTTP 와 표준 media type (e.g. XML, JSON, ... )로 resource를 구분하고 HTTP method를 이용해 동작하도록 구현하여 제공하는 Application Programming Interface (API)이다. 이 API는 기존 web service와 다르게 서버와 클라이언트 간 낮은 결합도(loosely coupled)를 가지는 장점을 있어 2 tier 구조 (서버-클라이언트) 뿐 아니라 3 tier 구조 (서버 - facade 혹은 gateway - 클라이언트) 이상의 복잡한 architecture로 구성된 다양한 서비스를 생성할 수 있다.


embedded system가 제공하는 REST API를 통해 기존 기기와 차별화된 융복합 (convergence) 서비스를 만들 수 있다. 예를 들어, file storage 및 synchronization 역할을 수행하는 Infra as a Service (IaaS) 없이도 기기 간 seamless data sharing이 가능한 cloud service3 를 제공할 수 있으며, client의 OS/제품군에 상관 없이 연동 가능한 TV 중심의 N-Screen Service4를 제공할 수 있다. 또한, home gateway server로서 원격에서 댁내의 가전 기기를 제어하고 모니터링할 수 있는 서비스5도 가능하다. 반면 REST API는 client 개발자가 사용하기에 난해하고 API 변경에 대응하기 힘들다는 문제를 가지고 있다. REST API를 사용하기 위해서는 친숙하지 않은 개념인 GET, PUT, POST, DELETE 같은 표준 HTTP method를 이용해 URI가 가리키는 리소스의 상태 전이(State Transfer)라는 형태로 action을 표현하는 REST API 개념을 이해해야만 하기 때문이다.


본 논문은 client 개발자에게 REST API의 기능을 JavaScript API를 제공하기 위해 REST API에서 JavaScript API를 설계하는 방법과 이를 구현한 wrapper를 제공함으로써 client 개발 생산성을 높이는 방안을 제시하였다. 이를 위해 Section 2에서는 REST API 와 별도로 JavaScript API를 도입하게 된 배경을 소개하고 Section 3에서는 REST API에서 JavaScript API를 설계하는 방법(approach)를 소개한다. Section 4에서는 Section 3에서 소개한 접근법을 통해 실제 진행한 과제를 소개한다. 마지막으로 Section 5에서 결론과 함께 추후 진행 방향(future work)을 설명한다.

2. MOTIVATION

embedded system에서 REST API를 제공하기 위해 설계할 때 있어서 전형적인 (traditional) REST API보다 고려해야 하는 제약 사항이 많다. 첫번째 제약은 예상 응답 시간이다. 기존 REST API는 대부분 계산(computation)을 요하는 논리적인 서비스(logical service)에 관련된 기능을 제공하는 데 반면 embedded system의 REST API는 기기가 수행(action)하는 실제적인 서비스(physical service)에 관련된 것이기 때문이다. 전자는 분산 환경 하에서 요청을 분배하여 빠르게 처리될 수 있어 응답 시간(response time)이 짧으나 후자는 요청의 동작을 기기가 완료할 때까지 대기해야만 하기 때문에 상대적으로 긴 응답 시간을 고려해야 한다. 두번째는 느린 진화 속도와 호환성이다. embedded system의 제품 생명 주기 (product life-cycle)는 제품 별로 천차 만별이고 대부분 차기 제품에서야 기존 제품의 개선 기능이 포함된다. 또한 차기 제품에서 기존 제품과 호환될 수 있도록 확장성 있는 설계가 필요하지만 실제 그렇게 구현하기가 어렵다. 그 이유는 호환성을 위해 고려해야 할 사항이 많아지면 제품 개발 비용이 증가하기 때문이다.


진정한(truly) REST API는 설계하는 것은 어렵고 기기 간 표준화된 REST API를 도출하는 것은 더욱 어렵다. REST API를 설계하는 명확한 가이드(concrete guide)와 설계 방법론(process)이 없고 대신 설계 과정 중 검토해야 할 복잡한 design decision들만이 존재한다. 때문에 동일 제품군의 동일 기능에 대해 규격 별로 상이한 API가 등장하고 있으며 Table 1에서는 동일 기능에 대해 가전 (consumer electronics, CE) 기기가 제공하는 다양한 형태의 API를 통해 보여주고 있다.


Table 1. 동일 기능에 대한 규격 별 URI 설계 사례

FeatureA 규격B 규격C 규격
Retrieving device status/allctrl/status/GetDeviceInfo/sd
Manipulating power status/allctrl/power/ SendCommandToDevice/sd
Retrieving power status/allctrl/power/GetDeviceInfo/sd
Retrieving available commandsN.A./GetCommandListOfDevice/sd

REST API는 API를 제공하는 측면에서 보면 진화 가능성(evolvability) 와 유지 보수성(maintainability)의 장점을 갖지만 도리어 API를 사용하는 측면에서 보면 사용하기 힘들게 만들고 작성한 client 코드의 가독성(readability)이 떨어지는 단점을 지닌다. 특히 REST API가 가지는 parameters가 많거나 다양한 media type을 지원하는 등의 조건에 따라 가질 수 있는 payload 형태가 달라지도록 REST API를 설계한 경우에 그렇다.


API 사용성은 도메인(domain)의 이해를 돕는 문서(document) 수준에 달려 있다. 엄밀히 말해 API를 제공하는 device 혹은 플랫폼에 대해 기본 지식이 있어야 API를 사용할 수 있다. 이를 위해서는 이런 기본 지식을 잘 정리된 문서가 필요하다. 이 문서에는 API에서 사용된 용어에 대해 기반 지식(background knowledge)이 없는 개발자도 이해할 수 있는 수준으로 기술되어 있어야 한다.


REST API guide 문서의 유지 보수에는 비용이 많이 든다. WADL6, WSDL 2.07, RDF8 와 같은 모델링 언어를 통해 설계한 경우 API reference 문서를 생성해주는 자동화 도구가 존재하나 programming guide를 생성해주는 도구는 없다. 개발자는 programming guide에 따라 개발하다가 세부 내용(detail)을 확인하기 위해 API reference를 참조하기 때문에 programming guide이 완전성(completeness)과 무결성(integrity)을 가질 수 있도록 관리해야 한다. 현실은 API 추가, 변경, 삭제로 인해 문서에 대한 관리 비용이 늘어나게 된다. 특히 다양한 media type를 지원하는 REST API의 경우, client 개발 시 예외가 발생할 가능성이 많아지고 예외 처리를 위해 client 코드는 복잡해 진다.


신뢰할 만한 서비스를 제공하기 위해서는 다양한 client 상에서 API 테스트가 필요하다. REST API는 server-client간 결합도가 낮고 (loosely coupled) API를 호출하는 측(caller)의 platform에 독립적이다. 이런 이유는 다양한 형태의 API caller에서 다양한 REST API의 호출 조합으로 정상 동작 여부를 테스트해야 한다. REST API의 경우 또다른 server에서 호출할 수도 있고 client 에서 호출할 수도 있는데 호출하는 server-client를 개발하는 언어/플랫폼은 매우 다양하기 때문에 모든 경우의 수에 대해 검증하기 위해서는 많은 비용이 든다. 특히, REST API를 통해 resource를 생성하거나 변경, 삭제하는 등의 device 상태를 변경하는 동작을 수행하는 경우에는 호출하는 쪽(caller)이 이를 수행할 수 있는 권한이 있는 지 확인하는 보안 정책이 고려되어야 한다. 이런 보안 정책의 부재로 web 표준을 따르는 web browser에서는 REST API가 호출되지 않는 현상이 제품 출시 후 발견된 사례를 Section 4에서 소개하겠다.


Web platform이 탑재된 기기 간 interaction을 위해 서로 다른 형태의 (heterogeneous) API가 필요하다. 현재 web application에서는 내부 resource를 이용하기 위해 JavaScript API를 사용하고 외부의 resource를 이용할 때는 REST API를 사용한다. 다시 말해, client application는 REST API를 통해 메세지를 host application에게 전달하고 host application는 JavaScript API로 client와 메세지를 받게 되는 구조가 된다. 따라서, web application 간의 상호 작용을 위해서 JavaScript - REST API 쌍(pair)이 필요하다.

현대 client 개발자에게 친숙한 API의 형태는 JavaScript API이다. 전형적인 web application는 Model-View-Controller (MVC) 개념으로 보면 모델(Model) 역할의 HTML, View 역할의 CSS 그리고 HTML 혹은 CSS의 정보를 가공(manipulation)하거나 간단한 연산을 수행하는 Control 역할로써 JavaScript 로 구성되어 있다. Ajax9, DHTML10 기술이 도입되면서 JavaScript로 대화형(interactive) application을 구현할 수 있게 되었고, HTML 511를 통해 멀티미디어 컨텐츠를 쉽고 용이하게 사용 수 있게 되면서 JavaScript API가 주목을 받게 되었다. REST API를 web application내에서 호출하기 위해서는 Figure 1.과 같이 Ajax JavaScript API를 사용해야 한다.

var xmlhttp = new XMLHttpRequest();

xmlhttp.onreadystatechange=function() {
    if (xmlhttp.readyState==4 && xmlhttp.status==200) {
        console.log(xmlhttp.responseText);
    }
}
xmlhttp.open("GET", url, true);
xmlhttp.send();

Figure 1. JavaScript Ajax API로 REST API 호출 코드 예제



JavaScript는 높은 수준의 (high-level) 추상화된 함수를 설계할 수 있도록 제공한다. 이는 JavaScript가 객체 지향 언어이며 또한 함수형 프로그래밍을 지원하는 특성을 가지기 때문이다. client 개발자는 business logic을 구현하는 중간에 Ajax API를 이용해 REST API를 호출하여 구현할 수 있다. 하지만, JavaScript 언어의 장점을 이용해 생산성을 높이기 위해서 Figure 4 와 같은 함수를 설계해서 활용할 수 있다. Figure 2에서 주의 깊게 볼 부분은 ajaxCall 함수의 6번째 argument로 successCallback를 전달 받는데 이는 함수 형 인자라는 사실이다. JavaScript에서는 이처럼 함수를 전달받아 호출이 가능하기 때문에 함수형 언어처럼 재사용성이 높은 함수를 만들 수 있다.

var addr = "http://foo.com/";
function ajaxCall(method, uri, headers, queries, payload, successCallback, isAsync) {
    var httpObj = new XMLHttpRequest();
    var url = addr + uri + "?" + queries;

    for (var i = 0; i < headers.length ; i++) {
        httpObj.setRequestHeader("header", headers[i]);
    }
    httpObj.onreadystatechange = function() {
        if (httpObj.readyState == 4 && xmlhttp.status == 200) {
            successCallback(xmlhttp.responseText);
        }
    }
    httpObj.open(method, url, isAsync);
    httpObj.send(payload);
}

Figure 2. JavaScript Ajax API를 함수로 은닉화 (encapsulation)한 코드 예제


JavaScript 로 작성한 logic를 공유와 재사용이 가능하다. 앞서 소개한 Ajax 함수와 DHTML 를 통해 JavaScript file 자체를 web application에 가져와서 활용할 수 있다. web application 개발 생산성이 높은 이유는 jQuery12 과 같은 open source JavaScript library를 활용하기 때문이다.


3. APPROACH

객체 지향적으로 설계한 JavaScript API를 역 공학(reverse engineering)를 통해 REST API 대신 만들어 제공한다. JavaScript의 문법(syntax)의 대부분은 객체 지향 언어인 Java에서 차용했다. Java는 객체 지향 특성을 이용해 구현한 다양한 종류의 API를 제공하고 개발자들은 이 API를 사용함으로써 개발 생산성을 향상시킬 수 있다. 따라서 JavaScript에서도 객체 지향 API를 통해 생산성을 향상시킬 수 있다. Figure 2 에서 소개한 수준으로 REST API와 JavaScript API를 맵핑하는 수준으로 JavaScript API를 만들 수 있으나 이렇게 생성된 JavaScript API는 기존 REST API와 비교해 장점이 없다. 하지만 REST API가 제공하는 기능을 역 분석을 통해 객체지향 적으로 재 설계하면 사용하기 쉬운 API로 탈바꿈하게 된다. 이를 위한 일반화된 변환 매커니즘을 소개하면 다음과 같다.


1) REST API의 사용 사례를 도출한다. 대개 REST API의 programming guide에서 사용 사례에 따라 필요한 API와 예시를 설명하고 있기 때문에 이를 통해 손쉽게 알 수 있다.


2) 사용 사례에서 client에서 가져야 할 state와 state relationship을 도출한다. REST API는 server에서 client의 상태 정보를 유지하지 않도록 API를 설계하기 때문에 client에서 해당 상태 정보를 유지해야 한다. 이에 착안하여 client가 유지해야 하는 state와 그 상태로 변경되는 조건 (state transition condition)을 유추할 수 있다. 방법은 간단하다. 먼저 특정 URI에서 GET method가 제공되는 경우 해당 resource에 대한 state를 가져온다고 보고 이에 해당하는 적절한 state를 명명한다. 그리고 이 state의 attribute(s)가 다른 REST API의 POST, PUT, DELETE method에 참조되는 지를 확인하면 state 사이의 relationship을 도출할 수 있다. 또한 URI는 resource의 상하 구조(hierarchy)로 구성되기 때문에 상위 resource가 존재하는 상태에서만 하위 resource가 존재할 수 있다. 때문에 이런 관계도 state relationship에 나타낸다.


3) 도출된 states와 state transition에 대한 책임(responsibility)을 담당할 entity를 도입한다. 객체 지향 설계 원칙13에 따라 client에서 해당 state(s)를 관리할 interface를 도입하는 것이다. 이때, 하나의 interface가 의미상으로는 여러 states와 연관 관계를 가질 수 있으나 하나의 책임을 맡도록 하는 단일 책임 원칙(Single Responsibility Principle)을 따라 설계하는 것이 좋다.


4) 도입한 interface에 state transition(s)에 해당하는 method를 추가한다. REST API 설계 시 POST, PUT, DELETE method에 생성, 업데이트, 삭제의 의미를 부여하기 때문에 method 이름을 지을 때 참조한다.


5) method의 parameter를 설계할때 해당 REST API의 parameters를 구분하여 parameter 수가 많지 않도록 맵핑한다. REST API에서는 parameter를 HTTP의 URI 일부 resource(s) 이름으로, HTTP header의 parameter로, URI 다음에 ? 토큰을 붙여 사용하는 query parameter로, payload body에 다양하게 설정할 수 있다. Figure 3.의 Sample REST API request를 예로 들면, resValueHeader-Param1Header-Param2query1query2, JSON 형태의 media type을 같는 parameters로 bodyParam1, bodyParam2가 이에 해당된다. REST API 설계 원칙에 따르면 URI 혹은 header의 parameters로는 범용 목적의 attribute(s)를 지정하고 query에는 보조적인 (ancillary) 기능에 해당하는 attribute(s)를 그 외는 특정 기능에 필요한 parameter(s) 지정한다. 따라서, JavaScript API로 설계할 때 이런 특성을 이용해 entity의 attribute로 parameter를 mapping할 지 아니면 method의 argument로 mapping하는 게 나을 지를 판단할 수 있다. 가능하면 범용 attributes는 별도의 interface를 도입해서 재사용할 수 있도록 하고 보조적인 attributes는 method의 optional argument(s)로, 나머지는 method의 mandatory parameter(s)로 설계한다. method의 parameter 개수가 너무 많아지면 API 사용성이 떨어지기 때문에 유사한 정보를 지니는 attributes는 묶어서 interface로 설계한 뒤 argument로 전달되도록 한다.

PUT http://127.0.0.1/ws/boo/resValue?query1=value1&query2=value2    HTTP/1.1

Accept: application/json
Accept-Language: ko-KR
Header-Param1 : headerValue1
Header-Param2 : headerValue2

{
    bodyParam1 : "bodyValue1",
    bodyParam2 : "bodyValue2" 
}

Figure 3. REST API에서의 parameters 예

[Constructor (DOMSting id)]
interface Boo {
    attribute DOMString id;           // originated from resValue
    attribute DOMString headerParam1; // originated from Header-Param1
    attribute DOMString headerParam2; // originated from Header-Param2

    void update(BodyParam params,            // grouping payload JSON data as BodyParam interface
                optional DOMString query1,   // orginated from query1 parameter
                optional DOMString query2);  // originated from query2 parameter
};

[NoInterfaceObject]
interface BodyParam {
    attribute DOMString param1; // originated from bodyParam1
    attribute DOMString param2; // originated from bodyParam2
};


Figure 4. Web IDL로 Figure 3의 REST API를 JavaScript API로 설계한 사례


구조 설계가 완료되면 JavaScript API를 모델링 언어로 상세 설계한다. Figure 4는 Figure 3의 REST API를 Web IDL14 언어로 설계한 사례이다. JavaScript API 설계 및 구현의 일관성을 돕기 위해 Web IDL을 존재하는데 이를 활용하면 구현 및 문서화에 도움을 받을 수 있다. 예를 들면 Web IDL에서 XML를 생성하는 open source tool인 widlproc15를 통해 모델링의 완결성(completeness) 검증이 가능하고 이를 확장하면 stub code 및 API 문서 자동 생성 등이 가능하기 때문에 이를 사용하는 것을 추천한다.


JavaScript API를 REST API와 mapping해 주는 wrapper를 구현한다. wrapper는 JavaScript API를 제공하는 web platform 종류에 따라 다양한 개발 언어로 구현될 수 있으며 JavaScript 언어로 구현할 경우 다양한 web platform에서 수정없이 재사용할 수 있다. JavaScript로 wrapper를 구현할 경우, Figure 4의 Ajax 함수를 사용한다.

개념 증명(proof of concept)를 통해 API 사용성을 검증하고 개선사항을 도출해 다음 설계에 반영한다. API 설계를 평가하는 최선의 방법은 설계한 API를 사용해서 직접 web application을 개발해 보는 것이다. 특히 기존 REST API가 제공하는 모든 기능을 한번에 JavaScript API로 설계하기보다 일부를 빠르게 설계하고 해당 기능을 구현해 보는 점진적인(iterative) 방법이 좋다. 좋은 설계 패턴을 찾아 다음 설계에 기준(criteria)으로 삼아 빠르게 API 사용성을 향상 시킬 수 있기 때문이다.


4. CASE STUDY

이번 case study에서는 Smart TV가 제공하는 convergence app API 중 client API를 REST API에서 JavaScript API로 변환해서 host-client 모두 JavaScript API로 제공한 사례를 통해 앞서 소개한 approach의 유용성을 다룬다.


TV Convergence App API (a.k.a N-Service)는 web platform를 탑재한 Smart TV 기기와 주변의(nearby) 모바일 기기가 연동하여 N-Screen 서비스를 개발할 수 있도록 애플리케이션 간의 통신 (inter application communication) 인터페이스를 제공하는 API이다. 


기존에는 Smart TV 기기의 application에서는 host 기능에 대한 JavaScript API를 제공하고 모바일 기기는 TV가 제공하는 REST API를 사용해서 client 기능의 application을 구현하도록 제공하고 있었으나 이번 case study를 통해 Figure 5와 같이 client에서도 host처럼 JavaScript API를 사용하여 application을 구현할 수 있도록 API와 wrapper를 개발자에게 제공하였다. 이 결과물은 Android16, Tizen17 OS에서 사용할 수 있는 API로써 samsung developer site18를 통해 공개되었다.




Figure 5. N-Service API의 system architecture


앞서 Section 3에서 소개한 접근 방식에 따라 첫번째, REST API의 기능을 파악하기 위해 API guide 문서에서 API 사용 사례를 정리한다. 일반적으로 API를 외부에 공개할 때 사용법을 가이드해주는 문서를 함께 공개한다. 이 문서는 API를 사용해서 개발자가 구현할 수 있는 기능을 설명하고 있는데 [19] 에서 client를 위한 REST API를 확인할 수 있다. 편의 상 Table 2.는 REST API가 제공하는 기능에 대한 사용 사례를 요약한 것이고 여기서 {appId}, {deviceId}, {groupId}는 각각 host application의 ID, host에 접속되어 있는 (connected) client device의 ID, 생성한 group 의 ID를 의미한다.


Table 2. 발췌한 client 를 위한 REST API list

HTTP methodURIUse case
POST/ws/apps/{appId}/connectconnect to host application
POST/ws/apps/{appId}/disconnectdisconnect with host application
GET/ws/apps/{appId}/infoget host application information
POST/ws/apps/{appId}/queuepush a message to host application or upload a file
GET/ws/apps/{appId}/queue/devices/{deviceId}pop a message of a specific client device from host application
POST/ws/apps/{appId}/queue/devices/{deviceId}push a message to a specific client device
POST/ws/apps/{appId}/queue/groups/{groupId}push a message to a specific group
GET/ws/apps/{appId}/queue/groups/{groupId}retrieve a group members
POST/ws/apps/{appId}/queue/groups/{groupId}/joinjoin a group
POST/ws/apps/{appId}/queue/groups/{groupId}/leaveleave a group

두번째 단계인 사용사례에서 client에서 가져야 할 state와 state relationship는 도출하면 Figure 5와 같다. 앞서 설명한 방법대로 Table 2의 use case list 중 GET method를 통해 도출한 state를 host applicationmessage queuegroup 으로 정의하고 각각의 state로 전이(transition)하기 위한 REST API를 맵핑하였다. 특히, URI hierarchy 상으로 {appId} 아래 queue, groups 가 존재하기 때문에 이점을 state diagram의 transition에 반영하였다.




Figure 6. State diagram from use cases


세번째, state와 state transition에 대한 responsibility를 담당할 entry를 도입한다. 앞서 소개한 바와 같이 host application을 위한 JavaScript API를 [20]에서 제공하고 있고 Table3.은 이를 발췌한 것이다. 따라서, 가능한 유사한 기능을 담당하는 신규 entity가 등장하지 않도록 기존 API에 등장하는 entity를 활용하도록 한다. 각 entity가 가져야 할 책임을 고려했을 때 host application를 담당할 NServiceHost interface를 새로 도입하기로 판단하고 message queue와 group은 기존 interface인 NServiceManager, NServiceDeviceGroup, NServiceDevice이 지니는 책임에 맞춰 기능을 나누기로 결정했다.


Table 3. host를 위한 JavaScript API list

InterfaceConstant/Attribute/MethodUse Case
NServiceDeviceManagervoid getNServiceDevices (successCallback, errorCallback)host와 연결된 (connected) client device 객체 (NServiceDevice)를 가져옴
NServiceDeviceManagervoid registerManagerCallback (callbackFn(ManagerEvent))client connection, disconnection 등의 이벤트를 수신하는 callback을 등록함
NServiceDeviceManagerNumber broadcastMessage (DOMString message)host와 연결된 모든 client 에게 메세지를 전달
NServiceDeviceManagerNumber multicastMessage (DOMString groupID, DOMString messasge)특정 group에게 메세지를 전달
NServiceDeviceDOMString getUniqueID ()특정 client의 고유 ID를 확인
NServiceDeviceDOMString getDeviceID ()특정 client의 device ID를 확인
NServiceDeviceDOMString getName ()특정 client의 이름을 확인
NServiceDeviceNumber getType ()특정 client의 유형 확인
NServiceDeviceNumber sendMessage (DOMString message)특정 client에게 메세지를 전달
NServiceDevicevoid registerDeviceCallback ( callbackFn(NServiceDeviceEventInfo) )특정 client가 전달하는 메세지를 host에서 수신하는 callback을 등록함
NServiceDevicevoid unregisterDeviceCallback ()특정 client에서 전달하는 메세지 수신을 해제함
ManagerEventNumber eventTypeconnection 혹은 disconnection 이벤트 유형을 확인
ManagerEventDOMString deviceName이벤트를 발생시킨 client 이름
ManagerEventDOMString uniqueID이벤트를 발생시킨 client의 고유 ID
ManagerEventNumber deviceType이벤트를 발생시킨 client 유형
NServiceDeviceEventInfoNumber eventType특정 client의 메세지 전송, 그룹 가입 탈퇴 이벤트 유형을 확인
NServiceDeviceEventInfoNServiceDeviceMessageInfo eventData or NServiceDeviceGroupInfo eventData메세지 내용
NServiceDeviceGroupInfoDOMString groupName특정 client가 가입 혹은 탈퇴한 그룹 이름
NServiceDeviceMessageInfoDOMString messageclient가 발송한 메세지
NServiceDeviceMessageInfoDOMString contextclient가 발송한 컨텍스트


네번째로 state transition에 해당하는 method를 설계하는데 있어 Figure 6에서 나타난 connect, disconnect, info, queue, join, leave를 JavaScript의 메소드로 설계하면 된다. 여기서 REST API는 ajax로 전송되기 때문에 응답 시간을 고려하면 되도록 비동기 함수로 설계하는 것이 좋다. 비동기 함수로 설계하기로 결정할 경우, 동작의 결과가 성공적이였을 때 호출될 success callback 과 실패했을 때에 호출될 error callback이 parameter로 추가되어야 한다.


마지막으로 REST API 특성 상 참조하는 parameters가 많기 때문에 범용 parameters나 유사한 의미를 지닌 parameters에 대해 새로운 인터페이스 안에 은닉화(encapsulation)함으로써 parameter 수를 줄인다. 예를 들어 host application과 connection를 하는 REST API의 예시는 Figure 7과 같다. 여기에 등장하는 parameters 중 application Id인 sampleWidget, header parameters인 SLDeviceID, VendorID, DeviceName, ProductID는 모두 공용 변수라고 판단하고 connection을 위한 메소드 뿐 아니라 다른 목적으로 사용할 수 있도록 별도의 인터페이스로 설계 한다. parameter가 가진 의미에 따라 해당 인터페이스를 도입한다. application Id는 host application에 관한 정보이고 SLDeviceID, VendorID, DeviceName, ProductID는 client에 관한 정보이기 때문에 전자는 NServiceHostInfo 인터페이스, 후자는 NServiceOwnDeviceInfo 인터페이스의 attribute로 설계한다. NServiceOwnDeviceInfo 인터페이스를 위한 get /set 함수를 도입해서 connection 하는 method를 호출하기 이전에 설정하도록 설계하고 연결에 필요한 추가 정보인 host server의 IP address와 port number를 NServiceHostInfo 인터페이스에 추가해서 connection method에 전달하고 응답 시간을 고려해서 비동기로 수행되도록 한다. 이렇게 설계한 JavaScript API를 사용하는 예시는 Figure 8과 같다.

POST /ws/app/sampleWidget/connect     HTTP/1.1

SLDeviceID: 12345
VendorID: VenderMe
DeviceName: IE-Client
ProductID: SMARTDev

Figure 7. N-Service REST API 중 Connect to Application에서 발췌

var ownInfo = new webapis.NServiceOwnDeviceInfo({
    deviceID : 12345, 
    deviceName : "IE-Client", 
    productID : "SMARTDev" 
});

webapis.nservice.setOwnDeviceInfo(ownInfo);

var hostInfo = new webapis.NServiceHostInfo({
   ipAddress : "162.168.1.2", // assume that it is the host server's address
   appID : "sampleWidget" 
}); 

webapis.nservice.connectToHost(hostInfo,
    function (hostObj) {
       console.log("successfully connected to host");
    },
    function (err) {
       console.log("fail to connect to host");
});

Figure 8. Figure 7의 REST API를 JavaScript API로 설계했을 때의 예시


Figure 9 는 REST API를 변환해서 client API로 만들고 기존의 host API와 융화(harmonize)되도록 설계한 ER-diagram이다. common I/F라고 표시한 부분은 host application에 존재하는 interface를 재사용 혹은 확장한 것을 의미하고 client specific I/F로 표시한 부분은 client API를 위해 추가한 interface를 의미한다. 이로써 common API라고 표시된 부분처럼 host의 JavaScript API에서 제공하던 method의 일부를 client API에서도 지원할 수 있게 되어 client-host 구분 없는 한 종의 API로 거듭하게 되었다.




Figure 9. N-Service API 의 overall entry-relation diagram


sequence diagram를 통해, API 사용 흐름(call flow)과 API를 구현함에 있어 논리적인 문제가 있는지 확인한다. Figure 10는 Figure 7의 REST API를 Figure 8처럼 JavaScript API를 통해 호출하는 과정을 표현하고 있다. 이런 과정을 통해 명확한 API 설계가 가능하고 구현 상에서 발생할 가능성이 있는 설계 오류를 줄일 수 있다.




Figure 10. N-Service 의 host-client connection를 위한 API sequence flow


구조 설계 (high level design) 과정이 끝났으면 모델링 언어로 상세 설계(detailed design)한다. 여기서는 Web IDL를 이용하여 설계하였고 Figure 11은 Figure 9, Figure 10를 토대로 Web IDL 문법으로 정의한 사례이다. 이 모델링 언어로 상세 설계하면 타입이 없는 언어(untyped language)인 JavaScript에서는 표시할 수 없는 argument type를 명시할 수 있어 API를 구현하거나 사용할 때 있어서 이해를 도울 수 있으며 자동화 도구를 통해 API의 완결성 검증이나 API 문서를 자동 생성 할 수 있다는 장점을 취할 수 있다. Web IDL로 설계하여 생성한 문서는 [21] 에서 확인할 수 있다.

[Constructor (NServiceOwnDeviceInfoInit init)]
interface NServiceOwnDeviceInfo {

    attribute DOMString deviceID;
    attribute DOMString vendorID;
    attribute DOMString deviceName;
    attribute DOMString productID;
};

[Constructor (NServiceHostInfoInit init)]
interface NServiceHostInfo {

    attribute DOMString ipAddress;
    attribute unsigned short portNumber;
    attribute DOMString appID;

    readonly attribute DOMString? version;
    readonly attribute DOMString? appName;
    readonly attribute NServiceHostStatus status;
};

[NoInterfaceObject] interface NServiceManager {

    boolean setOwnDeviceInfo(NServiceOwnDeviceInfo info);

    NServiceOwnDeviceInfo? getOwnDeviceInfo();

    void connectNServiceHost(NServiceHostInfo hostInfo, 
        NServiceHostConnectSuccessCallback onsuccess,
        optional ErrorCallback? onerror);
};

Figure 11. Web IDL 언어로 설계한 Connect to Application 관련 API


상세 설계와 같이 API를 제공할 wrapper를 구현한다. 변환 메커니즘의 산출물을 이용하면 REST API와 맵핑되는 JavaScript API의 logic를 구현하는 것은 어렵지 않다. 단, API를 구현할 플랫폼을 결정하고 이에 따라 발생할 수 있는 web application의 보안 정책에 대한 이해는 선행되어야 한다. 첫번째, JavaScript API를 제공하는 주체는 다양하다. 기본적으로 web browser부터 android native application에서 web application를 수행하는 webview22, 설치 형(installable) web application를 지원하는 Tizen, Firefox OS 같은 web platform등이 존재한다. API를 제공할 client 플랫폼을 무엇으로 할 지에 따라 API를 구현하는 언어가 달라질 수 있다.


개념 증명(Proof of concept)을 통해 시스템 제약 사항을 도출하고 개선한다. wrapper를 이용하는 sample client application을 개발해 수행해 본 결과 ajax를 이용해 wrapper를 구현하면 웹 보안 정책으로 인해 다음과 문제가 발생함을 알 수 있었다. cross-site scripting 이라고 알려진 보안 취약점 (security vulnerability)를 막기 위해 web application에서 수행하는 script는 모두 같은 도메인 주소에서 제공되어야 하는데 REST API는 REST API를 호출하는 wrapper와 같은 도메인에 존재할 수 없기 때문에 Ajax로 REST API 호출이 이뤄지지 않는 현상이 발생한 것이다. 이를 해결하기 위해 REST API를 제공하는 web server에서 W3C 표준 Cross Origin Resource Sharing (CORS)을 위해 [23]를 구현하도록 했다.


JavaScript API를 제공함으로써 얻는 client 개발 생산성 및 효과를 검토한다. 동일한 application에 대해 REST API를 사용해서 개발한 경우와 JavaScript API를 사용해서 개발한 경우와의 비교가 이뤄지지는 않았으나 client 개발자에게 JavaScript API를 통해 손쉽게 TV와 mobile 기기 간 convergence 기능을 만들 수 있도록 제공함으로써 이전에 비해 다양한 web application을 개발할 수 있음을 확인했다. 이 application들을 [24], [25], [26], [27], [28]에서 다운로드 받아 확인해 볼 수 있다.


마지막으로 case study를 통해 Section 3의 유효성을 평가하기 위해 Section 2에서 제기한 문제점들이 해결되었는지를 되짚어 보자. 첫째, 개념 증명 과정에서 발견한 REST API에 대한 제약사항을 반영해 제공함으로써 효과적으로 대처할 수 있었다. 둘째, 도출된 JavaScript API는 잘 알려진 객체 지향 설계 원칙에 따라 설계되어 client 개발자가 사용하기 편리했다. 셋째, JavaScript API를 사용한 client 코드는 REST API를 직접 호출한 것보다 가독성이 좋았다. 넷째, JavaScript API의 reference 문서로도 REST API의 programming guide 수준의 정보를 제공할 수 있다. client에서 가능한 동작(action)으로 API가 재설계되었기 때문이다. 마지막으로 비용 대비 효과적인 테스트가 가능했다. 기존의 REST API의 경우 테스트를 마치고 출시되었음에도 불구하고 web browser에서는 호출이 안되는 현상이 발생했는데 이번 case study를 통해 설계한 JavaScript API를 테스트 하면서 발견할 수 있었기 때문이다.

5. CONCLUSION AND FUTURE WORK

본 논문에서는 embedded system에서 제공하는 REST API가 client 개발의 입장에서는 사용하기 어렵다는 점에 주목했다. 따라서, client 개발 생산성을 향상시키고 추후 REST API 변경에도 적절히 대응할 수 있는 방안으로 REST API 대신 JavaScript API를 제공하는 방안을 제시했다. REST API의 사용 사례 분석과 client가 state를 가지는 REST API의 특성에서 부터 도출한 state diagram에서 객체 지향 방법론을 통해 사용성이 높은 JavaScript API를 설계하는 변환 메커니즘을 설명하고 JavaScript API 모델링 언어인 Web IDL로 상세 설계를 진행함으로써 설계 완결성 검증 및 자동 문서화 도구의 도움을 받을 수 있었다. 실제 수행한 case study를 통해 REST API 대신 JavaScript API를 제공하기 위해 발생하는 추가 개발 비용과 JavaScript API를 통한 client 개발 측면의 생산성 이득을 보여 주었다. 

REST API를 fully RESTful 하게 설계하기 위한 방법론은 아직 정립되지 않았고 특히 resource 제약이 있는 embedded system의 web server에서 제대로 구현하기도 어렵다. 따라서, 사물 간 통신, 즉 사물 인터넷(IoT)를 enabling 하는 기술로써 evolvability, maintainability, self-descriptiveness 등을 만족시키는 REST API가 device에 탑재되기까지는 더 많은 시간이 필요하리라 보인다. 

따라서, REST API를 client 개발자에게 공개하는 대신에 JavaScript API 형태로 포장(wrapping) 해서 제공하면 추후 embedded system의 RESTful API가 변경되거나 다른 모델로 변경되었을 때라도 손쉽게 client 유지 보수가 할 수 있으리라 기대한다.

future work으로 case study를 통해 얻은 API wrapper 개발 경험을 토대로 우리는 Web IDL로 설계한 문서에 REST API에 대한 정보를 추가(annotation)한 후 widlproc 기반으로 해당 stub 코드를 생성하는 도구를 개발하고자 한다. 또한 REST API 변경 및 삭제로 인해 JavaScript에서 발생하는 오류를 수집하는 logic를 추가해서 API wrapper의 수정이 이뤄질 수 있도록 하겠다. 마지막으로 API wrapper를 client 뿐 아니라 Node.JS28와 같은 server에서도 사용할 수 있도록 제공하여 IoT에서도 활용할 수 있는 방안을 연구하겠다.


6. ACKNOWLEDGEMENTS

We would like to thank the Samsung Web API team members for the case studies which they had been conducted together.



7. REFERENCES

[1] 사물 인터넷 기술, 서비스 그리고 정책, 조철회 외 www.nipa.kr
[2] Fielding RT (2000), Architectural styles and the design of network-based software architectures, Ph.D. Thesis, University of California. Irvine, USA
[3] Samsung Link. http://link.samsung.com/
[4] Smart TV Convergence App API. http://www.samsungdforum.com/Guide/ref00003/index.html
[5] Samsung Home Sync. http://developer.samsung.com/homesync
[6] M. Hadley. Web application description language (WADL). Techincal report, W3C, August 2009. http://www.w3.org/Submission/wadl/ 
[7] R. Chinnici, J. Moreau, A. Ryman, and S. Weerawarana. Web Service Description Language (WSDL) Version 2.0 Part 1 : Core Language. Technical report, W3C, June 2007. http://www.w3.org/TR/wsdl20
[8] Resource Description Framework. http://www.w3.org/RDF/
[9] Asynchronous JavaScript and XML http://en.wikipedia.org/wiki/Ajax_(programming)
[10] Dynamic HTML. http://www.w3.org/Style/#dynamic
[11] HTML5 http://www.w3.org/TR/html5/
[12] jQuery http://jquery.com/
[13] Robert C. Martin, Principles Of Object Oriented Desigin. http://c2.com/cgi/wiki?PrinciplesOfObjectOrientedDesign
[14] Cameron McCormack. Web Interface Definition Language. http://www.w3.org/TR/WebIDL/
[15] Tim Renouf, Paddy Byers, et al. widlproc https://github.com/dontcallmedom/widlproc
[16] Google. Android http://www.android.com/
[17] Linux Foundation. Tizen. http://tizen.org
[18] Samsung web API on developer site. http://developer.samsung.com/samsung-web-api
[19] Client (HHP) to TV Application Communication on samsung d forum site.http://www.samsungdforum.com/Guide/ref00003/convergence_app_clienttotvappcomm.html
[20] NService on samsung d forum site. http://www.samsungdforum.com/Guide/ref00008/nservice/dtv_nservice.html
[21] NService API Reference on Samsung developer site. http://img-developer.samsung.com/onlinedocs/samsung_webapi_guide_public_1.0/html/index.html
[22] WebView reference on Android Developers. http://developer.android.com/reference/android/webkit/WebView.html
[23] Anne van Kesteren. Cross-Origin Resource Sharing. http://www.w3.org/TR/cors/
[24] Colapicto http://developer.samsung.com/samsung-web-api/samples/Colapicto
[25] Draw Together http://developer.samsung.com/samsung-web-api/samples/Draw-Together
[26] Family Album http://developer.samsung.com/samsung-web-api/samples/Family-album
[27] YouTube Continue Play http://developer.samsung.com/samsung-web-api/samples/Continuous-Youtube-play
[28] Puzzle Game http://developer.samsung.com/samsung-web-api/samples/Puzzle-game
[28] Joyent.Inc. node.js. http://nodejs.org/

"생각의 웹"입니다.


구글에서 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), 상이한 전송 기법 - 예를 들면 모바일 앱, 이메일 메세지 - 등이 어떻게 되어야 하는지는 숙제로 남겨져 있습니다. 이 하나 하나 모두 풀기에 매우 까다로운 것들이기 때문이죠.


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



WS-REST 2014 워크숍이 끝난지도 벌써 두 달여의 시간이 지난 이제서야 용기를 내어 글을 써내려가기 시작하네요. -_-;;;


서두에 이번 워크샵을 한줄로 평가하면   

내 생애 최초로 논문을 발표한 워크숍이라서 매우 설레였고 

배경 지식 및 어학 역량이 부족해 이해하지 못한 부분이 많았으나 전 세계의 전문가들의 자신의 의견을 개진하면서 토론하는 모습에 매료되었다.

라고 요약할 수 있겠네요.


프로그램의 내용은 다음 링크를 참조하시고 발표 및 논의된 내용은 이어 간략하게 정리하겠습니다. 


http://ws-rest.org/2014/program


  1. Keynote
    • Google의 Sam Goto 가 발표를 진행했으며 Google에서 웹 서비스와 관련 API를 만들며 경험한 사례들과 REST Web API의 발전 과정을 매우 재미있고 역동적으로 소개
  2. '코를 막기' 대 '후각으로 따라가기'
    • REST API의 최근 서적인 'RESTful Web API'의 저자 중 한명인 마이크 아문센이 디즈니의 애니메이션 '업'에 등장하는 개를 빗대어 웹 상에서 서비스를 기술하는 방식 (service description)에 대한 올바른 접근 방법을 소개함.
  3. 프로비넌스(provenance)를 이용해 시간 대 별 Web API로 data를 publish 하기
    • 데이타 프로비넌스를 이용해 Web API의 형상을 관리하는 REST API와 이를 이용하여 Web API 변경에도 대응이 가능한 시스템 개발
  4. 클라이언트 개발 효율화를 위한 REST API를 JavaScript API로 설계하기 
    • 제가 제출한 논문으로 REST API와 JavaScript API를 맵핑해서 설계하는 디자인 패턴과 REST API 대신 JavaScript API를 제공하여 개발한 사례를 소개 
  5. 웹 암호화 API
    • W3C에서 복잡하고 다양한 암호화 기법을 추상화한 JavaScript API를 표준화 한 사례를 소개함.
  6. 동적 스트리밍 토폴로지를 제어하는 REST API
    • 스트리밍 트래픽에 따라 동적으로 토폴로지를 구성할 수 있도록 설계한 REST API를 소개 함. 
  7. 트랜젝션을 분산 처리하는 REST API
    • 이 커머스와 같이 트랜젝션이 필요한 서비스에서 REST API 형태로 이를 처리할 수 있는 디자인 패턴 소개 
  8. REST 설계 원칙을 따르는 트랜젝션 모델의 7대 도전 과제
    •  REST API와 기존 트랜젝션과의 상이 점과 이를 상쇄하기 위한 여러 기술적 접근법을 소개
  9. 실제 제품에 탑재하기 위한 목적으로 만든 코드 자동 생성 API 클라이언트 
    • REST API의 self-descriptiveness를 기반으로 API에서 클라이언트 코드가 자동 생성되도록 상용 수준으로 적용한 사례 소개
  10. 웹 상에서 RESTful linked service 를 연결하는 접근법
  11. IoT를 위한 COMPOSE API
    • 단말 디바이스 간 서비스를 조합 가능하도록 설계한 REST API 소개  

이해 부족 혹은 지나치게 요약하느라 내용이 잘못 전달될 수도 있으니 자세한 내용은 원문 링크의 논문 본문을 참고하시기 바랍니다.

감사합니다.





+ Recent posts