RESTful API : 공유 또는 특정 URL을 가진 HTTP 동사?


25

RESTful API를 작성하는 동안 동일한 URL에 HTTP 동사를 사용해야합니까 (가능한 경우) 또는 조치 당 특정 URL을 작성해야합니까?

예를 들면 다음과 같습니다.

GET     /items      # Read all items
GET     /items/:id  # Read one item
POST    /items      # Create a new item
PUT     /items/:id  # Update one item
DELETE  /items/:id  # Delete one item

또는 다음과 같은 특정 URL을 사용하십시오.

GET     /items            # Read all items
GET     /item/:id         # Read one item
POST    /items/new        # Create a new item
PUT     /item/edit/:id    # Update one item
DELETE  /item/delete/:id  # Delete one item

답변:


46

후자의 체계에서는 리소스의 URL에 동사를 유지합니다. HTTP 동사는 해당 용도로 사용해야하므로이를 피해야합니다. 기본 프로토콜을 무시, 복제 또는 재정의하는 대신 기본 프로토콜을 채택하십시오.

를 보면 DELETE /item/delete/:id동일한 요청에 동일한 정보를 두 번 배치 할 수 있습니다. 이것은 불필요한 것이며 피해야합니다. 개인적으로, 나는 이것과 혼동 될 것입니다. API가 실제로 DELETE요청을 지원 합니까? deleteURL에 배치 하고 다른 HTTP 동사를 대신 사용하면 어떻게됩니까? 일치합니까? 그렇다면 어떤 것이 선택됩니까? 올바로 설계된 API의 클라이언트로서 그런 질문을 할 필요가 없습니다.

어쩌면 발행 DELETE또는 PUT요청이 불가능한 클라이언트를 지원하기 위해 필요할 수도 있습니다 . 이 경우 HTTP 헤더에이 정보를 전달합니다. 일부 API X-HTTP-Method-Override는이 특정 목적을 위해 헤더를 사용합니다 (어쨌든 추악하다고 생각합니다). 그래도 동사를 경로에 배치하지는 않을 것입니다.

간다

GET     /items      # Read all items
GET     /items/:id  # Read one item
POST    /items      # Create a new item
PUT     /items/:id  # Update one item
DELETE  /items/:id  # Delete one item

동사에 대해 중요한 것은 이미 HTTP 사양에 잘 정의되어 있으며 이러한 규칙을 준수하면 애플리케이션 시맨틱이 아닌 HTTP의 시맨틱을 이해하는 애플리케이션 외부에서 캐시, 프록시 및 기타 도구를 사용할 수 있다는 것입니다. . URL에 포함하지 않아야하는 이유는 읽을 수있는 URL이 필요한 RESTful API에 관한 것이 아닙니다. 불필요한 모호성을 피하는 것입니다.

또한 RESTful API는 HTTP 스펙에 위배되지 않는 한 이러한 동사 (또는 그 서브 세트)를 애플리케이션 시맨틱 세트에 맵핑 할 수 있습니다. 예를 들어, 만 사용 요청이 허용하는 모든 작업 인 경우 얻을 편안한 API 구축 할 수 있도록 완벽하게 가능하다 모두 안전나무 등을 . 위의 매핑은 사용 사례에 적합하고 사양을 준수하는 예일뿐입니다. 반드시 이런 식일 필요는 없습니다.

RESTA 의 핵심 가정 중 하나 인 HATEOAS (Hypertext as the Engine of Application State) 원칙을 준수하는 한 진정으로 RESTful API를 사용하면 프로그래머가 사용 가능한 URL에 대한 광범위한 문서를 읽을 필요가 없어야 합니다. 클라이언트 응용 프로그램이 해당 응용 프로그램 상태 전환을 파악하고 이해하는 데 사용할 수있는 한, 링크는 사람이 완전히 이해할 수 없습니다.


