본문 바로가기
아직 카테고리 미정

Richardson Maturity Model (번역본)

by simplify-len 2020. 10. 4.

아래 내용은 마틴 파울러 블로그에서 가져온 글을 번역했습니다.

steps toward the glory of REST

REST 접근 방식의 주요 요소를 세 단계로 나누는 모델 (Leonard Richardson이 개발). 

Resources, http Verb 및 hypermedia controls을 소개합니다.

최근에 저는 Rest In Practice의 초안을 읽었 습니다. 동료 부부가 작업하고있는 책입니다. 그들의 목표는 기업이 직면하는 많은 통합 문제를 처리하기 위해 Restful 웹 서비스를 사용하는 방법을 설명하는 것입니다. 책의 핵심은 웹이 정말 잘 작동하는 대규모 확장 가능한 분산 시스템의 존재 증명이라는 개념이며, 우리는 통합 시스템을 더 쉽게 구축하기 위해 아이디어를 얻을 수 있습니다.

그림1: REST를 향한 단계

Level 0

모델의 시작점은 HTTP를 원격 상호 작용을위한 전송 시스템으로 사용하지만 웹의 메커니즘을 사용하지 않는 것입니다. 기본적으로 여기서 수행하는 작업은 일반적으로 원격 프로 시저 호출을(Remote Procedure Invocation.) 기반으로하는 자체 원격 상호 작용 메커니즘을위한 터널링 메커니즘으로 HTTP를 사용하는 것입니다.

그림 2. Level 0 예시

의사와 약속을 예약하고 싶다고 가정 해 보겠습니다. 내 예약 소프트웨어는 먼저 내 의사가 주어진 날짜에 어떤 오픈 슬롯을 가지고 있는지 알아야하므로 해당 정보를 얻기 위해 병원 예약 시스템에 요청합니다. 레벨 0 시나리오에서 병원은 일부 URI에서 서비스 엔드 포인트를 노출합니다. 그런 다음 요청 세부 정보가 포함 된 문서를 해당 엔드 포인트에 게시합니다.

POST / appointmentService HTTP / 1.1 
[various other headers]
<openSlotRequest date = "2010-01-04" doctor = "mjones"/>

POST / appointmentService HTTP / 1.1 
[various other headers] 
<openSlotRequest date = "2010-01-04" doctor = "mjones"/> 

그러면 서버는이 정보를 제공하는 문서를 반환합니다.

HTTP / 1.1 200 OK 
[various other headers] 

<openSlotList> 
  <slot start = "1400"end = "1450"> 
    <doctor id = "mjones"/> 
  </ slot> 
  <slot start = "1600"end = "1650" > 
    <doctor ID = "mjones"/> 
  </ slot> 
</ openSlotList>

여기에서는 예를 들어 XML을 사용하고 있지만 콘텐츠는 실제로 JSON, YAML, 키-값 쌍 또는 사용자 지정 형식이 될 수 있습니다.

다음 단계는 약속을 예약하는 것입니다.이 작업은 엔드 포인트에 문서를 게시하여 다시 할 수 있습니다.

POST / appointmentService HTTP / 1.1 
[various other headers] 

<appointmentRequest> 
  <slot doctor = "mjones"start = "1400"end = "1450"/> 
  <patient id = "jsmith"/> 
</ appointmentRequest>

모든 것이 잘되면 약속이 예약되었다는 응답을받습니다.

HTTP / 1.1 200 OK 
[various other headers] 

<appointment> 
  <slot doctor = "mjones"start = "1400"end = "1450"/> 
  <patient id = "jsmith"/> 
</ appointment>

문제가 있으면 다른 사람이 나보다 먼저 들어 왔다고 말하면 회신 본문에 오류 메시지가 표시됩니다.

HTTP/1.1 200 OK
[various headers]

<appointmentRequestFailure>
  <slot doctor = "mjones" start = "1400" end = "1450"/>
  <patient id = "jsmith"/>
  <reason>Slot not available</reason>
</appointmentRequestFailure>

지금까지 이것은 간단한 RPC 스타일 시스템입니다. POX (Plain Old XML)를 앞뒤로 돌리기 때문에 간단합니다. SOAP 또는 XML-RPC를 사용하는 경우 기본적으로 동일한 메커니즘입니다. 유일한 차이점은 XML 메시지를 일종의 봉투로 래핑한다는 것입니다.

Level 1 - Resources

RMM에서 Glory of Rest를 향한 첫 번째 단계는 리소스를 도입하는 것입니다. 이제 모든 요청을 단일 서비스 엔드 포인트에 보내는 대신 개별 리소스와 대화하기 시작합니다.

