"생각의 웹"입니다.


 "Web IDL로 JavaScript API를 설계하기" 시리즈의 첫 번째 포스팅에서 이 작업의 당위성에 대해 말씀드렸으니 이제는 도구를 설치하고 사용해 보기로 합시다.


지난 번 포스팅에서 소개해 드린 widlproc 도구는 Web IDL로 작성된 설계 문서를 XML 형태로 변환할 뿐만 아니라 연계된 도구를 통해 해당 xml에 대한 dtd와 xslt 문서를 통해 html 문서를 생성해 줍니다. 다시 말씀드리면, Web IDL로 설계한 사항에 대한 문법 적합성(문법 오류 및 완결성 등)를 검증(validation) 해서 이상이 있을 경우 해당 위치를 알려주고 문제가 없을 시 XML 문서로 내뱉어 줍니다. 이 XML를 이용해 사람이 읽을 수 있는 HTML 문서를 생성할 수 있으며 또한 이 정보를 기반으로 해당 API에 대한 코드 템플릿(stub code)을 생성하여 개발 생산성을 향상시킬 수 있습니다.


그럼 도구를 받아 설치해 보도록 합시다.

   

  1. 먼저 아래 github에서 widlproc를 다운로드 받습니다. 
    (https://github.com/dontcallmedom/widlproc)
    git clone 하거나 해당 페이지에서 다운로드 받을 수 있습니다.

  2.  해당 페이지에는 마치 windows에서 동작하는 것처럼 가이드되어 있으나 리눅스를 사용하시길 권장합니다. 윈도우즈 상에서 cygwin을 까느니 virtualbox 기반 ubuntu를 사용하는게 속 편하실 겁니다. XML 관련 도구들이 대부분 리눅스에서 제공되는 것들이기 때문입니다. 저는 아래와 같이 virtualbox에 ubuntu 14.04 LTS를 설치하여 작업했습니다.



  3. 다운로드 받은 파일이 존재하는 경로에서 Makefile 을 확인한 뒤 make 명령을 수행합니다. 빌드를 위해 필요한 라이브러리가 있다는 메세지가 나오는 경우, apt-get install 명령을 통해 설치하도록 합니다.

  4. 빌드가 정상적으로 완료되면 해당 경로 아래 obj 폴더가 생성되고 이 경로에 widlproc 이라는 실행 파일이 존재하게 됩니다.

  5. 도구의 사용법과 Web IDL 문법 및 documentation rule에 대한 정보는  /doc/widlproc.html 파일을 참고하시기 바랍니다.

  6. 간단한 테스트를 위해 함께 제공하고 있는 샘플 Web IDL 문서를 가지고 widlproc 도구를 실행해 봅시다. /examples 경로에 가면 *.widl 문서가 있습니다. 미리 알려드릴 사항은 이 문서들은 현재 widlproc 도구에서 더 이상 허용하지 않는 Web IDL 문법을 포함하고 있다는 점입니다. 따라서, 수행 결과 문법 에러 화면을 보시더라도 크게 놀라지 않으시기 바랍니다. (저는 놀랐거든요;;)

  7. *.widl 문서를 바로 *.html 문서로 생성해 주는 Makefile이 /examples 경로에 있습니다. 해당 파일을 열어 경로가 제대로 되었는지 확인합니다.



  8. make 명령을 수행하여 widl 문서를 html 문서로 변환합니다. 필요한 모든 도구가 설치되어 있다면  module ... { 으로 시작하는 라인에서 오류가 있다고 알려줍니다. (혹시 도구가 필요하다고 나오면 해당 도구를 apt-get install {도구 명} 명령으로 설치합니다. ) 여기까지 하시면 모든 작업을 제대로 수행하신 겁니다.


여기서 발생하는 오류들은 예제로 제공되고 있는 bondi.widl, filesystem.widl를 작성한 시점 이후에 Web IDL 문법은 많은 개정이 있었기 때문에 이에 맞춰 widlproc 코드는 업데이트 된 반면 예제 코드는 업데이트 되지 않아 발생한 문제입니다. 


따라서, 다음 포스팅은 지난 arduino JavaScript API 관련 포스팅에서 간략히 정리했던 Web IDL로 HTML 문서를 생성한 사례을 들어 Web IDL로 설계하는 법을 소개하도록 하겠습니다.


오늘 포스팅은 여기까지 입니다.


관심 가져주셔서 감사합니다.

늘 행복한 하루 되시길...    



  


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


이번 포스팅부터는 제목과 같이 Web IDL로 JavaScript API를 설계하는 방법을 여러분들께 공유해 보고자 합니다. 


먼저, 여러분에게 JavaScript API를 설계해야 하는 당위성과 그리고 Web IDL이 무엇인지에 대해서 설명드려야 하겠죠.


우선 첫번째 JavaScript API를 설계해야 하는 이유부터 말씀드리겠습니다.

  • JavaScript는 스크립트 언어라는 특성 상 type 선언 없이 변수를 생성하고 유연한 형 변환(type casting)을 통해 컴퓨터 언어의 지식이 부족한 초급 개발자들도 쉽게 사용할 수 있을 뿐만 아니라 함수형 언어의 특성을 갖는 객체 지향 언어로서 확장성과 유연성이 좋아 고급 개발자에게도 유용한 언어입니다.

  • 웹을 지원하는 모든 형태의 기기에서 동작하는 클라이언트 앱 외에도 Google이 만든 V8 엔진을 이용해 만든 Node.JS라는 서버 프레임워크에서도 동작하는 서버 앱 그리고 Mongo DB라는 NoSQL DB에서도 사용 가능한 매우 범용적인 개발 언어입니다.

  • 웹에서 동작하는 앱은 대부분 브라우저의 개발자 모드 (F12 키)를 통해 JavaScript code를 살펴 볼 수 있고 이런 수고가 아니라도 구글링을 통해 다양한 라이브러리 혹은 코드 조각 (code snippet)를 검색할 수 있습니다. 원하는 기능의 대부분을 단순히 복사 & 붙여 넣기로도 구현할 수 있습니다. 

  • 이렇게 코드를 훔쳐 사용하기 쉬운 구조 때문에 어차피 훔쳐 사용할 거라면 이걸 하기 위해 분석하는 수고를 덜어주는 마음씨 착한 개발자의 도움으로 인해 재사용하기 쉬운 형태로 만든 라이브러리가 매우 많이 있습니다. 물론 대부분 공짜구요. 이때 좋은 라이브러리는 API만 알아도 기능을 사용할 수 있도록 사용자에게 제공합니다. 코드를 모두 읽어 봐야 한다면 '복사 & 붙여넣기'보다 나은게 없으니까요.

  • API는 Application Programming Interface의 약자로 말 그대로 앱을 프로그래밍하는 인터페이스, 즉 앱에서 수행될 기능을 짜는 방법이라고 볼 수 있습니다. JavaScript 앱을 작성할 때 API의 도움을 받으면 적은 노력으로 원하는 기능을 구현할 수 있습니다.

  • API에 이용해 앱을 짜는데 자신감이 붙었다면 (게다가 혹시 개발 비 명목으로 돈도 벌었다면) 라이브러리가 제공하지는 않지만 앱을 짜는데 필요했던 기능을 API로 설계해서 추가해보면 어떨까요? 이런 너그러운 마음씨가 당신이 했던 수고를 반복하지 않고 당신이 알지 못하던 새로운 기능을 개발할 수 있도록 도울 겁니다. 당신이 사용했던 라이브러리를 개발한 원 저자가 그랬듯이 말입니다.

  • 좋은 앱은 많은 사람들에게 유용한 기능을 제공해 주지만 모든 사람들을 만족시켜 줄 수 없습니다. 사람들의 취향이란 사람들의 숫자 만큼이나 다양하니까요. 그들에게 DIY (Do It Yourself) 할 수 있도록 해 준다면 메일 함에 쌓이는 다양한 수정 요구사항에서 조금은 해방될 수도 있습니다. (그렇다고 버그에서 해방되는 걸 의미하지는 않습니다.)

  •  미래는 API의 시대가 될 것이라고 예견하는 사람들이 있습니다. (당연히 저도 그런 사람 중 하나입니다.) 소프트웨어 교육이 보편화 되고 있기에 대부분의 사람들이 프로그래밍을 할 수 있게 되리라고 보기 때문이죠. 따라서, 머지않아 단순히 API를 활용해 앱을 짜는 것은 더 이상 신기한 일이 되지 않겠지만, 새로운 기능을 제공하는 API를 만들어서 제공하는 역할은 여전히 전문가의 영역에 남아 있을 것입니다.

쓰다 보니 길어져서 한줄 요약하면 다음과 같습니다.

JavaScript는 시장이 크고 유용성이 높은 개발 언어로 API를 설계할 줄 알면 전문가로 대접 받을 수 있다. - 웹 오브 띵크

 

동기 부여가 되는 이야기를 한건지 모르겠지만 혹여 여기까지 읽으셨다면 필자는 여러분들이 API를 설계하기로 충분히 세뇌(?) 되었다고 생각하고 두 번째인 Web IDL에 대해 설명드리겠습니다.


일단 Web IDL 에 관련된 문서가 있는 아래 링크를 한번 방문해 보시죠. 


http://www.w3.org/TR/WebIDL/


영문으로 된 문서는 무조건 번역기를 돌리다 보니 무슨 소린 줄 모르시겠다는 분들과 영어에 자신있으나 배경 지식이 없어 이해가 안가시는 분들을 위해 요약 (abstract)을 한글로 번역해 보았습니다.


이 문서는 Web IDL 이라는 인터페이스 정의 언어를 정의하는데 웹 브라우저에서 구현될 것을 의도한 인터페이스들을 설명하는데 사용될 수 있다. Web IDL은 웹 플랫폼에서 사용되는 공용 스크립트 오브젝트들의 동작을 보다 읽기 쉽도록 명세화하기 위한 수많은 기능들을 가진 IDL의 변종이다. Web IDL로 명시된 인터페이스들이 어떻게 ECMAScript 실행 환경 내에서 구성되는 지에 대해서도 상세화 되어 있다. 이 문서는 이미 배포된 스펙 문서를 어떻게 구현할지에 대한 가이드을 개발자에게 제공하고 새로 배포하는 스펙 문서의 인터페이스의 구현체가 서로 호환되도록 보장하기 위해 참조하기 위함이다. - W3C Web IDL Abstract


등장한 용어들에 대해 간단히 설명 드리면 다음과 같습니다. 또 의아한 용어가 있다면 댓글로 남겨주시기 바랍니다. :-)

  • "정의" - Justice가 아닌 Definition 입니다. 전 공대 출신이니까요. ;-)
  • "웹 브라우저", "웹 플랫폼" - 모두 여러분이 웹 세계를 탐험하는 도구(앱)를 의미하나 브라우저는 사용자 관점에서 플랫폼은 개발자 관점에서 바라보는 겁니다.
  • "오브젝트" - 한글로는 객체라고 번역되나 프로그램에서 기능을 수행하는 단위라고 이해하면 됩니다.
  • "ECMAScript" - 여기서는 JavaScript와 동의어라고 이해하면 됩니다.
  • "스펙" - 대학이나 취업 시 적어내는 이력서가 아니라 정의한 내용을 적은 규격서입니다. 
  • "구현체" - 코딩을 완료해서 동작하는 프로그램을 의미합니다. 