4
PUTand 가 없으면 DELETE쿼리 문자열과 차별화하지 않고 경로에 추가하는 것이 좋습니다. 기존 작업에 대한 쿼리 문자열 수정이 아닙니다. 그것은 A의 별도의 작업.
Robert Harvey

4
이 경우 @RobertHarvey, 어쨌든 그것을 핵이라고 부를 것입니다. 당신이 말했듯이, 그것은 작업 이며 RESTful을 목표로하는 API를 설계 할 때 경로에 넣은 것이 아닙니다. 쿼리 문자열에 배치하면 덜 침습적 인 것처럼 보입니다. 캐싱을 방지하지는 않지만 이런 종류의 요청에 대한 응답을 캐시해야한다고 생각하지 않습니다. 또한 API 소비자는 URL을 구문 분석하거나 구성하지 않고도 메소드를 쉽게 표시 할 수 있습니다. 이상적인 RESTful API는 클라이언트가 URL을 직접 작성하지 않아도 하이퍼 링크를 제공하는 것이 이상적입니다.
toniedzwiedz

당신이 모든 동사를 가지고 있지 않다면, 어쨌든 완전히 편안하지는 않습니까?
Robert Harvey

@RobertHarvey는 사실이지만 나는 이것을 의도 된 디자인이 아닌 폴백으로 취급합니다. API가 실제 HTTP 메소드를 지원해야한다고 생각하고 어떤 클라이언트가 어떤 이유로 든 메소드를 구현할 수없는 경우 사용법을 이러한 쿼리 매개 변수로 바꿀 수 있습니다. 프록시는 즉시이를 가져 와서 진짜 HTTP 동사를 사용하여 요청을 요청으로 변환하여 서버가 신경 쓸 필요도 없습니다. 거의 API가 거의 RESTful입니다. 일반적인 웹 API에 관해서는 실제로 맛의 문제입니다. 개인적으로, 나는 깨끗한 URL을 갈 것입니다. IMHO 이해하기 쉬움.
toniedzwiedz

1
@RobertHarvey는 설명대로 사용하기에는 의도 된 방법이 아닙니다. 나는 당신이 고객의 한계를 극복해야 할 때 두 가지 악한 것 중 작은 것을 발견했습니다. 그런 API에 대한 문서를 읽은 것을 기억하지만 브라우저 기록 / 책갈피에서 발굴하여 찾아야합니다. 이제 생각하면 헤더가 더 좋을 것입니다. 동의하겠습니까?
toniedzwiedz

14

첫번째.

URI / URL은 리소스 식별자입니다 (이름 힌트 : Uniform Resource Identifier). 첫 번째 규칙에서는 "GET / user / 123"을 수행 할 때 말하는 자원과 "DELETE / user / 123"을 수행 할 때 말하는 자원은 동일한 URL을 가지므로 분명히 동일한 자원입니다.

두 번째 규칙을 사용하면 "GET / user / 123"과 "DELETE / user / delete / 123"이 실제로 동일한 리소스인지 확인할 수 없으며 리소스가 아닌 관련 리소스를 삭제하고 있음을 나타냅니다 삭제 /user/delete/123하면 실제로 삭제 하는 것이 다소 놀랍습니다 /user/123. 모든 작업이 다른 URL에서 작동하면 URI가 더 이상 자원 식별자로 작동하지 않습니다.

당신이 말할 때 DELETE /user/123, 당신은 "ID가 123 인 사용자 레코드 삭제" 라고 말합니다 . 당신이 말한다면 DELETE /user/delete/123, 당신이 암시하는 것처럼 보이는 것은 " 'ID가 123 인 사용자 삭제 자 레코드를 삭제하는 것"입니다. 이 상황에서 더 정확한 동사를 사용하더라도 "ID가 123 인 사용자 삭제기에 첨부 된 작업을 수행합니다"라는 "POST / user / delete / 123"이라고해도 여전히 레코드 삭제를 말하는 방법입니다. (이것은 영어로 동사의 명사와 유사합니다).