그림3: Level 1은 리소스를 추가합니다.

따라서 초기 쿼리를 통해 주어진 의사에 대한 리소스가있을 수 있습니다.

POST /doctors/mjones HTTP/1.1
[various other headers]

<openSlotRequest date = "2010-01-04"/>

응답은 동일한 기본 정보를 전달하지만 이제 각 슬롯은 개별적으로 주소를 지정할 수있는 리소스입니다.

HTTP / 1.1 200 OK 
[various other headers] 


<openSlotList> 
  <slot id = "1234" doctor = "mjones"start = "1400" end = "1450"/> 
  <slot id = "5678" doctor = "mjones"start = "1600" end = "1650"/> 
</ openSlotList>

특정 리소스를 예약하면 약속은 특정 슬롯에 게시하는 것을 의미합니다.

POST / slots / 1234 HTTP / 1.1 
[various other headers] 

<appointmentRequest> 
  <patient id = "jsmith"/> 
</ appointmentRequest>

모든 것이 잘되면 이전과 비슷한 답장을받습니다.

HTTP / 1.1 200 OK 
[various other headers] 

<appointment> 
  <slot id = "1234"doctor = "mjones"start = "1400"end = "1450"/> 
  <patient id = "jsmith"/> 
</ appointment>

차이점은 테스트 예약과 같이 약속에 대해 어떤 조치를 취해야하는 경우, 먼저 위 URI와 같은 URI가 있을 수 있는 appointment resources를 가져와 http://royalhope.nhs.uk/slots/1234/appointment 해당 리소스에 게시한다는 것입니다.

To an object guy like me this is like the notion of object identity. Rather than calling some function in the ether and passing arguments, we call a method on one particular object providing arguments for the other information.

저와 같은 객체 녀석에게 이것은 객체 정체성의 개념과 같습니다. ether에서 일부 함수를 호출하고 인수를 전달하는 대신 다른 정보에 대한 인수를 제공하는 특정 개체에 대한 메서드를 호출합니다.

Level 2 - HTTP Verbs

 여기 레벨 0과 1의 모든 상호 작용에 HTTP POST 동사를 사용했지만 일부 사람들은 대신 또는 추가로 GET을 사용합니다. 이 수준에서는 큰 차이가 없으며 둘 다 HTTP를 통해 상호 작용을 터널링 할 수있는 터널링 메커니즘으로 사용됩니다. Level 2는 HTTP Verb가 HTTP 자체에서 사용되는 방식에 최대한 가깝게 사용하여이 문제를 해결합니다.

그림 4 : Level 2는 HTTP 동사를 추가합니다.

슬롯 목록의 경우 GET을 사용하려고합니다.

GET /doctors/mjones/slots?date=20100104&status=open HTTP/1.1
Host: royalhope.nhs.uk
HTTP/1.1 200 OK
[various headers]

<openSlotList>
  <slot id = "1234" doctor = "mjones" start = "1400" end = "1450"/>
  <slot id = "5678" doctor = "mjones" start = "1600" end = "1650"/>
</openSlotList>

Level 2에서는 이와 같은 요청에 GET을 사용하는 것이 중요합니다. HTTP는 GET을 안전한 작업으로 정의합니다. 즉, 상태를 크게 변경하지 않습니다. 이를 통해 순서에 관계없이 GET을 몇 번이나 안전하게 호출하고 매번 동일한 결과를 얻을 수 있습니다. 이것의 중요한 결과는 요청 라우팅에 참여하는 모든 참가자가 캐싱을 사용할 수 있도록 허용한다는 것입니다. 이는 웹 성능을 향상시키는 데있어 핵심 요소입니다. HTTP에는 모든 통신 참여자가 사용할 수있는 캐싱을 지원하는 다양한 방법이 포함되어 있습니다. HTTP 규칙을 따르면 해당 기능을 활용할 수 있습니다.

약속을 예약하려면 상태를 변경하는 HTTP 동사, POST 또는 PUT가 필요합니다. 이전에했던 것과 동일한 POST를 사용하겠습니다.

POST / slots / 1234 HTTP / 1.1 
[various other headers] 

<appointmentRequest> 
  <patient id = "jsmith"/> 
</ appointmentRequest>

Level 1과 동일한 게시물을 사용하더라도 원격 서비스가 응답하는 방식에는 또 다른 중요한 차이가 있습니다. 모든 것이 순조롭게 진행되면 서비스는 응답 코드 201로 응답하여 세계에 새 리소스가 있음을 나타냅니다.

HTTP / 1.1 201 Create
위치 : slots / 1234 / appointment 
[various other headers] 

<appointment> 
  <slot id = "1234"doctor = "mjones" start = "1400" end = "1450"/> 
  <patient id = "jsmith" /> 
