원문 : http://www.ibm.com/developerworks/webservices/library/ws-restajax/index.html?ca=drs-

<div class="information"> 저자 : Shailesh K. Mishra (shailekm@in.ibm.com), Software Engineer, IBM </div>

2007년 7월 5일

RESTful웹서비스는 REpresentational State Transfer (REST) 아키텍처 스타일을 사용하는 웹서비스이다. 이 글은 간단한 프록시 서블릿과 비동기 XML과 자바스크립트(Ajax) 기반의 클라이언트를 사용하여 RESTful웹서비스를 작성하는 한가지 방법을 보여준다.

소개#

Roy Fielding은 그의 논문에서 현재 웹 아키텍처를 위한 기초적인 개념으로 REST를 언급했다. 그는 REST를 위해 다음과 같은 기준을 정립했다.

  • 현대 웹 아키텍처를 모델링하기 위한 제약들
  • REST원리는 HTTP와 URI 스펙에 적용된다.
  • HTTP의 진화로 볼수 있다.

REST의 중요한 차이점은 프로토콜이 아닌 아키텍처 스타일이라는 것이다. 웹서비스를 위해, W3C는 다음처럼 웹서비스를 정의했다.

<div> "A Web service is a software system identified by a URI, whose public interfaces and bindings are defined and described using XML. Its definition can be discovered by other software systems. These systems may then interact with the Web service in a manner prescribed by its definition, using XML based messages conveyed by internet protocols." (See Resources for a link to the source of this excerpt.) </div>

상식적으로 웹서비스는 장비 대 사람간의 통신에 반대되는 장비 대 장비의 통신을 위한 수단이라고 알려져 있다. RESTful 웹서비스는 REST 아키텍처 스타일을 사용하는 웹서비스이고 다음 섹션에서 예제를 사용하여 RESTful 웹서비스를 빌드하는 방법을 보여준다. 이 예제를 이해하기 위해, Ajax를 이해하는 것이 중요하다.

RESTful 웹서비스 만들기#

RESTful웹서비스를 만들기 위해서 먼저 웹서비스로 나타내고자 하는 모든 자원을 확인할 필요가 있다. 자원의 예로는 종업원 목록, 종업원 상세정보, 구매 주문 등등이 있다. REST에서 모든 자원은 URI에 의해 확인된다. 그래서 모든 자원을 위한 유일한 형태의 URL을 결졍할 필요가 있다. 예를 들어, 종업원 목록은 http://www.employee-details.com/employees-list 와 같은 유일한 형태로 확인될 수 있다. 종업원 상세정보는 http://www.employee-details.com/employees/01234 와 같은 URI로 표현될 수 있다.

자원을 가져오고 변경하기 위해 HTTP의 GET, PUT, POST 그리고 DELETE를 사용하라. 더 많은 관련 정보를 위한 자원에 대한 표시로 하이퍼링크를 제공하라. 자원을 위한 데이터를 요청하고 응답받기 위한 형태를 명시하라.

그림 1은 RESTful 웹서비스로 상호작용하는 것을 보여준다.

그림 1. RESTful 웹서비스를 사용한 상호작용

1.gif

RESTful 웹서비스 구현하기#

HTTP 서블릿을 사용하여 RESTful 웹서비스를 구현할 수 있다. 이 글은 회사의 종업원에 대한 상세정보를 제공하는 더미형태의 서비스를 사용한 구현체를 보여준다. 종업원 목록에 대한 자원은 논리적인 URI인 http://localhost:9080/AJAX_REST_Demo/RESTDemoServlet/employee-list 를 사용하여 표현된다. 이 서비스가 HTTP GET으로 호출되면, 리스트 1에서 보여주는 것과 같은 종업원의 목록을 반환한다.

리스트 1. HTTP GET으로 호출된 종업원 목록

<?xml version='1.0' encoding='UTF-8'?>
<p:Employees xmlns:p='http://www.employee-details.com'>
  <Employee id='00345'  href='/employees/00345'/>
  <Employee id='00346'  href='/employees/00346'/>
  <Employee id='00347'  href='/employees/00347'/>
  <Employee id='00348'  href='/employees/00348'/>
</p:Employees>

유사하게, 종업원의 상세정보는 http://localhost:9080/AJAX_REST_Demo/RESTDemoServlet/employee/0124 와 같은 논리적인 URI로 표현될 수 있다. 서비스가 HTTP GET으로 호출되면, 리스트 2에서 보여주는 것과 같은 종업원 상제정보를 반환한다.

리스트 2. HTTP GET으로 호출된 종업원 상세정보

<?xml version='1.0' encoding='UTF-8'?>
< EmpDetail xmlns:p='http://www.employee-details.com'>
  <Emp-ID>00345</Emp-ID>
  <Name>David Henry</Name>
  <Department>Finance</ Department >