발췌한 요약문에서 빨간 색 밑줄친 부분은 주의 깊게 봐주셨으면 합니다. 제가 Web IDL로 JavaScript API를 설계하는 데 사용하는 이유를 말해주는 대목이니까요. 이 내용에 대해 이후 포스팅에서 좀 더 자세하게 설명드리겠지만 먼저 간략히 말씀드리면 JavaScript 언어의 유연성에 대한 부작용으로 인해 API를 구체적으로 명세하기 어려운 점이 발생합니다. 이렇게 API의 동작을 명확하게 알려주지 못한다면 사용하는 사람 뿐 만 아니라 API를 구현하는 사람에게도 혼란을 초래하기 때문에 구체적인 명세화 방식이 꼭 필요합니다.


게다가 이외에도 Web IDL를 사용하면 추가 이득을 얻을 수 있는데 그것이 바로 API 설계 검증 및 문서화에 대한 자동화입니다. 아래 링크의 widlproc이라는 도구를 통해 설계자는 설계의 유효성을 검증하고 손쉽게 문서를 생성할 수 있습니다. 이 방법 역시 추후 포스팅으로 설명드리겠습니다.


widlproc: https://github.com/dontcallmedom/widlproc  

 


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


감사합니다.


"생각의 웹"입니다.


아빠의 공작소(Daddy's Lab.)에서 킥스타터를 통해 펀딩 중인 프로젝트 게임튜브를 이용해서 간단한 그네 게임을 만든 사례를 소개합니다. 


(참고로 breadino는 아두이노 호환 마이크로 컨트롤러로 게임튜브의 핵심 모듈 중 하나입니다. ^^)


아래 슬라이드는 춘향전에 등장하는 유명한 소재인 그네 뛰기를 모티브로 여기에 필요한 수학/물리 법칙들을 이용해 게임튜브와 스크래치를 통해 구현하는 것을 설명하고 있습니다.

  




게임튜브 프로젝트가 성공적으로 펀딩되어 많은 분들이 자녀들과 함께 스크래치 프로그래밍을 즐기시길 바라며 혹시 이 포스팅에 대해 보다 자세한 내용이 궁금하시면 댓글 남겨 주시기 바랍니다. 보다 상세한 내용의 후속 포스팅으로 찾아 뵙도록 하겠습니다. ^^


마지막으로 게임튜브에 대한 보다 자세한 내용을 원하시면 아래 링크를 참고하시기 바랍니다. 

 

게임튜브 : http://www.gametube4u.com/ 

대디스랩 : http://www.daddyslab.com/

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


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

웹 서비스가 스스로 새로운 웹서비스를 만들어가는 스마트한 IoT 세상을 꿈꾸는 "생각의 웹"입니다.


웹 세상에서 REST API가 Open API의 대세로 자리 매김한지도 꽤 시간이 지났음에도

진정 RESTful API를 설계하는 일이 여전히 쉽지 않습니다.

따라서 이전에 포스트에서 REST API의 성숙도를 표현하는 리처드슨의 성숙도 모델이 있다는 것 소개드린 바 있습니다.


http://webofthink.tistory.com/2


이번 포스트에서는 REST API의 대가인 리처드슨, 아문센 그리고 샘 루비가 오레일리 출판사를 통해 작년 말에 내 놓은 RESTful Web API에서 발췌한 REST API를 설계하는 절차를 소개하려 합니다.


먼저, 발췌한 해당 내용의 스크린 샷을 이미지 슬라이드로 보여 드리죠.


012345678910111213


책에서는 API를 설계하는 서로다른 두 가지 절차를 소개합니다. 첫번째는 두 단계로 이뤄진 요약이고 두 번째는 일곱 단계로 이뤄진 상세한 내용이라고 할 수 있습니다.


전자에 대해 정리하면 다음과 같습니다.


  1.  HTTP 요청에 대한 응답 body에 표현 (representation)으로 사용할 미디어 형태 (media type)을 선택한다. 이 선택으로 말미암아 프로토콜 의미 (protocol semantics) - HTTP 프로토콜 하에서 API의 동작 - 와 어플리케이션 의미 (application semantics) - 표현으로 참조할 수 있는 실제 세계의 사물 -  에 제약을 받게 된다.

  2. 나머지 모든 것을 대응할 수 있는 프로파일 (profile)을 작성한다.

REST API에 대해 설계한 경험이 없다면 이 두 단계로 함축한 것으로는 이해하기가 어려울 것으로 사료됩니다. 이 책을 읽고 포스트를 작성하는 저 스스로도 잘 와닿지 않기 때문입니다. ^^;

이번에는 좀 더 상세한 단계를 설명해 주고 있는 후자에 대해서 살펴 보시죠.

  1.  클라이언트(client) - REST API를 호출할 웹 앱 - 이 알아야 하거나 API에 담고자 하는 모든 정보를 나열한다. 이 정보가 추후 의미 기술 (semantic descriptors)이 되며 계층적 구조를 갖게 됩니다. 예를 들어 '사람'과 같은 오브젝트는 보다 추상적인 '성'과 같은 상세 정보를 갖게 되는데 이런 정보 간 계층이 직관적으로 묶일 수 있도록 합니다. 

  2. API를 위한 상태 전이도 (state diagram)를 그립니다. 이 도식에서 칸은 하나의 표현 - 의미 기술의 일부를 함께 묶은 문서 - 을 나타냅니다. 클라이언트가 이런 표현들을 자연스럽게 찾을 수 있도록 화살표를 이용해 표시합니다. 이 화살표는 HTTP 요청에 따른 상태 전이 (state transitions)이 됩니다.

  3. 의미 기술에 사용한 임의의 용어 (magic strings)를 기존 프로파일(profile)에 존재하는 용어로 대체합니다. 이때 사용한 모든 단어와 두번째 단계에서 그린 상태 전이도에 모두 적용될 때까지 반복합니다.

  4. 프로토콜 의미와 어플리케이션 의미에 부합하는 (compatible) 미디어 형식 (media type)을 선정하거나 필요할 경우 새로 만듭니다. 운이 좋다면 기 정의된 미디어 형식으로 어플리케이션 의미의 상당 부분을 대응할 수 있으며 이때 세 번째 단계로 되돌아 가서 미디어 형식의 용어가 대응하는지 다시 살펴봅니다.

  5. 어플리케이션 의미를 기술하는 프로파일을 작성합니다. 이 프로파일에는 당신만의 용어 (magic string), IANA에 등록된 링크 관계가 아닌 링크 관계들과 미디어 형식에 의해 기술된 용어를 담고 있어야 합니다.

  6.  세번째 단계에서 도출한 상태 전이도를 HTTP 서버로 구현하기 위한 코드를 작성합니다. 클라이언트는 특정 HTTP 요청으로 상태를 전이시키게 되고 그 결과로 응답을 전송받게 됩니다. 이 응답의 표현에는 4번째 단계에서 정의한 미디어 형식과 5번째 단계에서 정의한 프로파일에 대한 링크가 포함되어야 합니다. 

  7.  API를 사용하기 위한 접속 주소가 되는 빌보드 URL를 제공합니다. 또한 개발자를 위한 API 문서, 튜토리얼 및 예제 클라이언트 코드를 제공할 수도 있습니다.

API를 설계하는 일은 사용자를 고려한 UX를 설계하는 일처럼 어려운 일입니다. 특히, API를 사용하는 주체가 사람 뿐 아니라 기계일 경우는 더욱 그렇습니다.

프로그래머블 웹이 현실이 되고 인터넷에 연결된 IoT 기기가 시장에 본격적으로 등장하면서 진정 스마트한 기기를 만들기 위해서는 스마트한 API를 만들 수 있는 기술이 필요합니다.

이 설계 방법이 스마트한 웹 세계를 만들 것이라 기대해 봅니다.
감사합니다. 


  1. 참치 2014.07.07 14:06

    좋은 글 감사합니다. 많이 배우고 갑니다.

  2. 생각의 웹 WebofThink 2014.07.08 01:22 신고

    제 부족한 글에 과분한 커멘트 감사합니다. 현재 이 분야를 공부하는 중이라 배운 내용을 종종 공유하려고 합니다. 계속된 관심 부탁드립니다. ^^

안녕하세요.

스크래치를 통해 프로그래밍 세계에 입문하신 분들을 환영합니다.


최신 스크래치인 2.0 버전은 플래쉬 앱으로 만들어져 있어 브라우저를 통해 앱을 만들고 바로 웹을 통해 공개할 수 있습니다. 제가 첫 번째 만든 데모 앱처럼요. ^^


스크래치 프로그래밍에 자신이 붙으셨다면 나만의 아이디어를 실현해 볼 수 있는 재밌는 개발 환경을 소개합니다.


  1. 라즈베리 파이에서 스크래치 프로그래밍 하기
    • 라즈베리 파이는 영국 케임브리지 대학에서 만든 싱글보드 컴퓨터로 우리 돈으로 5만원 내외면 휴대폰 충전기로 동작하는 저전력의 PC 환경을 만들 수 있습니다. (http://www.raspberrypi.org/) 라즈베리 파이의 운영체제 (OS)인 라즈비안에는 스크래치 1.4 버전이 기본 설치되어 제공되니 이 기기에서 스크래치 프로그래밍을 즐겨보는 것도 색다른 즐거움이 될 것입니다.


  2. 아두이노를 스크래치로 프로그래밍 하기
    • 아두이노는 내가 원하는 회로를 구성해 컴퓨터로 제어할 수 있는 마이크로 컨트롤러로 오픈 소스로 만들어져 많은 사용자들을 확보하고 있습니다. (http://ko.wikipedia.org/wiki/%EC%95%84%EB%91%90%EC%9D%B4%EB%85%B8
    • 아두이노는 원래는 C/C++ 언어로 개발하도록 제공되나 스크래치에서 개발할 수 있는 S4A라는 프로젝트가 존재합니다. (http://s4a.cat/) 이 블로그에서는 주로 S4A를 이용하여 스크래치로 개발한 사례를 소개하고자 합니다.



안녕하세요.


이곳에 스크래치 항목을 만들고 첫번째 데모 앱 포스팅 이후 아무런 글을 올리지 않아 고민하던 차에 잘 정리한 블로그가 있어 아래와 같이 링크를 공유합니다.


http://flowingtime.tistory.com/category/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D/%EC%8A%A4%ED%81%AC%EB%9E%98%EC%B9%98


스크래치가 개발 언어로 처음이신 분들에게 도움이 될 만한 내용들로 구성되어 있어 일독을 추천합니다.


감사합니다.

안녕하세요.


웹 API과 IoT의 만남을 주제로 블로깅을 시작한지도 꽤나 시간이 흐른것 같네요.

사실 의도하지는 않았지만 연구를 진행해가면 갈수록 더욱 재밌는 것들을 발견하게 되어 너무나 기쁩니다. 

이번 포스팅에서 소개하고자 하는 내용은 node.js에서 Arduino를 제어하는 API를 제공하는 duino입니다.  (여담입니다만 이 글을 Internet of Things 목록에 넣어야 할지 아니면 JavaScript API 목록에 넣어야 할지 한참 고민했네요. ;-) )


https://github.com/ecto/duino


자세한 소개가 링크에 나와 있기는 하지만 아래와 같이 한글로 번역해서 정리하니 참고하시기 바랍니다.

  1. 설치



  2. npm install duino
    

      상기 git hub의 ./src/du.ino 코드를 scatch 도구를 이용해 arduino에 flash

  3. LED 점멸 코드 예제

  4. var arduino = require('duino'),
        board = new arduino.Board({
         device: 'USB0'
    });
    
    var led = new arduino.Led({
      board: board,
      pin: 13
    });
    
    led.blink();
    
      라즈베리파이와 아두이노 연결 시 /dev/ttyUSB0를 통해 serial 통신하게 되어 device attribute에 USB0라고 입력
      MS Windows / MAC 계열에서는 아래 파일로 node_modules/duino/lib/board.js를 대체한 뒤 device 명으로 시리얼 포트가 연결된 COM포트 명 입력 ex) COM4

    board.js




  5. API Signatures (using Web IDL)

  6. // duino uses arduino namespace by default.
    
    enum EmitterType { "data", "connected", "ready" };
    enum Mode {"in", "out"};
    
    dictionary BoardOption {
        DOMString device;
        boolean debug;
    };
    
    dictionary LEDOption {
        Board board;
        DOMString pin = '13';
    };
    
    callback BoardOnCallback = void (optional DOMString msg);
    callback BoardSerialCallback = void (DOMString msg);
    
    [Constructor, Constructor (BoardOption option)]
    interface Board {
    
        const DOMString LOW = '000';
        const DOMString HIGH = '255';  
        void on(EmitterType type, BoardOnCallback cb); 
        void serial(BoardSerialCallback cb);
        void write(DOMString msg);
        void pinMode(DOMString  pin, Mode mode);
        void digitalRead(DOMString pin);
        void digitalWrite(DOMString pin, DOMString val);
        void analogRead(DOMString pin);
        void analogWrite(DOMString pin,DOMString val);
        void delay(unsigned short ms);    
    };
    
    [Constructor, Constructor (LEDOption option)]
    interface LED {
    
        void on();
        void off();
        void blink(unsigned short interval = 1000);
        void fade(unsigned short interval = 2000);
        unsigned short bright();
    };
    
    interface LCD {
      // TODO: See the details at the original link
    };
    
    interface Piezo {
      // TODO: See the details at the original link
    };
    
    interface Button {
      // TODO: See the details at the original link
    };
    
    interface Ping {
      // TODO: See the details at the original link
    };
    
    interface Servo {
      // TODO: See the details at the original link
    };
    
    

    Web IDL에 관한 문법은 http://www.w3.org/TR/WebIDL/ 를 참고하시기 바랍니다.


    API를 사용하는데 도움이 되시기 바랍니다.

    감사합니다. ;-)


안녕하세요,


이전에는 DOM 객체 제어 (manipulation) 및 server 부하(workload)를 줄이기 위한 간단한 스크립트 언어에 불과했던 JavaScript가 AJAX를 이용한 Rich Internet Application (RIA) 등장으로 활용도가 커지기 시작했습니다. 이와 함께 AJAX의 XML 대신 JSON (JavaScript Object Notation)을 이용해 데이터를 교환하는 방식이 개발자들에게 인기를 얻고, HTML5 표준화로 인해 다양한 기능을 JavaScript를 통해 사용할 수 있게 되었죠.

또한 구글이 만든 JavaScript 엔진인 V8에 기반한 서버 개발을 위한 플랫폼인 Node.JS 등장으로 인해 client 뿐 아니라 server 개발을 아우르는 언어로 각광받기 시작했습니다.


현재 JavaScript를 표준화를 담당하고 있는 단체인 ECMA에서는 몇가지 JavaScript 언어의 취약점을 보완해 ECMAScript 5까지 내놓았으나 여전히 기존 언어들에 비해 부족한 면이 많습니다.


아래 링크를 통해 소개할 RequireJS는 Node.JS에서 기본적으로 채택한 모듈화 방식이며 client 개발 시에도 사용이 가능한 library가 제공되어 대형 web app 개발에도 사용되고 있습니다.


http://helloworld.naver.com/helloworld/591319


JavaScript는 매우 자유롭고 유연한 언어이지만, 코드의 크기가 커지면 관리하기가 힘들어지는 단점이 있기 때문에 되도록 상기 링크의 RequireJS를 이용해서 개발하는 걸 권고합니다.


현재 ECMA에서도 이와 유사한 형태의 모듈화에 대한 표준화가 진행 중이니 머지 않은 미래에 JavaScript 기본 기능으로써 제공되리라 봅니다.


감사합니다. 

+ Recent posts