</ appointment>

201 응답에는 클라이언트가 향후 해당 리소스의 현재 상태를 가져 오는데 사용할 수있는 URI가 있는 위치 속성이 포함되어 있습니다. 여기의 응답에는 클라이언트에게 지금 당장 추가 호출을 저장하기위한 해당 리소스의 표현도 포함됩니다.

다른 사람이 세션을 예약하는 등 문제가 발생하면 또 다른 차이가 있습니다.

HTTP/1.1 409 Conflict
[various headers]

<openSlotList>
  <slot id = "5678" doctor = "mjones" start = "1600" end = "1650"/>
</openSlotList>

이 응답의 중요한 부분은 HTTP 응답 코드를 사용하여 무언가 잘못되었음을 나타냅니다. 이 경우 409는 다른 누군가가 이미 호환되지 않는 방식으로 리소스를 업데이트했음을 나타내는 좋은 선택으로 보입니다. 반환 코드 200을 사용하지만 오류 응답을 포함하는 대신 레벨 2에서 이와 같은 일종의 오류 응답을 명시 적으로 사용합니다. 사용할 코드를 결정하는 것은 프로토콜 디자이너의 몫이지만 오류가 발생하면 2xx가 아닌 응답이 있어야합니다. 레벨 2는 HTTP 동사 및 HTTP 응답 코드 사용을 소개합니다.

여기에 불일치가 있습니다. REST 옹호자들은 모든 HTTP 동사 사용에 대해 이야기합니다. 또한 REST가 웹의 실질적인 성공을 통해 배우려고한다고 말함으로써 접근 방식을 정당화합니다. 그러나 전세계 웹은 실제로 PUT 또는 DELETE를 많이 사용하지 않습니다. PUT 및 DELETE를 더 많이 사용하는 합리적인 이유가 있지만 웹의 존재 증명은 그중 하나가 아닙니다.

웹의 존재에 의해 지원되는 핵심 요소는 안전 (예 : GET) 작업과 안전하지 않은 작업 간의 강력한 분리와 함께 발생하는 오류의 종류를 전달하는 데 도움이되는 상태 코드를 사용하는 것입니다.

Level 3 - Hypermedia Controls

마지막 단계에서는 HATEOAS (Hypertext As The Engine Of Application State)의 추악한 약어로 자주 듣게되는 것을 소개합니다. 그것은 약속을 예약하기 위해 무엇을해야하는지 알기 위해리스트 오픈 슬롯에서 얻는 방법에 대한 질문을 다룹니다.

그림 5 : Level 3은 하이퍼 미디어 컨트롤을 추가합니다.

Level 2에서 보낸 것과 동일한 초기 GET으로 시작합니다.

GET /doctors/mjones/slots?date=20100104&status=open HTTP/1.1
Host: royalhope.nhs.uk

But the response has a new element

HTTP/1.1 200 OK
[various headers]

<openSlotList>
  <slot id = "1234" doctor = "mjones" start = "1400" end = "1450">
     <link rel = "/linkrels/slot/book" 
           uri = "/slots/1234"/>
  </slot>
  <slot id = "5678" doctor = "mjones" start = "1600" end = "1650">
     <link rel = "/linkrels/slot/book" 
           uri = "/slots/5678"/>
  </slot>
</openSlotList>

이제 각 슬롯에는 약속 예약 방법을 알려주는 URI가 포함 된 링크 요소가 있습니다.

하이퍼 미디어 컨트롤의 요점은 다음에 할 수 있는 작업과 이를 수행하기 위해 조작 해야하는 리소스의 URI를 알려주는 것입니다. 약속 요청을 게시 할 위치를 알아야하는 대신 응답의 하이퍼 미디어 컨트롤이 이를 수행하는 방법을 알려줍니다.

POST는 다시 레벨 2를 복사합니다.

POST / slots / 1234 HTTP / 1.1 
[various other headers] 

<appointmentRequest> 
  <patient id = "jsmith"/> 
</ appointmentRequest>

그리고 회신에는 다음에 수행 할 여러 작업에 대한 여러 하이퍼 미디어 컨트롤이 포함되어 있습니다.

HTTP/1.1 201 Created
Location: http://royalhope.nhs.uk/slots/1234/appointment
[various headers]