</p:EmpDetail>

리스트 3은 서블릿 코드를 보여준다. 여기서는 모두 하드코딩되었지만 실시간 RESTful 웹서비스가 되도록 데이터베이스와 상호작용하는 형태로 확장하는 것은 지극히 쉽다.

리스트 3. 서블릿 코드

public class RESTDemoServlet extends HttpServlet implements Servlet {
  /* (non-Java-doc)
   * @see javax.servlet.http.HttpServlet#HttpServlet()
   */
  Map map = new HashMap();

  /* (non-Javadoc)
   * @see javax.servlet.GenericServlet#init()
   */
  public void init() throws ServletException {
    // TODO Auto-generated method stub
    super.init();

    Employee emp0 = new Employee("David""Finance");
    Employee emp1 = new Employee("Smith""HealthCare");
    Employee emp2 = new Employee("Adam""Information technology");
    Employee emp3 = new Employee("Stephan""Life Sciences");

    map.put("00345", emp0);
    map.put("00346", emp1);
    map.put("00347", emp2);
    map.put("00348", emp3);
  }

  /* (non-Java-doc)
   * @see javax.servlet.http.HttpServlet#doGet
   (HttpServletRequest arg0, HttpServletResponse arg1)
   */
  protected void doGet(HttpServletRequest arg0, HttpServletResponse arg1throws ServletException, IOException {
    // TODO Auto-generated method stub
    arg1.setContentType("text/xml");
    PrintWriter out = arg1.getWriter();
    System.out.println(map);
    if (arg0.getPathInfo() != null) {
      String EmpId = arg0.getPathInfo().substring(1, arg0.getPathInfo().length());
      System.out.println(EmpId);

      out.write("<?xml version='1.0' encoding='UTF-8'? >" "\n");
      out.write("<p:EmpDetail xmlns:p='http://www.employee-details.com' >" "\n");
      out.write("<Emp-ID>" + EmpId + " </Emp-ID >" "\n");
      out.write("<Name>" ((Employeemap.get(EmpId)).name + " </Name >" "\n");
      out.write("<Department >" ((Employeemap.get(EmpId)).dept + " </Department >" "\n");
      out.write("</p:EmpDetail >" "\n");
      out.flush();
    else {
      out.write("<?xml version='1.0' encoding='UTF-8'? >" "\n");
      out.write("<p:Employees xmlns:p='http://www.employee-details.com' >" "\n");
      out.write("<Employee id='00345' href='http://localhost:9080/AJAX_REST_Demo/RESTDemoServlet/employees/00345'/ >" "\n");
      out.write("<Employee id='00346' href='http://localhost:9080/AJAX_REST_Demo/RESTDemoServlet/employees/00346'/ >" "\n");
      out.write("<Employee id='00347' href='http://localhost:9080/AJAX_REST_Demo/RESTDemoServlet/employees/00347'/ >" "\n");
      out.write("<Employee id='00348' href='http://localhost:9080/AJAX_REST_Demo/RESTDemoServlet/employees/00348'/ >"  "\n");
      out.write("</p:Employees >");
      out.flush();
    }
  }

  /* (non-Java-doc)
   * @see javax.servlet.http.HttpServlet#doPost
   (HttpServletRequest arg0, HttpServletResponse arg1)
   */
  protected void doPost(HttpServletRequest arg0, HttpServletResponse arg1throws ServletException, IOException {
    // TODO Auto-generated method stub
  }
}

다음 섹션에서, RESTful 웹서비스를 위한 Ajax기반의 클라이언트를 작성하는 방법을 배워보자.

RESTful 웹서비스를 위한 Ajax 클라이언트 작성하기#

앞서 언급했듯이, Ajax는 비동기 자바스크립트와 XML을 나타낸다. 그래서 HTTP기술로 언급된다. Ajax에서 핵심 기술은 페이지 갱신없이 서버에 대한 비동기 통신에 집중된다. XMLHTTPRequest 객체는 서버에 비동기 GET, POST, PUT, DELETE를 허용한다. 사용자에게는 어떤것도 보여주지는 않는다. 달리 말하면, 보여지는 상태 메시지가 없다. 상태를 변경하고자 핸들러 메소드를 명시할 수 있고 핸들러는 다음 요청시 알려진다.

  • 초기화
  • 시작
  • 반환하도록 처리중
  • 완전히 종료

리스트 4는 위 RESTful 웹서비스를 위한 클라이언트처럼 작동하는 Ajax기반의 HTML페이지를 위한 코드를 보여준다.

리스트 4. Ajax 기반의 HTML 페이지를 위한 코드

<SCRIPT language="javascript" type="text/javascript" >
var req=null;
//This function initializes XHR
function initXHR() {
 if (navigator.appName.indexOf("Microsoft"> -) {
   try{
      req=new ActiveXObject("Microsoft.XMLHTTP");
     }catch(e1){
      alert("failed to create XHR in IE");
     }
   }else{
       try{
            req=new XMLHttpRequest();
           }catch(error){
            alert("failed to create XHR in FireFox");
           }
        }
}
//get an employee detail
function getEmpDetails(Empurl){
 initXHR();
 req.open("GET",Empurl, true);
 req.onreadystatechange=handleEmpDetailResponse;
 req.send(null);

}

//get employee list
function getEmployeeList(listurl){
 initXHR();
  req.open("GET", listurl, true);
  req.onreadystatechange=handleEmpListResponse;
  req.send(null);
}
function handleEmpDetailResponse(){
 //if Response is complete

  if(req.readyState==4){
   //response is OK
    if(req.status==200){
     var str="";
  var response=req.responseXML;
  var root=response.documentElement;
  for(i=0;i <root.childNodes.length;i++){
       if(root.childNodes[i].nodeType != 1continue;
        var name=root.childNodes[i].nodeName;
        var value=root.childNodes[i].firstChild.nodeValue;
        str=str+name+"--- >"+value+" <br >";
      }
   document.getElementById("emp-div").style.display="";
   document.getElementById("emp-detail-div").innerHTML=str;
  }else{
      document.getElementById("messageDiv").innerHTML=" <SPAN style='color:#FF0000; 
          font-size:12pt; text-decoration:none;' <Invalid URL or PartId </SPAN >";
  }
  req.abort();
   }
}

function handleEmpListResponse(){
 //if Response is complete

  if(req.readyState==4){
   //response is OK
    if(req.status==200){
     var pstr="";
     var response=req.responseXML;
     var root=response.documentElement;
     for(i=0;i <root.childNodes.length;i++){
      if(root.childNodes[i].nodeType != 1continue;
       var id=root.childNodes[i].getAttribute("id");
       var href=root.childNodes[i].getAttribute("href");
         pstr=pstr+"EmpId"+"--- >"+id+"&nbsp; <input type='button' value='
            GetEmpDetails' onclick="+'"'+"getEmpDetails('"+href+"')"+'"'+">"+" <br >";
       }
   document.getElementById("emp-list-div").style.display="";
   document.getElementById("emp-list").innerHTML=pstr;
  }else{
   document.getElementById("messageDiv").innerHTML=" <SPAN style='color:#FF0000; 
          font-size:12pt; text-decoration:none;' >Invalid Employee ID. </SPAN >";
  }
    }
}
</SCRIPT >
<center >
<input type="button" value="getEmployee-List" onclick="getEmployeeList
    'http://localhost:9080/AJAX_REST_Demo/RESTDemoServlet/employee-list')" > <br > <br >
<div id="messageDiv" > </div >
<div id="emp-list-div" style='color:#FF0000; font-size:12pt; text-decoration:none; 
      display:none;' >Employee List : </div > <br >
<div id="emp-list" > </div > <br > <br >
<div id="emp-div" style='color:#FF0000; font-size:12pt; text-decoration:none; 
      display:none;' >Selected Employee Detail : </div > <br >
<div id="emp-detail-div" > </div >
</center >

리스트 4에서 사용자가 getEmployee-List 버튼을 클릭하면, XML HTTP 요청이 서버로 전달된다. 핸들러 함수인 handleEmpListResponse는 readyState 를 변경하도록 XML HTTP요청에 명시된다. 서버가 응답을 완료(readyState = 4)하고 응답이 OK라면, XML파싱해서 종업원 목록을 보여주기 위한 페이지의 문서 객체 모델(DOM)에 추가할것이다. 유사하게 사용자가 GetEmpDetails 버튼을 클릭하면, 핸들러 함수인 handleEmpDetailResponse는 서버에서 전달된 XML응답을 다루고 특정 종업원의 상세정보를 보여주기 위한 페이지 DOM으로 변경할것이다.

결론#

이 글에서, 서블릿을 사용하여 RESTful 웹서비스를 작성하는 방법과 Ajax기반의 클라이언트를 사용하는 방법을 배웠다. RESTful 웹서비스를 쉽게 이해하고 구현할수 있길 바란다. 좀더 유용한 정보를 위해서는 아래의 참조문서 섹션을 보라.

참조문서#

Learn

Get products and technologies

  • Innovate your next development project with IBM trial software, available for download or on DVD.

Discuss

Add new attachment

Only authorized users are allowed to upload new attachments.

List of attachments

Kind Attachment Name Size Version Date Modified Author Change note
gif
1.gif 12.2 kB 1 06-Jul-2007 09:32 DongGukLee
« This page (revision-6) was last changed on 06-Jul-2007 17:37 by DongGukLee