REST(REpresentational State Transfer)는 웹 서비스를 자원으로 여기는 일종의 아키텍처 원리로 웹 서비스의 URL로 고유하게 식별할 수 있다. RESTful 웹 서비스의 주요 특성은 다양한 조작을 호출하는 과정을 표시하기 위해 HTTP를 명시적으로 사용한다는 점이다.
REST에서는 다음과 같은 일반적인 CRUD 조작을 HTTP 프로토콜을 사용하여 처리하는 것이 기본 설계 원칙이다.
- POST - 자원 작성
- GET - 자원 검색
- PUT – 자원 업데이트
- DELETE - 자원 삭제
REST 서비스의 주요 장점은 다음과 같다.
- REST 서비스는 기본적인 HTTP 프로토콜을 기반으로 하기 때문에 Java, .NET, PHP 등과 같은 다양한 플랫폼 간에 재사용할 수 있는 가능성이 높다.
- REST 서비스는 복잡한 SOAP XML 대신 기본적인 XML을 사용하므로 쉽게 사용할 수 있다.
REST 기반 웹 서비스는 점차 백엔드 엔터프라이즈 서비스에 통합되어 가는 추세이다. SOAP 기반 웹 서비스와 비교하여 REST 기반 웹 서비스의 프로그래밍 모델은 보다 단순하며 SOAP 대신 기본적인 XML을 사용하기 때문에 복잡한 직렬화와 비직렬화가 줄어들 뿐만 아니라 같은 작업을 하기 위해 추가로 써드파티 라이브러리를 사용해야 할 필요성이 감소한다.
Apache CXF, RESTlet, REST를 지원하는 JAX-WS API, Spring 3.0 이상에서 사용 가능한 Spring MVC REST 지원과 같은 RESTful 서비스를 빌드하는 데 필요한 Java 기반 프레임워크는 개발과 XML 구성이 복잡하고 일반적으로 배우는 데 시간이 오래 걸린다. 또한, 이러한 프레임워크는 종속 관계에 있는 jar 파일 특정 버전과의 종속성으로 인해 애플리케이션 서버 환경을 교차하여 통합하기가 매우 어렵다. 또한, Apache CXF, JAX-WS와 같은 일부 프레임워크에서는 SOAP와 REST 서비스를 모두 지원하려고 하기 때문에 이러한 프레임워크는 패키징이 복잡해지고 이 때문에 성능이 영향을 받게 되는 경향이 있다.
따라서 여기에서는 비즈니스 서비스를 REST 형태의 서비스로 표시할 수 있는 보다 단순한 확장 가능한 프레임워크를 제안한다. 이 프레임워크는 매우 경량이며 쉽게 이해할 수 있는 표준 Front Controller 패턴을 사용한다. 또한, 이 프레임워크는 확장하여 ESB 등과 같은 기타 통합 패턴이나 API를 통해 백엔드 서비스와 통합할 수 있으며 사용자 정의 직렬화 프로그램이나 JAXBXML 또는 오브젝트 - XML 변환 도구를 사용하여 데이터 교환 모델을 쉽게 구성할 수 있다.
이 기사에서는 이러한 프레임워크를 자세하게 살펴본다.
J2EE 애플리케이션에서는 Java API나 서비스가 Stateless 세션 Bean API(Session Façade 패턴)나 SOAP 웹 서비스 형태로 표시된다. .NET 또는 PHP 등과 같은 비Java 기술을 사용하여 이러한 서비스를 클라이언트 애플리케이션과 통합하는 경우에는 SOAP 웹 서비스를 처리하기가 매우 어렵고 개발에 필요한 노력도 많이 들어간다.
여기에서 설명하는 방식은 일반적으로 재사용 가능하지만 SOAP를 사용하는 데 들어가는 개발 비용과 상호 호환성 문제로 인해 신속하게 통합하기 어려운 다양한 서비스가 있는 조직 내에서 서비스를 통합하기 위한 용도로 사용된다. 또한, 내부 거버넌스 조직에서 서비스를 엔터프라이즈 ESB나 EAI에서 표시되지 않도록 하는 경우에는 2개의 다양한 기술 서비스를 지점간 방식으로 통합하기는 어렵다.
예를 들면, 통신 IT 환경에서는 다음과 같은 경우가 해당한다.
- SOAP 웹 서비스나 EJB API로 표시되는 특정 범주의 SMSC에 SMS를 전송하는 경우, 또는
- MQ나 JMS 바인딩을 사용하여 ESB 전체에 표시되는 데이터베이스 저장 프로시저로 표시되는 CRM 애플리케이션(예: Oracle CRM)에서 서비스 요청을 작성하는 경우, 또는
- SMSGateway를 사용하는 모바일 SMS에서 판매자를 위해 판매 주문 요청을 작성하는 경우
위에 언급한 서비스를 비Java 애플리케이션에서 사용하면 SOAP 웹 서비스를 사용하여 통합하기가 어려워지고 개발 기간이 늘어나게 된다.
이러한 새로운 방식은 Java 서비스를 REST 형태의 자원으로 표시할 수 있도록 프레임워크 형태로 구현된다. 이 방식은 Struts 프레임워크 방식과 유사하며 아래에 있는 다이어그램에 표시된 것과 같은 컴포넌트로 구성된다.
그림 1. 아키텍처 개요
아키텍처는 요청을 수신하여 해당 클라이언트에 응답을 하는 중앙 지점으로 작동하는 Front Controller로 구성된다. Front Controller는 프레임워크를 처리하는 로직이 있는 ActionController에 위임하여 요청을 처리한다. ActionController는 요청의 유효성을 검증한 후, 이 요청을 해당 조치에 맵핑하고 이 조치를 호출하여 응답을 생성한다. 다양한 헬퍼 서비스를 제공하여 개별 조치와 ActionController에서 사용할 수 있는 로깅 및 예외 처리와 요청을 처리를 수행한다.
다음 다이어그램에는 프레임워크의 다양한 컴포넌트와 이 컴포넌트 간의 관련성이 표시되어 있다.
그림 2. 프레임워크 컴포넌트
아래에서 다양한 컴포넌트를 설명한다.
이 컴포넌트는 서비스를 호출하는 데 필요한 클라이언트 애플리케이션이다. HTTP 메소드를 지원하는 한 이 컴포넌트는 Java 기반 클라이언트나 다른 클라이언트가 될 수 있다.
이 컴포넌트는 로깅 및 예외 처리와 같이 프레임워크에서 필요로 하는 유틸리티 서비스와 구현에 필요한 모든 공통 기능이나 상수를 말한다. Log4j 구현을 사용한 Apache Commons 로깅은 샘플 코드에서 사용된다.
프레임워크에서는 Front Controller 패턴을 사용하여 중앙 집중식으로 요청을 처리하며 이 Java 서블릿 컴포넌트를 사용하여 입력 요청을 처리한다. 이 컴포넌트는 GET, PUT, POST 및 DELETE와 같은 공통 HTTP 메소드를 지원한다.
이 컴포넌트는 서비스 로드, 프레임워크 구성, 요청의 유효성 검증, 구성된 REST 조치를 사용한 요청 맵핑 및 조치 실행과 같은 핵심 기능을 관리하는 중요한 프레임워크 제어기이다.
이 컴포넌트는 프레임워크 구성과 다양한 REST 서비스 구성을 런타임 시에 로드하고 캐시하는 기능을 담당한다. RESTActionController는 이 컴포넌트를 사용하여 호출할 올바른 조치를 식별하고 입력 요청의 유효성을 검증하여 요청을 처리한다.
이 컴포넌트는 구성 파일에 지정된 REST 조치 맵핑을 저장한다. 맵핑은 주로 클라이언트에서 호출하는 URI와 처리 기능을 수행하는 조치 클래스로 구성된다.
이 컴포넌트는 REST 조치를 실행하는 데 필요한 모든 기능을 캡슐화한다. 이 컴포넌트는 요청과 응답 처리 기능을 제공하여 개발자는 실제 비즈니스 로직 구현만을 코드화하면 되도록 도움을 준다. 이 컴포넌트는 Action 컴포넌트의 특정 프로토콜에 적합한 요청과 응답 오브젝트를 숨긴다. 따라서 이 컴포넌트를 이용하면 POJO와 같은 것을 독립적으로 테스트할 수 있다. 또한, 이 컴포넌트는 구성된 XML 바인딩 API를 기반으로 Java 비즈니스 오브젝트를 XML로 그리고 XML을 Java 비즈니스 오브젝트로 쉽게 변환할 수 있도록 XML 바인딩 서비스를 처리하는 기능을 제공한다. RESTActionController는 이러한 컴포넌트를 동적으로 구성하여 Action 컴포넌트에 제공한다.
이 컴포넌트는 Java XML 바인딩 메커니즘을 캡슐화하고 일정한 인터페이스를 제공하며 Java 비즈니스 오브젝트를 XML로 변환하거나 XML을 Java 비즈니스 오브젝트로 변환한다. 이 컴포넌트를 이용하면 표준 프레임워크 인터페이스를 구현하여 JAXB, SDO, Castor 등과 같은 모든 XML 바인딩 메커니즘을 구성할 수 있다. 기본적으로 이 컴포넌트는 즉시 사용할 수 있는 XMLEncoder와 XMLDecoder를 지원한다.
이 컴포넌트는 프레임워크와 서비스 구성으로 이루어진다. REST 서비스는 개발되는 대로 서비스 구성 파일에 추가될 수 있다. 프레임워크 구성은 정기적으로 변경될 필요가 없는 XML 바인딩 서비스와 로깅으로 구성된다.
일반적인 POST 요청을 처리하기 위해 이러한 컴포넌트는 다음과 같은 상호 작용을 한다.
그림 3. 컴포넌트 상호 작용
위에서 살펴본 바와 같이 REST 서비스 구성은 초기에 로드되어 RESTConfiguration 컴포넌트에 캐시된다. REST 서비스의 모든 HTTP 요청을 처리하기 위해 RESTServiceServlet 컴포넌트는 RESTActionController에 요청을 위임하며 이 컴포넌트는 해당하는 맵핑을 차례로 검색하고, 요청의 유효성을 검증하고, 경로와 쿼리 입력을 사용하여 ActionContext 컴포넌트와 Action 클래스(예: createUserAction)를 작성한다. Action 클래스는 백엔드 Java 비즈니스 서비스를 호출하여 처리한다.
이번 섹션에서는 이 기사와 함께 제공되는 프레임워크의 샘플 구현을 살펴본다. 클래스 다이어그램과 다양한 구성 파일 및 코드 스니펫을 통해 위에서 살펴본 디자인이 어떻게 실행되는지 살펴본다.
참고: 샘플 코드는 단지 예제일 뿐이므로 Java 코딩과 관련된 베스트 프랙티스를 모두 준수하는 것은 아니다.
아래에 있는 다이어그램에는 샘플 구현의 클래스가 표시되어 있다. "파란색"으로 표시된 클래스는 프레임워크 외부에 존재한다. 그러나 여기서는 이 클래스가 프레임워크와 구조적으로 어떤 관계에 있는지 나타내기 위해 표시하였다.
그림 4. 클래스 다이어그램
아래에 표시된 바와 같이 "rest-services-config.xml" 구성 파일에는 REST 서비스 표현과 해당 Java Action 간의 맵핑이 포함되어 있다.
Listing 1. REST 서비스 구성
<?xml version="1.0" ?>
<rest-config>
<rest-api id="CreateUserProfile" uri="/Registration/CreateUser" method="POST">
<handler id="RegAction" class="ws.registration.restactions.CreateProfile"/>
</rest-api>
<rest-api id="GetUserProfile" uri="/Registration/GetUser" method="GET">
<handler id="RegAction" class=" ws.registration.restactions.GetProfile"/>
</rest-api>
...
</rest-config>
|
아래와 같이 샘플 구현에서는 XML 바인딩 서비스 구현이 프레임워크 구성 파일인 "rl-config.xml" 파일에서 구성된다. XMLBindingService
인터페이스를 구현하기만 하면 이 파일을 수정하여 모든 사용자 정의 구현을 플러그인할 수 있다.
Listing 2: 프레임워크 구성
# XML Binding Implementation Service # Default implementation ws.rest.xmlbinding.service.impl=ws.rest.xmlbinding.service.impl.XMLEncDecServiceImpl |
로그 구성 파일 "ws_log.properties"는 Log4j 특성과 로그 파일의 위치를 지정한다. 이 로그 구성 파일은 필요에 따라 적절하게 수정할 수 있다.
아래에 표시된 바와 같이 RESTServiceServlet은 web.xml에서 구성되어 <web-app>/restservices/*와 같은 컨텍스트 경로가 있는 모든 요청을 처리한다.
Listing 3: 서블릿 구성
<servlet>
<description></description>
<display-name>RESTServletService</display-name>
<servlet-name>RESTServletService</servlet-name>
<servlet-class>ws.rest.servlet.RESTServiceServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>RESTServletService</servlet-name>
<url-pattern>/restservices/*</url-pattern>
</servlet-mapping>
|
각 REST 자원(예: GetUserProfile)을 처리하기 위해 ActionInterface를 구현하는 해당 조치 클래스가 작성된다. 이 인터페이스에는 Action 클래스를 처리하기 위해
구현해야 하는 "doExecute(ActionContext ctx)" 메소드가 정의되어 있다. ActionContext는 REST 경로 입력이나 쿼리 매개변수 그리고
XMLBindingService 인스턴스를 가져오고 프로토콜의 특성을 Action 클래스에 표시하지 않으면서 XML 출력을 클라이언트에 전송하는 데 필요한 서비스를
제공한다. PathInputs는 해당 URL에 지정된 것과 같은 순서로 되어 있는 경로 값을 포함하고 있는 List 오브젝트이다.
Listing 4: Action 코드 스니펫
public class GetProfile implements ActionInterface {
public void doExecute(ActionContext context) throws Exception {
// Get the value from URL path
String userName = context.getPathInputs().get(0);
// Invoke backend service to retrieve user profile
UserProfileBean bean = getUser(userName);
// Serialize the bean using framework service and send response
String xml = context.getXMLBindingService().serialize(bean);
// Use the ActionContext to generate XML and
context.sendResponse(response, xml);
}
|
Action 클래스는 수퍼클래스에서 사용 가능한 XMLBindingService를 사용하여 XML 출력을 생성하는 기능을 담당한다. 샘플 구현의
ws.registration.restactions.GetProfile 클래스를 확인하자. 또한, 사용자 정의 처리에 필요한 경우에는 ActionContext도 특정 프로파일에 맞는 HttpServletRequest와 HttpServletResponse 오브젝트를
제공할 수 있다. 또한, ActionContext는 경로 값 외에 URL 매개변수를 제공한다.
샘플 코드에서는 java.beans.XMLEncoder와 java.beans.XMLDecoder 클래스를 사용하여 Java XML 바인딩 구현을 작성한다. XML Binding 서비스 구현은
JavaBean 오브젝트를 받아서 위에 있는 엔코더와 디코더의 해당 XML 표현으로 변환한다. JAXB 구현이 필요하면
ws.rest.xmlbinding.service.XMLBindingService 인터페이스를 구현하는 구현 클래스를 개발할 수 있다.
샘플 코드 배포판에는 Tomcat 컨테이너에서 전개할 수 있는 샘플 "RESTWS.war" 파일이 들어 있다(Apache Tomcat 버전 6.0.20에서 테스트함). JDK는 버전 1.5 이상이 필요하다.
애플리케이션이 정상적으로 전개되면 아래와 같이 브라우저에서 다음 URL을 입력한다. http://localhost:8080/RESTWS/html/CreateProfile.html
그림 5. 프로파일 서비스 입력 작성
이 페이지는 REST 서비스를 호출한다.
POST <url-prefix>/Registration/CreateProfile |
<string></string> 태그에 지정된 XML 값을 수정할 수도 있다.
참고: XML 구조는 사용한 JavaBean 오브젝트와 Java XML 직렬화 기술에 따라 달라진다.
Submit 단추를 클릭하면 백엔드 서비스 호출을 표시하는 Action 클래스에서 성공 메시지가 표시된다. ws_log.log 파일에서 디버그 메시지를 확인할 수 있다.
그림 6. 프로파일 서비스 출력 작성
마찬가지로 프로파일을 가져오기 위해 아래와 같이 샘플 GET <url-prefix>/Registration/GetProfile/{username} 서비스를 구현한다.
그림 7. 프로파일 가져오기 서비스 실행
이 프레임워크를 사용하여 모든 Java 서비스를 REST API로 쉽게 표시할 수 있다는 사실을 확인했다. XML을 출력 데이터로 사용하면 해당 언어에서 HTTP 프로토콜을 지원하는 한 모든 비Java 언어로 작성한 클라이언트 애플리케이션을 REST 서비스와 쉽게 통합할 수 있다. 또한, Action 클래스를 구현하기 위한 개발 노력이 상당히 줄어든다.
이 프레임워크에서 더 작업을 하여 구현의 예외 처리와 캐싱 서비스 기능을 개선할 수 있다. 또한, 개발자에게 도움이 되게 구성 파일에서 어노테이션 지원을 지정하지 않아도 기본적으로 구성이 되도록 어노테이션 지원을 구현할 수 있다.
이 기사의 내용을 검토해주고 아낌 없는 조언을 해준 동료, Rajesh Mishra에게 진심으로 감사드린다. 그는 필자를 도와서 프레임워크의 유용성을 개선했을 뿐만 아니라 프리젠테이션을 말끔하게 정리해 주었다.
| 설명 | 이름 | 크기 | 다운로드 방식 |
|---|---|---|---|
| A sample implementation code for the framework | RESTWS.war | 10KB | HTTP |
교육
- Architectural Styles and the Design of Network-based Software Architectures - (Roy Thomas Fielding, 캘리포니아 대학, 어바인 2000년): REST와 관련된 Fielding의 박사 학위 논문.
- RESTful 웹 서비스 – REST의 아키텍처 패턴과 JAX-WS에서의 REST 지원에 관한 기본 기본 사항을 다루는 기사
- RESTlet 프레임워크 - 오픈 소스 RESTful 웹 프레임워크
- Apache CXF - SOAP, XML/HTTP, RESTful과 같은 서비스를 지원하는 오픈 소스 서비스 프레임워크
- Apache Struts - 웹 애플리케이션을 빌드하는 데 필요한 오픈 소스 프레임워크
- developerWorks의 SOA와 웹 서비스 영역에서 개발자의 기술을 향상시키는 데 도움이 되는 참고자료를 다운로드할 수 있다.
- 기술 서점에서 다양한 기술 주제와 관련된 서적을 살펴보자.
제품 및 기술 얻기
- IBM 제품 평가판을 다운로드하거나 IBM SOA Sandbox의 온라인 시험판을 살펴보고 DB2®, Lotus®, Rational®, Tivoli® 및
WebSphere®의 애플리케이션 개발 도구와 미들웨어 제품을 사용해 볼 수 있다.
토론
- developerWorks 포럼 & 블로그를 통해 developerWorks 커뮤니티에 참여하자.
Vedesh Dambal has 12 years of experience in designing and developing Java/J2EE applications. Vedesh has worked in product development as well as service engagements in BPM, Telecom and Retail domains. He also has contributed reusable artifacts in knowledge sharing systems in various organizations and participated in forums and discussions on the Web including TheServerSide.com. Vedesh is currently working as a Product Technical Architect in Infosys Technologies Ltd.