URL에 대해 생각할 수있는 한 가지 방법은 객체 지향 프로그래밍에서 URL을 객체 및 리소스에 대한 포인터처럼 취급하는 것입니다. 당신이 할 때 GET /user/123, DELETE /user/123:, 당신은 객체의 메소드로 생각 생각할 수 [/user/123].get(), [/user/123].delete()(가) 어디 [](당신이 포인터를 가지고 언어를 알고있는 경우) 연산자를 역 참조 포인터처럼하지만 URL에 대한 것입니다. REST의 기본 원칙 중 하나는 균일 한 인터페이스입니다. 즉, 방대한 자원 / 객체 네트워크에서 모든 작업에 사용할 수있는 작고 제한된 동사 / 방법 세트를 갖는 것입니다.

따라서 첫 번째 것이 좋습니다.

추신 : 물론 이것은 가장 순수한 방식으로 REST를보고 있습니다. 때로는 실용성이 순결을 능가하기 때문에 적절한 REST를 수행하기 어려운 뇌사 클라이언트 또는 프레임 워크를 위해 양보해야합니다.


OOP 예제의 경우 +1 :)
53777A

6

(죄송합니다. 처음으로 (2)에서 / edit / 및 / delete /를 놓쳤습니다 ...)

URI의 아이디어는 그것이 메소드 호출이 아니라 주소 지정 가능한 자원식별자 라는 것 입니다. 따라서 URI는 특정 리소스를 가리켜 야합니다. URI를 연기하면 항상 동일한 리소스를 가져와야합니다.

즉, 데이터베이스에서 행의 기본 키에 대해 생각하는 것과 동일한 방식으로 URI에 대해 생각해야합니다. Universal Resource Identifier라는 것을 고유하게 식별합니다.

따라서 복수를 사용하든 단수를 사용하든 URI는 호출이 아닌 식별자 여야합니다 . 당신이하려고하는 것은 방법에 있습니다 : 즉 GET (get), PUT (create / update), DELETE (delete) 또는 POST (기타).

따라서 "/ item / delete / 123"은 리소스를 가리 키지 않기 때문에 REST를 중단합니다. 메서드 호출에 더 가깝습니다.

(또한 의미 적으로는 URI를 GET하고 구식을 결정한 다음 식별자이므로 동일한 URI를 삭제할 수 있어야합니다. GET URI에 "/ delete /"가없고 DELETE는 HTTP 의미론에 위배됩니다. 리소스 당 2 개 이상의 URI를 브로드 캐스트하고 있습니다.

이제 치트는 이것입니다. 자원의 정의와 정의에 대한 명확한 정의가 없으므로 REST의 일반적인 회피는 "처리 명사"를 정의하고 URI를 가리키는 것입니다. 그것은 거의 단어 게임이지만 의미를 만족시킵니다.

예를 들어 어떤 이유로 든 이것을 사용할 수 없다면 :

DELETE /items/123

당신은 "삭제 자"처리 자원을 가지고 세계에 선언하고 사용할 수 있습니다

POST /items/deletor  { id: 123 }

이제는 RPC (Remote Procedure Call)와 매우 유사하지만 HTTP 사양에 이름이 지정된 POST 사양의 "데이터 처리"절의 방대한 허점을 통과합니다.

그러나, 그 일을하는 것은 일종의 예외적이며, 당신이 경우 APPEND에 대한 공통의 삭제에 대한 삭제 / 업데이트를 생성하기위한 PUT 및 POST를 사용하여 작성하고, 다른 모든 것들, 다음 해야 , 그것은 HTTP의보다 표준 사용 때문에. 그러나 "commit"또는 "publish"또는 "redact"와 같은 까다로운 경우에는 프로세서 명사를 사용하는 경우 REST 순수 주의자를 만족 시키며 여전히 필요한 의미를 제공합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.