<appointment>
  <slot id = "1234" doctor = "mjones" start = "1400" end = "1450"/>
  <patient id = "jsmith"/>
  <link rel = "/linkrels/appointment/cancel"
        uri = "/slots/1234/appointment"/>
  <link rel = "/linkrels/appointment/addTest"
        uri = "/slots/1234/appointment/tests"/>
  <link rel = "self"
        uri = "/slots/1234/appointment"/>
  <link rel = "/linkrels/appointment/changeTime"
        uri = "/doctors/mjones/slots?date=20100104&status=open"/>
  <link rel = "/linkrels/appointment/updateContactInfo"
        uri = "/patients/jsmith/contactInfo"/>
  <link rel = "/linkrels/help"
        uri = "/help/appointment"/>
</appointment>

 

 Hypermedia Controls의 한 가지 분명한 이점은 서버가 클라이언트를 중단하지 않고, URI 체계를 변경할 수 있다는 것입니다. 클라이언트가  "addTest" 링크 URI를 조회하는 한 서버 팀은 초기 진입 점을 제외한 모든 URI를 저글링 할 수 있습니다.

또 다른 이점은 클라이언트 개발자가 프로토콜을 탐색하는 데 도움이 된다는 것입니다. 링크는 클라이언트 개발자에게 다음에 가능한 작업에 대한 힌트를 제공합니다. 모든 정보를 제공하지는 않습니다. "self"및 "cancel" 컨트롤은 모두 동일한 URI를 가리킵니다. 하나는 GET이고 다른 하나는 DELETE인지 파악해야합니다. 그러나 적어도 그것은 더 많은 정보를 위해 무엇을 생각하고 프로토콜 문서에서 유사한 URI를 찾는 지에 대한 출발점을 제공합니다.

마찬가지로 서버 팀은 응답에 새로운 링크를 넣어 새로운 기능을 광고 할 수 있습니다. 클라이언트 개발자가 알려지지 않은 링크를 주시하는 경우, 이러한 링크는 추가 탐색을 위한 트리거가 될 수 있습니다.

Hypermedia Controls을 표현하는 방법에 대한 절대적인 표준은 없습니다. 

 여기서 제가 한 것은 REST in Practice 팀의 현재 권장 사항을 사용하는 것입니다. 이는 ATOM (RFC 4287) 을 따르는 것입니다. 대상 URI에 대한 속성과 관계의 종류를 설명하기위한 속성이 있는 <link>요소를 사용합니다 . 잘 알려진 관계 (예: 요소 자체에 대한 참조)는 표시되지 않으며 해당 서버에 특정한 것은 완전한 URI입니다. ATOM은 잘 알려진 linkrel에 대한 정의가 Registry of Link Relations 라고 명시합니다. 제가 글을 쓸 때 이것들은 일반적으로 Level 3 안정의 리더로 간주되는 ATOM이 한 일에 국한됩니다.urirelself

The Meaning of the Levels

RMM은 REST의 요소에 대해 생각하는 좋은 방법이지만 REST 자체 수준의 정의가 아니라는 점을 강조해야합니다. Roy Fielding은 level 3 RMM is a pre-condition of REST 임을 분명히 했습니다. 소프트웨어의 많은 용어와 마찬가지로 REST는 많은 정의를 얻지만, Roy Fielding이 용어를 만들었기 때문에 그의 정의는 대부분의 것보다 더 중요합니다.

 이 RMM에 대해 유용하다고 생각되는 점은 Restful thinking 뒤에 있는 기본 아이디어를 이해하는데 단계적으로 좋은 방법을 제공한다는 것입니다. 따라서, 나는 그것이 어떤 종류의 assessment mechanism에서 사용되어야 하는 것이 아니라, 개념에 대해 배우는 데 도움이 되는 도구라고 생각합니다. the restful approach이 시스템을 통합하는 올바른 방법이라는 것을 확신 할 수 있는 충분한 예가 아직 없다고 생각합니다. 매우 매력적인 접근 방식이며 대부분의 상황에서 권장하는 방식이라고 생각합니다.

Ian Robinson과 이 문제에 대해 이야기하면서 그는 Leonard Richardson이 처음으로 이 모델이 일반적인 디자인 기술과의 관계를 발표했을 때 이 모델에 대해 매력적이라고 ​​느꼈다고 강조했습니다.

  • Level 1은 분할 및 정복을 사용하여 복잡한 처리 문제를 해결하고 대규모 서비스 엔드 포인트를 여러 리소스로 분할합니다.
  • Level 2에서는 표준 동사 세트를 도입하여 유사한 상황을 동일한 방식으로 처리하여 불필요한 변형을 제거합니다.
  • Level 3은 검색 가능성을 도입하여 프로토콜을보다 자체적으로 문서화하는 방법을 제공합니다.

그 결과 우리가 제공하려는 HTTP 서비스의 종류에 대해 생각하고 상호 작용하려는 사람들의 기대치를 구성하는 데 도움이되는 모델이 탄생했습니다.

 

댓글