RESTful 디자인을 목표로하는 이유는 무엇입니까?
RESTful 원칙 은 ( 임의의 사용자 가 웹 사이트를 쉽게 "서핑"할 수 있도록) 웹 사이트를 웹 서비스 API 디자인 에 쉽게 제공하는 기능을 제공하므로 프로그래머가 쉽게 사용할 수 있습니다. REST는 REST이기 때문에 좋지 않습니다. REST는 좋기 때문에 좋습니다. 그리고 그것은 단순 하기 때문에 주로 좋습니다 .
일부 기능이 "기능 부족" 이라고 부르는 일반 HTTP (SOAP 엔벨로프 및 단일 URI 오버로드 된 POST
서비스가없는) 의 단순성 은 실제로 가장 큰 장점 입니다. HTTP는 즉시 접근성 과 상태 비 저장 을 요구합니다. HTTP는 오늘날의 대규모 사이트 (및 대규모 서비스)까지 확장 가능한 두 가지 기본 설계 결정입니다.
그러나 REST는 은색이 아닙니다. 때로는 RPC 스타일 ( "원격 프로 시저 호출"(예 : SOAP)) 이 적합 할 수 있으며 때로는 웹의 미덕보다 다른 요구가 우선합니다. 이건 괜찮아. 우리가 정말로 싫어하는 것은 불필요한 복잡성 입니다. 프로그래머 나 회사가 너무 자주 일반 HTTP가 잘 처리 할 수있는 작업을 위해 RPC 스타일 서비스를 도입하는 경우가 너무 많습니다. 그 결과 HTTP가 "실제로"진행중인 것을 설명하는 거대한 XML 페이로드에 대한 전송 프로토콜로 축소됩니다 (URI 또는 HTTP 메소드가 이에 대한 실마리를주지 않음). 결과 서비스는 너무 복잡하고 디버깅이 불가능하며 클라이언트가 개발자가 의도 한대로 정확하게 설정 하지 않으면 작동하지 않습니다 .
Java / C # 코드가 객체 지향적 이지 않은 것과 같은 방식으로 HTTP를 사용하더라도 디자인이 RESTful하지 않습니다. 조치와 호출해야하는 원격 방법의 관점에서 서비스 에 대한 생각을 서두르고있을 수도 있습니다 . 이것이 주로 RPC 스타일 서비스 (또는 REST-RPC- 하이브리드)로 끝나는 것은 당연합니다. 첫 번째 단계는 다르게 생각하는 것입니다. RESTful 디자인은 여러 가지 방법으로 달성 할 수 있습니다. 한 가지 방법은 작업이 아니라 리소스 측면에서 애플리케이션 을 생각 하는 것입니다.
💡 수행 할 수있는 행동을 생각하는 대신 ( "지도에서 장소 검색") ...
... 이러한 조치 의 결과 ( "검색 기준과 일치하는 장소 목록")로 생각하십시오.
아래 예를 들어 보겠습니다. (REST의 다른 주요 측면은 HATEOAS를 사용하는 것입니다. 여기서 브러시하지는 않지만 다른 게시물에서 빠르게 이야기합니다 .)
첫 번째 디자인의 문제
제안 된 디자인을 살펴 보자.
ACTION http://api.animals.com/v1/dogs/1/
먼저 새로운 HTTP 동사 ( ACTION
)를 만드는 것을 고려해서는 안됩니다 . 일반적으로 몇 가지 이유로 바람직하지 않습니다 .
- (1) 서비스 URI 만 주어지면 "랜덤"프로그래머는
ACTION
동사가 어떻게 존재 하는지 알 수 있습니까?
- (2) 프로그래머가 존재한다는 것을 알고 있다면, 그 의미를 어떻게 알 수 있습니까? 그 동사는 무엇을 의미합니까?
- (3) 그 동사가 어떤 속성 (안전성, dem 등식)을 기대해야합니까?
- (4) 프로그래머에게 표준 HTTP 동사 만 처리하는 매우 간단한 클라이언트가있는 경우 어떻게해야합니까?
- (5) ...
이제 사용을 고려해POST
봅시다 (아래에서 왜 그런지 설명하겠습니다. 지금 내 말을 들어보십시오).
POST /v1/dogs/1/ HTTP/1.1
Host: api.animals.com
{"action":"bark"}
이 수 확인을 할 수 ...하지만 경우에만 :
{"action":"bark"}
문서였다; 과
/v1/dogs/1/
"문서 프로세서"(공장과 같은) URI였습니다. "문서 프로세서"는 URI를 단지 "에 던져"하고 "잊어 버린"URI입니다. 프로세서는 "던지기"후에 새로 만든 리소스로 리디렉션 할 수 있습니다. 예를 들어, 메시지 브로커 서비스에 메시지를 게시하기위한 URI. 게시 후 메시지 처리 상태를 표시하는 URI로 리디렉션합니다.
나는 당신의 시스템에 대해 잘 모르지만, 나는 이미 둘 다 사실이 아니라고 확신합니다.
{"action":"bark"}
는 문서가 아니며 실제로 서비스 에 닌자 몰래 들어 가려는 방법입니다 . 과
/v1/dogs/1/
URI는 "개"리소스 (와 아마 개 대표 id==1
)이 아닌 문서 프로세서를.
이제 우리가 아는 것은 위의 디자인이 너무 RESTful 한 것이 아니라 정확히 무엇입니까? 뭐가 그렇게 나쁜가요? 기본적으로 복잡한 의미를 가진 복잡한 URI이기 때문에 나쁘다. 아무것도 추론 할 수 없습니다. 프로그래머가 개에게 bark
비밀리에 개가 주입 될 수 있는 행동이 있다는 것을 어떻게 알 수 POST
있을까요?
질문의 API 호출 디자인
따라서 추격을 줄이고 리소스 측면에서 생각 하여 휴식을 취하도록 디자인하십시오 . Restful Web Services 책 을 인용하겠습니다 .
POST
요청은 기존에서 새 자원을 작성하기위한 시도이다. 기존 자원은 데이터 구조적 의미에서 새로운 자원의 부모 일 수 있으며, 트리의 루트는 모든 리프 노드의 부모입니다. 또는 기존 자원은
다른 자원을 생성하는 것이 유일한 목적인 특수 "공장" 자원 일 수 있습니다 . POST
요청 과 함께 전송 된 표현 은 새로운 자원의 초기 상태를 설명합니다. PUT과 마찬가지로 POST
요청에는 표현이 전혀 포함될 필요가 없습니다.
우리가 볼 수있는 위의 설명을 다음 bark
과 같이 모델링 할 수 의 하위 리소스dog
(A가 있기 때문에 bark
, 껍질은 "짖었다"입니다 개, 내에 포함 하여 개).
그 추론에서 우리는 이미 얻었습니다.
- 방법은
POST
- 리소스는 "factory"를 나타내는
/barks
dog :의 하위 리소스입니다 . 해당 URI는 개마다 고유합니다 (아래에 있으므로 )./v1/dogs/1/barks
bark
/v1/dogs/{id}
이제 목록의 각 사례마다 특정 동작이 있습니다.
1. 껍질은 단지 전자 메일을 보내고 dog.email
아무것도 기록하지 않습니다.
첫째, 짖는 소리 (이메일 보내기)는 동기식 작업이든 비동기식 작업입니까? 둘째, bark
요청에 문서 (이메일 등)가 필요합니까, 아니면 비어 있습니까?
1.1 껍질은 전자 메일을 보내고 dog.email
아무것도 기록하지 않습니다 (동기식 작업으로)
이 경우는 간단합니다. barks
팩토리 자원에 대한 호출은 즉시 껍질 (이메일 전송)을 생성하고 응답 (확인이 가능하거나 그렇지 않은 경우)이 즉시 제공됩니다.
POST /v1/dogs/1/barks HTTP/1.1
Host: api.animals.com
Authorization: Basic mAUhhuE08u724bh249a2xaP=
(entity-body is empty - or, if you require a **document**, place it here)
200 OK
아무것도 기록 (변경)하므로 200 OK
충분합니다. 모든 것이 예상대로 진행되었음을 보여줍니다.
1.2 껍질은 전자 메일을 보내고 dog.email
아무것도 기록하지 않습니다 (비동기 작업으로)
이 경우 클라이언트는 bark
작업 을 추적 할 방법이 있어야합니다 . bark
작업은 다음의 자신의 URI의 자원이어야한다 :
POST /v1/dogs/1/barks HTTP/1.1
Host: api.animals.com
Authorization: Basic mAUhhuE08u724bh249a2xaP=
{document body, if needed;
NOTE: when possible, the response SHOULD contain a short hypertext note with a hyperlink
to the newly created resource (bark) URI, the same returned in the Location header
(also notice that, for the 202 status code, the Location header meaning is not
standardized, thus the importance of a hipertext/hyperlink response)}
202 Accepted
Location: http://api.animals.com/v1/dogs/1/barks/a65h44
이 방법으로 각각 bark
추적 할 수 있습니다. 그러면 클라이언트는 URI에 a GET
를 발행하여 bark
현재 상태를 알 수 있습니다. 어쩌면 a DELETE
를 사용 하여 취소 할 수도 있습니다.
2. 껍질은 이메일을 보낸 dog.email
다음 dog.barkCount
1 씩 증가 합니다.
클라이언트에게 dog
리소스가 변경 되었음을 알리려면 더 까다로울 수 있습니다 .
POST /v1/dogs/1/barks HTTP/1.1
Host: api.animals.com
Authorization: Basic mAUhhuE08u724bh249a2xaP=
{document body, if needed; when possible, containing a hipertext/hyperlink with the address
in the Location header -- says the standard}
303 See Other
Location: http://api.animals.com/v1/dogs/1
이 경우 location
헤더의 의도는 클라이언트에게 살펴보아야한다는 것을 알리는 것 dog
입니다. 보내는 사람 에 대한 HTTP RFC303
:
이 방법은 주로 POST
활성화 된 스크립트 의 출력이 사용자 에이전트를 선택된 자원으로 경로 재 지정할 수 있도록하기 위해 존재
합니다.
작업이 비동기 인 경우 상황과 bark
마찬가지로 하위 리소스가 필요 하며 작업이 완료되면 at을 반환해야합니다 .1.2
303
GET .../barks/Y
3. 껍질은 껍질이 생겼을 때 bark
기록 된 새로운 " "레코드를 생성합니다 bark.timestamp
. 또한 dog.barkCount
1 씩 증가 합니다.
POST /v1/dogs/1/barks HTTP/1.1
Host: api.animals.com
Authorization: Basic mAUhhuE08u724bh249a2xaP=
(document body, if needed)
201 Created
Location: http://api.animals.com/v1/dogs/1/barks/a65h44
여기에서는 bark
요청으로 인해 생성되었으므로 상태 201 Created
가 적용됩니다.
생성이 비동기 인 경우 대신 HTTP RFC에 표시된대로 a 202 Accepted
가 필요 합니다.
저장된 타임 스탬프는 bark
리소스 의 일부이며 a GET
를 사용하여 검색 할 수 있습니다 . 업데이트 된 개는 그 안에 "문서화"될 수 있습니다 GET dogs/X/barks/Y
.
4. bark는 시스템 명령을 실행하여 Github에서 최신 버전의 Dog 코드를 가져옵니다. 그런 다음 dog.owner
새 개 코드가 생산 중임 을 알리는 문자 메시지를 보냅니다 .
이 표현은 복잡하지만 간단한 비동기 작업입니다.
POST /v1/dogs/1/barks HTTP/1.1
Host: api.animals.com
Authorization: Basic mAUhhuE08u724bh249a2xaP=
(document body, if needed)
202 Accepted
Location: http://api.animals.com/v1/dogs/1/barks/a65h44
그런 다음 클라이언트는 GET
s를 발행 /v1/dogs/1/barks/a65h44
하여 현재 상태를 알 수 있습니다 (코드를 가져 오면 전자 메일이 소유자에게 전송 된 것 등). 개가 바뀔 때마다 a 303
가 적용됩니다.
마무리
인용 로이 필딩 :
REST가 메소드에 요구하는 유일한 것은 모든 자원에 대해 균일하게 정의된다는 것입니다 (즉, 중개자가 요청의 의미를 이해하기 위해 자원 유형을 알 필요가 없음).
위의 예에서 POST
균일하게 설계되었습니다. 개를 " bark
"로 만듭니다. 그것은 안전하지 않습니다 (나무 껍질이 자원에 영향을 미침) 또는 i 등성 (각 요청은 새로운 것을 산출합니다 bark
)은 POST
동사에 잘 맞습니다 .
프로그래머는 알 것하십시오 POST
에 barks
낳는 bark
. 응답 상태 코드 (필요한 경우 엔터티 본문 및 헤더와 함께)는 변경된 내용과 클라이언트가 수행 할 수있는 방법과 진행 방법을 설명하는 작업을 수행합니다.
참고 : 사용 된 주요 소스는 " 휴식 웹 서비스 "책, HTTP RFC 및 Roy Fielding의 블로그 였습니다.
편집하다:
질문과 답변은 처음 만들어진 이후로 상당히 바뀌 었습니다. 원래의 질문은 URI를 등의 디자인에 대해 질문 :
ACTION http://api.animals.com/v1/dogs/1/?action=bark
아래는 왜 좋은 선택이 아닌지에 대한 설명입니다.
클라이언트가 서버에게 데이터로 무엇을해야하는지 알려주 는 방법 은 메소드 정보 입니다.
- RESTful 웹 서비스는 메소드 정보를 HTTP 메소드로 전달합니다.
- 일반적인 RPC 스타일 및 SOAP 서비스는 엔티티 본문 및 HTTP 헤더에 유지됩니다.
어느 부분 의 데이터에 작동 할 수있다 [클라이언트는 서버가 원하는] 범위 지정 정보 .
- RESTful 서비스는 URI를 사용합니다. SOAP / RPC 스타일 서비스는 다시 한번 엔티티 본문과 HTTP 헤더를 사용합니다.
예를 들어 Google의 URI를 사용하십시오 http://www.google.com/search?q=DOG
. 방법 정보가 GET
있고 범위 지정 정보는 /search?q=DOG
입니다.
간단히 말해 :
- 에서 편안하고 아키텍처 , 방법 정보는 HTTP 메소드로 들어갑니다.
- 에서 자원 지향 아키텍처 , 범위 지정 정보는 URI로 들어갑니다.
그리고 경험의 법칙 :
HTTP 메소드가 메소드 정보와 일치하지 않으면 서비스가 RESTful하지 않습니다. 범위 지정 정보가 URI에 없으면 서비스가 자원 지향적이지 않은 것입니다.
당신은 넣을 수 있습니다 "껍질" "행동" 의 URL (또는 엔터티 본문에) 및 사용 POST
. 아무런 문제가 없으며 작동하며 가장 간단한 방법 일 수 있지만 RESTful하지는 않습니다 .
서비스를 진정으로 편안하게 유지하려면 한 걸음 물러서서 실제로하고 싶은 일 (자원에 어떤 영향을 미칠지)에 대해 생각해야 할 수도 있습니다.
구체적인 비즈니스 요구에 대해 이야기 할 수는 없지만 예를 들어 보겠습니다. 주문이 URI와 같은 RESTful 주문 서비스를 고려하십시오 example.com/order/123
.
이제 주문을 취소하고 싶다고하면 어떻게해야합니까? 그것이 "취소" "행동" 이라고 생각하고 그것을 다음과 같이 설계하려는 유혹을받을 수 있습니다 POST example.com/order/123?do=cancel
.
우리가 위에서 이야기했듯이 그것은 RESTful하지 않습니다. 대신, 우리는 수도 PUT
의 새로운 표현 order
A의 canceled
요소에 전송 true
:
PUT /order/123 HTTP/1.1
Content-Type: application/xml
<order id="123">
<customer id="89987">...</customer>
<canceled>true</canceled>
...
</order>
그리고 그게 다야. 주문을 취소 할 수없는 경우 특정 상태 코드가 반환 될 수 있습니다. ( POST /order/123/canceled
Entity-body와 같은 하위 리소스 디자인 true
도 간단하게 사용할 수 있습니다.)
특정 시나리오에서 비슷한 것을 시도해 볼 수 있습니다. 개가 짖는 동안 그런 식으로, 예를 들어, GET
AT는 /v1/dogs/1/
그 정보를 포함 할 수있다 (예를 <barking>true</barking>
) . 또는 ... 너무 복잡하면 RESTful 요구 사항을 풀고에 충실하십시오 POST
.
최신 정보:
답변을 너무 크게 만들고 싶지는 않지만 알고리즘 ( action )을 리소스 집합으로 노출시키는 데 시간이 걸립니다 . 행동 ( "지도에서 장소 검색") 에 대해 생각하는 대신 , 그 행동의 결과 ( "검색 기준과 일치하는지도에있는 장소 목록 " )에 대해 생각해야합니다 .
디자인이 HTTP의 균일 한 인터페이스에 맞지 않는 경우이 단계로 돌아갈 수 있습니다.
쿼리 변수 는 정보 범위를 지정 하지만 새로운 자원을 나타내지 않습니다 ( /post?lang=en
분명히 다른 자원과 동일한 자원 /post?lang=jp
임). 오히려 클라이언트 상태 를 전달하는 데 사용됩니다 (예 ?page=10
: 상태가 서버에 유지되지 않음 ( ?lang=en
여기의 예이기도 함)). 또는 입력 매개 변수 를 알고리즘 자원 ( /search?q=dogs
, /dogs?code=1
)에 전달합니다. 다시, 별개의 자원이 아닙니다.
HTTP 동사 (방법) 속성 :
?action=something
URI에 표시 되는 또 다른 분명한 점 은 RESTful이 아니며 HTTP 동사의 속성입니다.
GET
및 HEAD
안전 (나무 등)이고;
PUT
i DELETE
등원 일 뿐이다.
POST
둘 다 아닙니다.
안전 : GET
또는 HEAD
요청은 서버 상태 변경 요청이 아닌 일부 데이터 읽기 요청입니다. 클라이언트는 10 번 GET
또는 HEAD
요청을 할 수 있으며 한 번 만들 거나 전혀 만들지 않는 것과 같습니다 .
dem 등원 (Idempotence) : dem 등원 (Idempotent) 연산은 한 번 또는 여러 번 적용해도 동일한 효과를 갖습니다 (수학에서 0을 곱하면 i 등원). DELETE
리소스를 한 번 사용하는 경우 다시 삭제하면 동일한 효과가 적용됩니다 (리소스가 GONE
이미 존재 함).
POST
안전하거나 dem 등하 지 않습니다. POST
'팩토리'리소스에 대해 두 개의 동일한 요청을하면 아마도 동일한 정보를 포함하는 두 개의 하위 리소스가 생길 수 있습니다. 오버로드 된 (URI 또는 entity-body의 메소드) POST
모든 베팅이 해제됩니다.
이 두 속성은 모두 신뢰할 수없는 네트워크를 통한 HTTP 프로토콜의 성공에 중요했습니다 GET
. 페이지가 완전히로드 될 때까지 기다리지 않고 몇 번 업데이트 했습니까 ()?
조치를 작성 하여 URL에 배치하면 HTTP 메소드 계약이 명확하게 중단됩니다. 다시 한번,이 기술은 당신을 허용하지만, 당신은 그것을 할 수 있지만 RESTful 디자인은 아닙니다.