|
GET
, PUT
, POST
, DELETE
등과 같은 HTTP 지원 메소드만 사용할 수 있음을 의미한다. 이로 인해 WSDL과 같은 서비스 설명 언어가 필요없다.
왜 또다른 Java 표준인가? JAX-RS는 REST 기반 Java 개발을 단순화하기 위해 정의된 새로운 스펙이다. JAX-RS는 RESTful 서비스 구현을 위해 Java 어노테이션 및 POJO(Plain Old Java Object)를 사용하는 데 중점을 둔다. 역사적으로는 항상 서블릿을 사용하여 RESTful 서비스를 구현할 수 있었지만 비즈니스 로직 구현 과정에 항상 너무 많은 HTTP가 존재했었다.
JAX-RS는 이러한 HTTP를 모두 숨기고 서블릿을 적절하게 Java 클래스의 개별 메소드에 바인드한다. 어노테이션도 동적으로 HTTP 요청에서 정보를 추출하고 애플리케이션 생성 예외를 HTTP 응답 코드에 맵핑할 수 있다. 이것이 JAX-RS가 RESTful Java 웹 서비스를 구현하는 데 효과적인 방법인 이유 중 일부이다.
REST에 대해 다루다가 JAX-RS를 뛰어넘어 마침내 Apache Wink에 이르렀다. Apache Wink 1.0은 처음부터 설계된 JAX-RS 1.0 스펙의 구현을 완전히 준수한다. 사용하기 쉽고 프로덕션 준비가 되어 있으며 핵심 JAX-RS 스펙을 강화하는 기능 세트를 제공한다.
Apache Wink 런타임 아키텍처는 JAX-RS 1.0 스펙의 직접적인 구현이다. Apache Wink는 Java EE(Java Platform, Enterprise Edition) 환경에 전개되며 상위 레벨에서는 다음과 같은 세 가지 구성 요소로 구성된다.
RestServlet
. RestServlet
은 웹 애플리케이션의 Java EE web.xml 디스크립터 파일에서 구성된다. 이 서블릿은 모든 HTTP 웹 서비스 요청의 주요 시작점 역할을 하며 추가적인 처리를 위해 요청 및 응답 오브젝트 인스턴스를 요청 프로세서에 위임한다.
RequestProcessor
는 Apache Wink RestServlet
에 의해 초기화되는 핵심 Apache Wink 엔진이다. 요청 프로세서는 요청 URI를 사용하여 해당 자원 클래스 및 메소드를 찾고 대응시키고 호출한다. 요청 처리 중에 예외가 발생하면 RequestProcessor
가 예외 처리를 위해 오류 핸들러 체인을 호출한다.
그림 1에 표시된 대로 이 전체 요청 주기를 Apache Wink 논리 플로우라고 한다.
Apache Wink는 RESTful 웹 서비스의 구현에 도움이 될 뿐만 아니라 RESTful 서비스를 쉽게 이용할 수 있도록 하기 위한 강력한 클라이언트 라이브러리도 제공한다. 마지막으로 Apache Wink는 산업 표준 데이터 형식인 XML, Atom, RSS, JSON, CSV 및 HTML을 지원하도록 개발자를 지원하는 일련의 내장 공급자와 함께 패키지화된다.
이제 약간의 코딩 작업을 해야 한다. 코딩 작업을 재미있게 하기 위해 Apache Wink 1.0에서 특별한 RESTful 서비스를 설계하고 구현하고 전개한다. 이 서비스는 인터넷을 통한 신용카드 처리를 가능하게 하는 PayPal Payflow 지불 게이트웨이 서비스에 대한 RESTful 랩퍼이다. 하지만 이 예제의 목적에 맞는 트랜잭션 조회 기능으로 제한된다. 이 기능을 사용하면 인증된 사용자에게 속하는 고유 ID가 제공된 트랜잭션의 상태를 검색할 수 있다.
서비스에 대한 인터페이스 모델을 정의한 후 공식적으로 REST의 자원으로 만드는 URI를 해당 인터페이스 모델에 지정하는 것부터 시작한다. 서비스에서 수행할 작업은 트랜잭션 상태를 제공하는 것이므로 Listing 1에서 언급한 URI를 노출한다.
/transactions /transactions{id} |
/transactions
URI는 시스템의 모든 트랜잭션을 나타낸다. 개별 트랜잭션의 상태를 검색하기 위해서는 /transactions{id}
가 사용된다. {id}
는 트랜잭션 모델의 트랜잭션 ID에 해당하는 고유 영숫자 값을 나타낸다. 또한 특정 사용자를 인증하기 위해 Listing 2에 있는 패턴을 사용한다(여기서 UNAME
, VNAME
, PNAME
및 PWD
는 등록 시 판매자에게 지정된 Payflow 게이트웨이 로그인 신임의 일부임). 하지만 네트워크에서 이러한 신임이 인터셉트되거나 캐시되지 않도록 하려면 암호화된 HTTPS 연결을 사용하고 신임을 요청 헤더 매개변수로 전달하는 것이 좋다.
Listing 2. 쿼리 문자열에 사용자 신임이 있는 URI 패턴
GET /transactions{id} username=UNAME vendor=VNAME partner=PNAME password=PWD |
일반적으로 URI 구조는 외부에 공개된 경우 클라이언트 개발자에 의해 연결될 수 있으며 서버가 URI 공간을 수정하는 것을 제한할 수 있다. 하지만 이 기사의 목적상 필자는 해당 설계 제한조건을 무시한다.
모든 RESTful 인터페이스는 클라이언트에게 지원하는 여러 유형의 표시에 대해 결정해야 한다. XML, JSON, HTML 및 Atom은 Apache Wink 1.0이 지원할 수 있는 옵션 중 일부에 불과하지만 JSON은 자주 사용되는 형식이고 xxJavaScript 코드는 Ajax 애플리케이션을 위해 사용하기 쉽기 때문에 이 예제에서는 JSON을 사용한다. Listing 3은 JSON 문자열로 형식화된 트랜잭션 표시의 상태에 대한 예제이다.
Listing 3. JSON 문자열인 트랜잭션 상태 응답
{ "RESULT":19,"PNREF":"V19A2A1A7CC5", "RESPMSG":"Original transaction ID not found: V19A2A192BE9", "AUTHCODE":null,"CVV2MATCH":null,"AVSADDR":null, "AVSZIP":null,"IAVS":null,"CARDSECURE":null } |
응답의 데이터 형식으로 JSON을 사용하면 사용 중인 실제 JSON 구조의 대역 외 지식에 대한 서비스 레벨 연결이 발생할 수 있다.
마지막으로 자원과 해당 기능에 대해 작동하기 위해 사용할 HTTP 메소드를 결정해야 한다. 이러한 HTTP 메소드의 전형적인 사용법을 따르고 여기에서 벗어나지 않는 것이 중요하다. 예를 들어, GET
은 안전하고 멱등적인 읽기 전용 호출이어야 하며 어떤 방식으로든 자원의 상태를 변경해서는 안 된다. 이러한 지침을 따르지 않으면 클라이언트측의 작업이 복잡해지고 혼동이 가중된다. 이 경우에는 단일 트랜잭션의 상태에 대한 읽기 전용 검색을 수행하려고 하기 때문에 Listing 4에 표시된 대로 GET
메소드가 URI 패턴 사용에 가장 적합하다.
/transactions{id} |
Listing 5에 표시된 대로 각각의 GET
호출에서는 쿼리 중인 트랜잭션의 상태에 대한 JSON 형식 데이터 표시를 리턴한다.
Listing 5. 트랜잭션 ID가 포함된 GET 요청
GET /transactions/V19A2A192BE9 HTTP/1.1 |
하지만 이 트랜잭션 상태 쿼리 모델과 관련된 문제가 있다. 서비스에 트랜잭션을 쿼리하는 사용자가 실제로 트랜잭션의 소유자인지 인증하는 방법이 없다. 이러한 문제를 해결하려면 Listing 6에 설명된 대로 클라이언트가 로그인 신임을 URI의 요청 헤더 매개변수로 전달할 수 있도록 한다.
Listing 6. 보안 신임이 요청 헤더 매개변수인 GET 요청
GET /transactions/V19A2A192BE9 HTTP/1.1 user=winktest vendor=winktest partner=PayPal pwd=wink123 |
Apache Wink 서비스는 JAX-RS 어노테이션을 사용하여 수신 HTTP 요청을 Java 메소드에 맵핑하는 일반 Java 클래스 또는 POJO로 구현된다. 기본적으로 서비스는 싱글톤이거나 요청 시 작성된다. 이 예제에서는 TransactionResource
클래스를 작성하여 Apache Wink RESTful 서비스를 구현한다. 이 클래스는 수신 상태 검색 요청을 구문 분석하고 사용자 신임을 인증하고 Payflow 게이트웨이 서비스를 호출한 후 JSON 오브젝트로 형식화된 트랜잭션의 상태를 리턴한다. Listing 7에는 TransactionResource
클래스의 코드 스니펫이 제공된다.
Listing 7. Apache Wink 서비스 Java 클래스 스니펫
package org.openengine.wink.example.payflow; import ...; @Path("/transactions") public class TransactionResource { @GET @Path("{pnref}") @Produces(MediaType.APPLICATION_JSON) public JSONObject doInquiry(@PathParam("pnref") String pnref, @HeaderParam("user") String userName, @HeaderParam ("vendor") String vendorName, @HeaderParam ("partner") String partnerName, @HeaderParam ("pwd") String password) { try { if(userName!=null && vendorName!=null && partnerName!=null && password!=null) return getTxnStatus(pnref, userName, vendorName, partnerName, password).toString(); else throw new WebApplicationException(Response.Status.UNAUTHORIZED); } catch (JSONException e) { throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); } } .... |
@javax.ws.rs.Path
어노테이션은 클래스를 JAX-RS 서비스로 표시한다. 모든 JAX-RS 서비스에는 이 어노테이션이 필요하다. @Path
어노테이션의 값 /transactions
는 트랜잭션 서비스 URI의 상대 경로를 나타낸다.
@GET
어노테이션은 메소드 자체가 맵핑되는 HTTP 동사를 나타낸다. 메소드 레벨에 있는 @Path
어노테이션의 값은 기본 URI에 대해 상대적인 서브 루트를 참조한다. 메소드 레벨 @Path
에 있는 {pnref}
와 @PathParam
은 트랜잭션 고유 ID의 값을 나타낸다. 예를 들어, 수신 URI가 /transactions/V19A2A192BE9
인 경우 V19A2A192BE9
문자열이 getTxnStatus
메소드의 {pnref}
매개변수에 삽입된다.
@javax.ws.rs.HeaderParam
어노테이션은 @PathParam
과 비슷하지만 Listing 8에 표시된 대로 개별 요청 헤더 매개변수를 Java 매개변수에 삽입한다.
Listing 8. 요청 헤더 매개변수가 포함된 URI
/transactions/V19A2A192BE9 user=winktest vendor=winktest partner=PayPal pwd=wink123 |
Apache Wink 애플리케이션은 일반적으로 Apache Tomcat과 같은 서블릿 컨테이너에서 전개되고 WAR 파일로 패키지화된다. 다른 웹 애플리케이션과 마찬가지로 Apache Wink 서비스에도 web.xml 파일이 필요하다. Listing 9에는 샘플 Apache Wink 서비스의 web.xml 파일 컨텐츠가 제공된다.
<web-app> <display-name>Wink demo</display-name> <description>Demonstration of SDK features</description> <!-- Wink SDK servlet configuration. This servlet handles HTTP requests of SDK web service on application server.--> <servlet> <servlet-name>restSdkService</servlet-name> <servlet-class> org.apache.wink.server.internal.servlet.RestServlet </servlet-class> <init-param> <param-name>applicationConfigLocation</param-name> <param-value>/WEB-INF/application</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>restSdkService</servlet-name> <url-pattern>/rest/*</url-pattern> </servlet-mapping> </web-app> |
이와 같이 Apache Wink RestServlet
은 url-pattern
과 함께 web.xml 파일에 정의된다. /WEB-INF/application 디렉토리에 있는 파일을 가리키는 RestServlet
에 대한 초기화 매개변수도 있다. 이 파일에는 JAX-RS가 전개하기로 되어 있는 모든 클래스 및 오브젝트의 목록이 포함되어 있다. 이 구성 파일은 필요하지 않으며 서비스가 구현 중인 자원을 프로그램적으로 나열하는 애플리케이션 클래스를 구현하도록 결정할 수 있지만 이 예제에서는 Listing 10과 같이 애플리케이션 구성 파일 접근 방식을 대신 사용한다.
org.openengine.wink.example.payflow.TransactionResource |
서비스를 실행하려면 먼저 Tomcat에서 애플리케이션을 빌드하고 전개해야 한다. 다음과 같은 단계를 수행한다.
이 단계에서는 그림 3에 표시된 대로 PayFlow 프로젝트를 빌드하고 PayFlow.war라는 파일을 작성해야 한다.
telnet localhost 8080
을 입력한다(Tomcat 웹 서버는 포트 8080에서 수신하도록 구성되어 있다고 가정함).
Ctrl+]
(Ctrl 키를 누른 상태로 오른쪽 대괄호를 누름)를 입력한 후 set localecho
를 입력한다.
GET /PayFlow/rest/transactions/V19A2A192BE9 HTTP/1.1 user: winktest vendor: winktest partner: PayPal pwd: wink123 Host: localhost |
Telnet 출력에는 그림 5와 같이 JSON 형식 트랜잭션 상태가 포함되어 있어야 한다.
이 기사에서는 RESTful 서비스 구현을 단순화하는 것을 목적으로 하는 새 JAX-RS Java 표준과 REST 아키텍처의 기본사항에 대해 간략하게 살펴봤다. 이 기사는 JAX-RS 1.0 스펙을 완전히 준수하고 완벽하며 사용하기 쉬운 구현인 새로운 Apache Wink 1.0 프레임워크에 특히 초점을 두었다. 이 기사에서는 Apache Wink의 기본 아키텍처에 대해 살펴봤으며 새로운 샘플 Apache Wink 웹 서비스를 설계하고 구현했고 이를 전개하고 실행하기 위해 필요한 단계에 대해서 살펴봤다. REST, JAX-RS 또는 Apache Wink 1.0 프레임워크에 대한 자세한 내용은 이 기사의 참고자료 섹션을 참조한다.
첫댓글 RESTful 예전부터 있던거라는데.. 최근에 다시 떠오른다고 들었습니다. HTTP 전송규약 구현과 더불어서 흥미가 있어지더라구요.. ^^