아키텍쳐 /WEB 2.0

REST 연재-2회 Advanced REST

Terry Cho 2009. 6. 23. 23:57

2회 - Advanced REST (DRAFT)

 

자바스터디 조대협
(http://bcho.tistory.com)

 

전의 글에서는 기본적인 REST의 개념에 대해서 설명하였다. 그러나 REST 는 HTTP의 장점을 이용하여 좀더 발전된 형태의 구현이 가능하다.

하나의 예로 이 글은  http://www.infoq.com/articles/subbu-allamaraju-rest 를 이용하여 편역하여 설명한다. 

예를 들기위해서 은행의 계좌이체를 하는 시나리오를 가정해서 생각해보자.

1. 인터넷 뱅킹 계좌 이체 시나리오의 구현

STEP 1. 인터넷 뱅킹 시스템에 로그인을 한다.

STEP 2. 사용자 ID로, 해당 사용자가 가지고 있는 계좌 목록을 조회한다.

http://bank.org/accounts?findby=7t676323a 

200 OK
Content-Type: application/xml;charset=UTF-8
 <accounts xmlns="urn:org:bank:accounts">
    <account>
        <id>AZA12093</id>
        <customer-id>7t676323a</customer-id>
        <balance currency="USD">993.95</balance>
    </account>
    <account>
        <id>ADK31242</id>
        <customer-id>7t676323a</customer-id>
        <balance currency="USD">534.62</balance>
    </account>
</accounts>

 사용자 ID 7t76323a에 대해서 두개의 계좌 AZA12093과 ADK31242 가 리턴되고 각 계좌의 잔액이 함께 리턴된다. 각 계좌 번호를 조회했기 때문에 각 계좌의 상세 정보는 http://bank.org/account/AZA12093

http://bank.org/account/ADK31242

STEP 3. 계좌 이체를 하는 시나리오를 보면

POST /transfers
Host: bank.org
Content-Type: application/xml;charset=UTF-8
<transfer xmlns="urn:org:bank:accounts">
    <from>account:AZA12093</from>
    <to>account:ADK31242</to>
    <amount currency="USD">100</amount>
    <note>RESTing</note>
</transfer>

AZA12093에서 ADK31242로 100 USD를 이체하는 것을 HTTP POST를 통해서 보낸다.계좌 이체가 성공하면 다음과 같은 결과값이 리턴된다.

201 Created
Content-Type: application/xml;charset=UTF-8
<transfer xmlns="urn:org:bank:accounts">
    <from>account:AZA12093</from>
    <to>account:ADK31242</to>
    <id>transfer:XTA8763</id>
    <amount currency="USD">100</amount>
    <note>RESTing</note>
</transfer>

이때 주의해서 볼 것은 리턴값이 HTTP 200이 아니라 HTTP 201이다. 이 시스템의 경우 계좌이체가 바로 발생하는 것이 아니라 비동기적으로 나중에 발생하는 형태로 가정하기 때문에, 계좌 이체 요청이 접수되었다라는 의미로 HTTP 201 Created를 리턴하고 이체 신청 번호 XTA8763을 리턴한다. 

STEP 4. 하루가 지난후에, 계좌 이체가 된 내용을 다시 확인해보면

http://bank.org/check/XTA8763

GET /check/XTA8763
Host: bank.org 
200 OK
Content-Type: application/xml;charset=UTF-8
<status xmlns="urn:org:bank:accounts">
    <code>01</code>
    <message xml:lang="en">Pending</message>
</status>

 해당 계좌 이체 요청이 Pending이 되어 있는 것으로 나타난다.

 2. 진보된 형태의 REST를 이용한 인터넷 뱅킹 계좌이체 시나리오의 구현

언뜻 보면 상당히 잘 구현된 형태의 REST처럼 보이지만, 이는 실제 REST의 장점을 제대로 살린 아키텍쳐라고 볼 수 없다.

REST는

첫번째로 URI를 이용한 자원의 식별이 가능해야 하고,

두번째로 HTTP 프로토콜의 여러 기능들 특히 HTTP Header들을 이용해서 리소스에 대한 다양한 접근 방법을 표현할 수 있어야 한다. 예를 들어서 Sync/Async 식의 Message Exchange Pattern, Correlation ID 등을 이용한 CALL BACK, 웹캐쉬를 이용하기 위한 Last Update Time등의 메타 정보를 HTTP HEADER에 정의해야 하며 Contents Type등을 통한 Input과 Output Data Format에 대한 정의가 가능할 수 있다.

세번째로는 링크를 이용한 리소스간의 관계나 현재 리소스에 대한 상태 정보를 표현할 수 있어야 한다

그러면 이 특징을 기반으로 해서 앞에서 작성했던 계좌 이체 시나리오를 재 구현해보자

STEP 1. 인터넷 뱅킹 시스템에 로그인을 한다.

STEP 2. 사용자 ID로, 해당 사용자가 가지고 있는 계좌 목록을 조회한다.

200 OK
Content-Type: application/vnd.bank.org.account+xml;charset=UTF-8
<accounts xmlns="urn:org:bank:accounts">
    <account>
        <id>AZA12093</id>
        <link href="http://bank.org/account/AZA12093" rel="self"/>
        <link rel="http://bank.org/rel/transfer edit"
              type="application/vnd.bank.org.transfer+xml"
              href="http://bank.org/transfers"/>
        <link rel="http://bank.org/rel/customer"
              type="application/vnd.bank.org.customer+xml"
              href="http://bank.org/customer/7t676323a"/>
        <balance currency="USD">993.95</balance>
    </account>
    <account>
        <id>ADK31242</id>
        <link href="http://bank.org/account/ADK31242" rel="self"/>
        <link rel="http://bank.org/rel/transfer"
              type="application/vnd.bank.org.transfer+xml"
              href="http://bank.org/transfers"/>
        <link rel="http://bank.org/rel/customer"
              type="application/vnd.bank.org.customer+xml"
              href="http://bank.org/customer/7t676323a"/>
        <balance currency="USD">534.62</balance>
    </account>
</accounts>

앞서 설명한것과 다소 다른 형태의 리턴값이 오게되는데, 먼저 살펴볼 부분은 Content-Type이다. : application/vnd.bank.org.account+xml; 리턴 형태의 Content-Type이 리턴된다. 먼저 +xml은 이 문서의 포맷이 xml임을 의미하며 vnd.bank.org.account는 리턴 데이터의 구조를 정의한다. (마치 XML 스키마와 같이, 실제로 UNIQUE한 이름으로 INPUT또는 OUTPUT으로 사용되는 XML 스키마의 이름에 ID를 부여해서 사용하면, REST의 약점중의 하나인 데이터 형의 미정의에 대한 약점을 보완할 수 있다. )

 또다른 변화점은 LINK부분이 추가되었다는 것이다. 이 LINK는 현재 자원의 상태가 어떤 상태로 변화될 수 있으며, 상태를 변화시키기 위해서는 어떤 URI를 이용하면 된다는 것을 설명한다. 또는 이 자원과 관련성이 있는 다른 자원에 대한 연관 관계를 표현하며 호출시에 리턴되는 데이터 형태에 대해서 Content-Type으로 정의할 수 있다. 이렇게 RETURN되는 메시지 자체에 다른 자원으로의 연결 상태와 데이터 형태등이 정의되면 서비스에 대한 별도의 정의가 없이도, 자원에 대한 사용 방법과 관계를 알 수 있기 때문에 이러한 특성을 REST에서는 self-descriptive message라고 한다.

 <account>

        <id>ADK31242</id>
        <link href="http://bank.org/account/ADK31242" rel="self" type=”application/vnd.bank.org.account+xml”/>
        <link rel="http://bank.org/rel/transfer"
              type="application/vnd.bank.org.transfer+xml"
              href="http://bank.org/transfers"/>
        <link rel="http://bank.org/rel/customer"
              type="application/vnd.bank.org.customer+xml"
              href="http://bank.org/customer/7t676323a"/>
        <balance currency="USD">534.62</balance>

이 부분을 살펴보면 세가지 변화 상태를 볼 수 있다. Self와 http://bank.org/rel/transfer 그리고 http://bank.org/rel/customer 이다.

첫번째로 http://bank.org/rel/transfer 로 이 계좌에 대해서 “계좌 이체”를 할 수 있는 관계(또는 기능)을 정의하며, 계좌 이체를 하기 위해서는  http://bank.org/transfers URL에 보내면 되고 리턴값은 application/vnd.bank.org.transfer+xml 형태가 된다.

두번째 self는 이 Account 자체에 대한 좀더 제사한 정보를 나타내며 http://bank.org/account/ADK31242 를 통해서 조회할 수 있으며 리턴 되는 데이터 형태는 application/vnd.bank.org.account+xml 로 리턴 됨을 정의한다.

세번째 http://bank.org/rel/customer 는 고객 정보를 나타내며 http://bank.org/customer/7t676323a 를 통해서 조회가 가능하고 리턴되는 데이터 형태는 application/vnd.bank.org.customer+xml 이 된다.

STEP 3. 실제로 계좌 이체를 수행한다.

STEP 2에서 리턴 받은 transfer 관계의 URL로 아래와 같은 데이터를 전송한다.

POST /transfers
Host: bank.org
Content-Type: application/vnd.bank.org.transfer+xml;charset=UTF-8
<transfer xmlns="urn:org:bank:accounts">
    <from>account:AZA12093</from>
    <to>account:ADK31242</to>
    <amount currency="USD">100</amount>
    <note>RESTing</note>
</transfer>
 

 리턴값은 아래와 같다.

201 Created
Content-Type: application/vnd.bank.org.transfer+xml;charset=UTF-8 
<transfer xmlns="urn:org:bank:accounts">
    <link rel="self"
          href="http://bank.org/transfer/XTA8763"/>
    <link rel="http://bank.org/rel/transfer/from"
          type="application/vnd.bank.org.account+xml"
          href="http://bank.org/account/AZA12093"/>
    <link rel="http://bank.org/rel/transfer/to"
          type="application/vnd.bank.org.account+xml"
          href="http://bank.org/account/ADK31242"/>
    <link rel="http://bank.org/rel/transfer/status"
          type="application/vnd.bank.org.status+xml"
          href="http://bank.org/check/XTA8763"/>
    <id>transfer:XTA8763</id>
    <amount currency="USD">100</amount>
    <note>RESTing</note>
</transfer>

 STEP 4. 계좌 이체 진행 상태를 확인한다.

계좌 이체 진행 상태를 확인하기 위해서는 STEP 3에서 리턴된 http://bank.org/check/XTA8763 을 이용하여 확인할 수 있다.

결론

사실 여기서 언급하고자 한 부분은 HTTP의 Content-Type을 이용한 데이터 타입의 정의와 Link를 이용한 리소스간의 관계 정의 방법이다. 많은 REST 관련글을 보면 비슷한 사상들을 가지고는 있지만 아직 “이거다” 하는 식의 표준 디자인 방법은 존재하지 않는다.

위의 예제에서도 Content-Type을 통해서 In/out data format을 정의할 수 는 있지만 고민해보면 Link에 정의된 type만으로는 out(return) data format을 정의할 수 있을지 몰라도 input에 대한 정의는 빠져 있다. 또한 다른 디자인에서는 XML의 namespace의 URI에 실제 XML Scheme의 URI를 정의해서 데이터 타입을 정의하는 방법론도 있다.

 또한 Link를 사용하는 방법은 프로토콜 차원에서는 리소스간의 관계를 정의를 하는것이라서 언뜻 보면 좋아보일 지는 모르지만 실제 구현시에는 여러가지 제약사항을 만들어 낼 수 있다.

이 글은 HTTP의 좀더 활용을 통해서 좀더 발전된 형태의 REST 디자인 방법의 하나의 예시를 설명한 것 뿐이고, 좀더 실용적인 REST 디자인은 더 많은 고려가 필요하리라 생각된다.

=======

Comment

사실 본인도 Advanced 스타일의 REST 디자인에 대해 정리를 하기위해서 작성한 글이라서 내용이 다소 떨어지더라도,  아직까지 다소 정리되지 않은 형태의 글임을 이해해주시기 바랍니다. 다음에 기회가 되면 Advanced Style 특히 LINK와 Data type 대해서는 다시 한번 다루기로 하겠습니다. 다음 연재에서는 실제로 REST를 JAVA에서 구현하는 방법에 대해서 알아보겠습니다.

 

그리드형