Gọi một phương thức phía máy chủ trên một tài nguyên theo cách RESTful


142

Hãy nhớ rằng tôi có một sự hiểu biết thô sơ về REST. Giả sử tôi có URL này:

http://api.animals.com/v1/dogs/1/

Và bây giờ, tôi muốn làm cho máy chủ làm cho con chó sủa. Chỉ có máy chủ biết làm thế nào để làm điều này. Hãy nói rằng tôi muốn nó chạy trên một công việc CRON khiến con chó sủa cứ sau 10 phút cho đến hết đời. Cuộc gọi đó trông như thế nào? Tôi muốn làm điều này:

Yêu cầu URL:

ACTION http://api.animals.com/v1/dogs/1/

Trong cơ thể yêu cầu:

{"action":"bark"}

Trước khi bạn nổi giận với tôi vì đã tạo ra phương thức HTTP của riêng tôi, hãy giúp tôi và cho tôi biết ý tưởng tốt hơn về cách tôi nên gọi phương thức phía máy chủ theo cách RESTful. :)

CHỈNH SỬA

Một số làm rõ hơn xung quanh những gì phương pháp "vỏ cây" làm. Dưới đây là một số tùy chọn có thể dẫn đến các lệnh gọi API có cấu trúc khác nhau:

  1. sủa chỉ gửi một email đến dog.email và không có gì.
  2. bark gửi email đến dog.email và gia tăng dog.barkCount bằng 1.
  3. vỏ cây tạo ra một bản ghi "vỏ cây" mới với bản ghi bark.timestamp khi vỏ cây xảy ra. Nó cũng tăng dog.barkCount thêm 1.
  4. bark chạy một lệnh hệ thống để kéo phiên bản mới nhất của mã chó xuống từ Github. Sau đó nó sẽ gửi một tin nhắn văn bản tới dog.owner nói với họ rằng mã chó mới đang được sản xuất.

14
Thật thú vị, việc thêm tiền thưởng dường như đã thu hút các câu trả lời tệ hơn so với ban đầu của bạn ;-) Khi đánh giá câu trả lời hãy nhớ rằng: 1) Thông số kỹ thuật cho các động từ HTTP loại trừ bất kỳ lựa chọn nào khác ngoài POST. 2) REST không liên quan gì đến cấu trúc URL - đó là danh sách chung của các điều khoản (không trạng thái, bộ nhớ cache, lớp, giao diện thống nhất, v.v.) hơn là mang lại lợi ích (khả năng mở rộng, độ tin cậy, khả năng hiển thị, v.v.). 3) Thực tiễn hiện tại (chẳng hạn như sử dụng POST trong thông số RPC) hơn hẳn các nhà xác định đang tạo ra các quy tắc API của riêng họ. 4) REST yêu cầu giao diện thống nhất (theo thông số HTTP).
Raymond Hettinger

@Kirk bạn nghĩ gì về câu trả lời mới? Có bất cứ điều gì bạn vẫn muốn biết nhưng không được giải quyết trong bất kỳ trong số họ? Tôi rất vui lòng chỉnh sửa lại câu trả lời của mình nếu nó có thể hữu ích hơn.
Jordan

@RaymondHettinger PATCHcó thể thích hợp. Tôi giải thích tại sao đến cuối câu trả lời của tôi .
Jordan

PATCH sẽ chỉ thích hợp để tăng dog.barkCount thêm một. POST là phương thức gửi email, tạo bản ghi vỏ cây mới, chạy các lệnh để tải xuống từ Github hoặc kích hoạt tin nhắn văn bản. @Jordan, việc bạn đọc PATCH RFC là tưởng tượng nhưng có phần mâu thuẫn với mục đích là một biến thể của PUT để sửa đổi tài nguyên một phần. Tôi không nghĩ rằng bạn đang giúp OP bằng cách đưa ra các cách đọc khác thường về thông số kỹ thuật HTTP hơn là thừa nhận thực tiễn tiêu chuẩn sử dụng POST cho các cuộc gọi thủ tục từ xa.
Raymond Hettinger

@RaymondHettinger mà thực tế de facto tiêu chuẩn hóa POST? Tất cả các giao diện RPC tiêu chuẩn mà tôi đã thấy xác định tài nguyên theo thực thể (không phải RESTful), so với URI, do đó, một câu trả lời hợp lệ ưu tiên quy ước RPC sẽ cần phải khác thường, theo tôi nghĩ là không chấp nhận giá trị của RPC thông thường: một là tưởng tượng hoặc không nhất quán . Bạn không bao giờ có thể sai với POST vì đây là phương thức xử lý dữ liệu, nhưng có nhiều phương pháp cụ thể hơn. REST có nghĩa là đặt tên tài nguyên và mô tả các thay đổi trong trạng thái của chúng, không đặt tên các thủ tục thay đổi trạng thái. PATCH và POST đều mô tả các thay đổi trạng thái.
Jordan

Câu trả lời:


280

Tại sao lại nhắm đến một thiết kế RESTful?

Các nguyên tắc RESTful mang các tính năng giúp các trang web dễ dàng (cho một người dùng ngẫu nhiên của con người "lướt" chúng) vào thiết kế API dịch vụ web , do đó chúng dễ dàng cho lập trình viên sử dụng. REST không tốt vì nó là REST, nó tốt vì nó tốt. Và nó là tốt chủ yếu bởi vì nó là đơn giản .

Sự đơn giản của HTTP đơn giản (không có phong bì SOAP và các POSTdịch vụ quá tải URI đơn ), điều mà một số người có thể gọi là "thiếu tính năng" , thực sự là thế mạnh lớn nhất của nó . Ngay lập tức, HTTP yêu cầu bạn có địa chỉtrạng thái không trạng thái : hai quyết định thiết kế cơ bản giúp HTTP có thể mở rộng lên đến các trang web lớn hiện nay (và các dịch vụ lớn).

Nhưng REST không phải là bulltet bạc: Đôi khi, kiểu RPC ("Cuộc gọi thủ tục từ xa" - chẳng hạn như SOAP) có thể phù hợp và đôi khi các nhu cầu khác được ưu tiên hơn các ưu điểm của Web. Điều này là tốt Những gì chúng ta không thực sự thích là sự phức tạp không cần thiết . Quá thường xuyên một lập trình viên hoặc một công ty mang đến các Dịch vụ theo kiểu RPC cho một công việc mà HTTP cũ đơn giản có thể xử lý tốt. Hiệu quả là HTTP được giảm xuống một giao thức truyền tải cho một tải trọng XML khổng lồ giải thích những gì "thực sự" đang diễn ra (không phải là URI hoặc phương thức HTTP đưa ra manh mối về nó). Dịch vụ kết quả quá phức tạp, không thể gỡ lỗi và sẽ không hoạt động trừ khi khách hàng của bạn có thiết lập chính xác như nhà phát triển dự định.

Tương tự như vậy, mã Java / C # có thể không hướng đối tượng, chỉ sử dụng HTTP không tạo ra thiết kế RESTful. Người ta có thể bị cuốn vào suy nghĩ vội vàng về các dịch vụ của họ về các hành động và phương thức từ xa nên được gọi. Không có gì ngạc nhiên khi điều này chủ yếu sẽ kết thúc trong một dịch vụ RPC-Style (hoặc REST-RPC-hybrid). Bước đầu tiên là suy nghĩ khác biệt. Một thiết kế RESTful có thể đạt được bằng nhiều cách, một cách là nghĩ về ứng dụng của bạn về mặt tài nguyên, chứ không phải hành động:

Thay vì suy nghĩ về các hành động, nó có thể thực hiện ("thực hiện tìm kiếm địa điểm trên bản đồ") ...

... Cố gắng suy nghĩ về kết quả của những hành động đó ("danh sách các địa điểm trên bản đồ phù hợp với tiêu chí tìm kiếm").

Tôi sẽ lấy ví dụ dưới đây. (Khía cạnh quan trọng khác của REST là việc sử dụng HATEOAS - Tôi không đánh nó ở đây, nhưng tôi nói nhanh về nó ở một bài khác .)


Các vấn đề của thiết kế đầu tiên

Chúng ta hãy xem một thiết kế được đề xuất:

ACTION http://api.animals.com/v1/dogs/1/

Trước hết, chúng ta không nên xem xét việc tạo một động từ HTTP mới ( ACTION). Nói chung, điều này là không mong muốn vì nhiều lý do:

  • (1) Chỉ được cung cấp URI dịch vụ, làm thế nào một lập trình viên "ngẫu nhiên" sẽ biết ACTIONđộng từ tồn tại?
  • (2) nếu lập trình viên biết nó tồn tại, làm thế nào anh ta biết ngữ nghĩa của nó? Động từ đó có nghĩa là gì?
  • (3) những tính chất nào (an toàn, không cần thiết) người ta nên mong đợi động từ đó có?
  • (4) nếu lập trình viên có một máy khách rất đơn giản chỉ xử lý các động từ HTTP tiêu chuẩn thì sao?
  • (5) ...

Bây giờ hãy xem xét việc sử dụngPOST (Tôi sẽ thảo luận về lý do tại sao bên dưới, hãy hiểu ý tôi ngay bây giờ):

POST /v1/dogs/1/ HTTP/1.1
Host: api.animals.com

{"action":"bark"}

Điều này thể ổn ... nhưng chỉ khi :

  • {"action":"bark"}là một tài liệu; và
  • /v1/dogs/1/là một URI "bộ xử lý tài liệu" (giống như nhà máy). "Bộ xử lý tài liệu" là một URI mà bạn chỉ cần "ném mọi thứ" và "quên" về chúng - bộ xử lý có thể chuyển hướng bạn đến một tài nguyên mới được tạo sau khi "ném". Ví dụ: URI để đăng tin nhắn tại dịch vụ môi giới tin nhắn, sau khi đăng sẽ chuyển hướng bạn đến URI hiển thị trạng thái xử lý tin nhắn.

Tôi không biết nhiều về hệ thống của bạn, nhưng tôi đã cá rằng cả hai đều không đúng:

  • {"action":"bark"} không phải là một tài liệu , nó thực sự là phương pháp mà bạn đang cố gắng lén lút vào dịch vụ; và
  • các /v1/dogs/1/URI đại diện cho một "con chó" tài nguyên (có thể là con chó với id==1) và không phải là một bộ vi xử lý tài liệu.

Vì vậy, tất cả những gì chúng ta biết bây giờ là thiết kế ở trên không quá RESTful, nhưng đó chính xác là gì? Điều gì là xấu về nó? Về cơ bản, nó là xấu vì đó là URI phức tạp với ý nghĩa phức tạp. Bạn không thể suy ra bất cứ điều gì từ nó. Làm thế nào một lập trình viên biết một con chó có một barkhành động có thể được bí mật truyền POSTvào nó?


Thiết kế các lệnh gọi API của câu hỏi của bạn

Vì vậy, hãy cắt giảm để theo đuổi và cố gắng thiết kế những tiếng sủa đó một cách khéo léo bằng cách suy nghĩ về các nguồn lực . Cho phép tôi trích dẫn cuốn sách Dịch vụ web đầy đủ :

Một POSTyêu cầu là một nỗ lực để tạo ra một nguồn lực mới từ một hiện có. Tài nguyên hiện có có thể là cha mẹ của cái mới theo nghĩa cấu trúc dữ liệu, cách gốc của cây là cha mẹ của tất cả các nút lá của nó. Hoặc tài nguyên hiện có có thể là tài nguyên "nhà máy" đặc biệt với mục đích duy nhất là tạo ra các tài nguyên khác. Đại diện được gửi cùng với một POSTyêu cầu mô tả trạng thái ban đầu của tài nguyên mới. Như với PUT, một POSTyêu cầu hoàn toàn không cần bao gồm một đại diện.

Theo mô tả ở trên, chúng ta có thể thấy rằng barkcó thể được mô hình hóa như là một nguồn con của mộtdog (vì một con barkđược chứa trong một con chó, nghĩa là, một con chó sủa bị "sủa" bởi một con chó).

Từ lý do đó, chúng tôi đã có:

  • Phương pháp là POST
  • Tài nguyên là /barks, nguồn cung cấp con chó : /v1/dogs/1/barks, đại diện cho một bark"nhà máy". URI đó là duy nhất cho mỗi con chó (vì nó nằm dưới /v1/dogs/{id}).

Bây giờ mỗi trường hợp danh sách của bạn có một hành vi cụ thể.

1. vỏ cây chỉ gửi e-mail đến dog.emailvà ghi lại không có gì.

Thứ nhất, việc sủa (gửi e-mail) là một nhiệm vụ đồng bộ hay không đồng bộ? Thứ hai, barkyêu cầu có yêu cầu bất kỳ tài liệu nào (e-mail, có thể) hoặc nó trống?


1.1 vỏ cây gửi e-mail đến dog.emailvà ghi lại không có gì (như một nhiệm vụ đồng bộ)

Trường hợp này là đơn giản. Một cuộc gọi đến barkstài nguyên nhà máy mang lại một vỏ cây (một e-mail được gửi) ngay lập tức và phản hồi (nếu OK hoặc không) được đưa ra ngay lập tức:

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

Vì nó ghi lại (thay đổi) không có gì, 200 OKlà đủ. Nó cho thấy rằng mọi thứ đã đi như mong đợi.


1.2 vỏ cây gửi e-mail đến dog.emailvà ghi lại không có gì (như một nhiệm vụ không đồng bộ)

Trong trường hợp này, khách hàng phải có cách theo dõi barknhiệm vụ. Các barknhiệm vụ sau đó phải là một tài nguyên với riêng URI nó .:

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

Bằng cách này, mỗi barklà có thể truy nguyên. Sau đó, khách hàng có thể đưa ra một GETđến barkURI để biết đó là tình trạng hiện thời. Thậm chí có thể sử dụng một DELETEđể hủy bỏ nó.


2. vỏ cây gửi e-mail đến dog.emailvà sau đó tăng thêm dog.barkCount1

Điều này có thể phức tạp hơn, nếu bạn muốn cho khách hàng biết dogtài nguyên được thay đổi:

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

Trong trường hợp này, locationmục đích của người đứng đầu là để cho khách hàng biết rằng anh ta nên xem qua dog. Từ RFC HTTP về303 :

Phương thức này tồn tại chủ yếu để cho phép đầu ra của POSTtập lệnh được kích hoạt để chuyển hướng tác nhân người dùng đến tài nguyên đã chọn.

Nếu tác vụ không đồng bộ, cần có một barknguồn cung cấp phụ giống như 1.2tình huống và 303phải được trả lại vào lúc GET .../barks/Ynhiệm vụ hoàn thành.


3. vỏ cây tạo ra một barkbản ghi "" mới với bark.timestampghi âm khi vỏ cây xảy ra. Nó cũng tăng thêm dog.barkCount1.

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

Ở đây, barkmột được tạo do yêu cầu, vì vậy trạng thái 201 Createdđược áp dụng.

Nếu việc tạo không đồng bộ, thay vào đó , 202 Acceptedcần phải có ( như RFC HTTP nói ).

Dấu thời gian được lưu là một phần của barktài nguyên và có thể được truy xuất bằng a GET. Con chó cập nhật cũng có thể được "ghi lại" trong đó GET dogs/X/barks/Y.


4. vỏ cây chạy một lệnh hệ thống để kéo phiên bản mới nhất của mã chó xuống từ Github. Sau đó, nó sẽ gửi một tin nhắn văn bản để dog.ownernói với họ rằng mã chó mới đang được sản xuất.

Từ ngữ của cái này rất phức tạp, nhưng nó khá nhiều là một nhiệm vụ không đồng bộ đơn giản:

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

Sau đó, khách hàng sẽ phát hành GETs để /v1/dogs/1/barks/a65h44biết trạng thái hiện tại (nếu mã được kéo, e-mail đã được gửi cho chủ sở hữu và như vậy). Bất cứ khi nào con chó thay đổi, a 303là đáng khen ngợi.


Gói lại

Trích dẫn Roy Fielding :

Điều duy nhất REST yêu cầu các phương thức là chúng được xác định thống nhất cho tất cả các tài nguyên (nghĩa là để các trung gian không phải biết loại tài nguyên để hiểu ý nghĩa của yêu cầu).

Trong các ví dụ trên, POSTđược thiết kế thống nhất. Nó sẽ làm cho con chó " bark". Điều đó không an toàn (có nghĩa là vỏ cây có ảnh hưởng đến tài nguyên), cũng không phải là idempotent (mỗi yêu cầu mang lại một cái mới bark), rất phù hợp với POSTđộng từ.

Một lập trình viên sẽ biết: a POSTđể barksmang lại a bark. Mã trạng thái phản hồi (cũng với phần thân thực thể và tiêu đề khi cần thiết) thực hiện công việc giải thích những gì đã thay đổi và cách khách hàng có thể và nên tiến hành.

Lưu ý: Các nguồn chính được sử dụng là: sách " Dịch vụ web đầy đủ ", blog của HTTP RFCRoy Fielding .




Biên tập:

Câu hỏi và do đó, câu trả lời đã thay đổi khá nhiều kể từ khi chúng được tạo lần đầu tiên. Câu hỏi ban đầu hỏi về thiết kế của một URI như:

ACTION http://api.animals.com/v1/dogs/1/?action=bark

Dưới đây là lời giải thích tại sao nó không phải là một lựa chọn tốt:

Làm thế nào khách hàng nói với máy chủ PHẢI LÀM GÌ với dữ liệu là thông tin phương pháp .

  • Các dịch vụ web RESTful truyền tải thông tin phương thức trong phương thức HTTP.
  • Các dịch vụ RPC-Style và SOAP điển hình giữ cho chúng trong tiêu đề thực thể và HTTP.

Phần nào của dữ liệu [máy khách muốn máy chủ] hoạt động là thông tin phạm vi .

  • Các dịch vụ RESTful sử dụng URI. Các dịch vụ SOAP / RPC-Style một lần nữa sử dụng các tiêu đề thực thể và HTTP.

Ví dụ: lấy URI của Google http://www.google.com/search?q=DOG. Ở đó, thông tin phương pháp là GETvà thông tin phạm vi là /search?q=DOG.

Mẩu chuyện dài:

  • Trong các kiến ​​trúc RESTful , thông tin phương thức đi vào phương thức HTTP.
  • Trong Kiến trúc hướng tài nguyên , thông tin phạm vi đi vào URI.

Và quy tắc của ngón tay cái:

Nếu phương thức HTTP không khớp với thông tin phương thức, thì dịch vụ không phải là RESTful. Nếu thông tin phạm vi không có trong URI, thì dịch vụ không hướng đến tài nguyên.

Bạn có thể đặt "hành động" "vỏ cây" trong URL (hoặc trong phần thân thực thể) và sử dụng . Không có vấn đề ở đó, nó hoạt động và có thể là cách đơn giản nhất để làm điều đó, nhưng đây không phải là RESTful .POST

Để giữ cho dịch vụ của bạn thực sự RESTful, bạn có thể phải lùi lại một bước và suy nghĩ về những gì bạn thực sự muốn làm ở đây (nó sẽ có tác dụng gì đối với tài nguyên).

Tôi không thể nói về nhu cầu kinh doanh cụ thể của bạn, nhưng hãy để tôi cho bạn một ví dụ: Hãy xem xét một dịch vụ đặt hàng RESTful trong đó các đơn đặt hàng tại URI như thế nào example.com/order/123.

Bây giờ nói rằng chúng tôi muốn hủy một đơn đặt hàng, làm thế nào chúng ta sẽ làm điều đó? Người ta có thể bị cám dỗ để nghĩ rằng đó là một "hành động" "hủy bỏ " và thiết kế nó như là POST example.com/order/123?do=cancel.

Đó không phải là RESTful, như chúng ta đã nói ở trên. Thay vào đó, chúng ta có thể PUTlà một đại diện mới của ordervới một canceledyếu tố gửi đến true:

PUT /order/123 HTTP/1.1
Content-Type: application/xml

<order id="123">
    <customer id="89987">...</customer>
    <canceled>true</canceled>
    ...
</order>

Và đó là nó. Nếu đơn đặt hàng không thể bị hủy, một mã trạng thái cụ thể có thể được trả lại. (Một thiết kế nguồn phụ, như POST /order/123/canceledvới cơ thể thực thể truecó thể, để đơn giản, cũng có sẵn.)

Trong kịch bản cụ thể của bạn, bạn có thể thử một cái gì đó tương tự. Bằng cách đó, trong khi một con chó đang sủa, ví dụ, GETtại /v1/dogs/1/có thể bao gồm thông tin đó (ví dụ <barking>true</barking>) . Hoặc ... nếu điều đó quá phức tạp, hãy nới lỏng yêu cầu RESTful của bạn và kiên trì thực hiện POST.

Cập nhật:

Tôi không muốn làm cho câu trả lời quá lớn, nhưng phải mất một thời gian để hiểu được việc phơi bày một thuật toán (một hành động ) dưới dạng một tập hợp các tài nguyên. Thay vì suy nghĩ về các hành động ( "tìm kiếm địa điểm trên bản đồ" ), người ta cần suy nghĩ về kết quả của hành động đó ( "danh sách các địa điểm trên bản đồ phù hợp với tiêu chí tìm kiếm" ).

Bạn có thể thấy mình quay lại bước này nếu bạn thấy rằng thiết kế của bạn không phù hợp với giao diện thống nhất của HTTP.

Các biến truy vấn thông tin phạm vi , nhưng không biểu thị các tài nguyên mới ( /post?lang=enrõ ràng là cùng một tài nguyên với /post?lang=jp, chỉ là một đại diện khác). Thay vào đó, chúng được sử dụng để truyền đạt trạng thái máy khách (như ?page=10, để trạng thái đó không được giữ trong máy chủ; ?lang=encũng là một ví dụ ở đây) hoặc các tham số đầu vào cho tài nguyên thuật toán ( /search?q=dogs, /dogs?code=1). Một lần nữa, không phải là tài nguyên riêng biệt.

Thuộc tính (phương thức) của động từ HTTP:

Một điểm rõ ràng khác cho thấy ?action=somethingtrong URI không phải là RESTful, là các thuộc tính của động từ HTTP:

  • GETHEADđược an toàn (và bình thường);
  • PUTDELETEchỉ là idempotent;
  • POST không phải là.

An toàn : A GEThoặc HEADyêu cầu là yêu cầu đọc một số dữ liệu, không phải yêu cầu thay đổi bất kỳ trạng thái máy chủ nào. Khách hàng có thể thực hiện GEThoặc HEADyêu cầu 10 lần và nó giống như thực hiện một lần hoặc hoàn toàn không bao giờ thực hiện .

Idempotence : Một phép toán idempotent trong một hoạt động có cùng tác dụng cho dù bạn áp dụng nó một lần hay nhiều lần (trong toán học, nhân với số 0 là idempotent). Nếu bạn DELETEtài nguyên một lần, xóa lại sẽ có tác dụng tương tự (tài nguyên GONEđã có).

POSTkhông an toàn cũng không bình thường. Thực hiện hai POSTyêu cầu giống hệt nhau đối với tài nguyên 'nhà máy' có thể sẽ dẫn đến hai tài nguyên cấp dưới chứa cùng một thông tin. Với tình trạng quá tải (phương thức trong URI hoặc thực thể) POST, tất cả các cược đã tắt.

Cả hai thuộc tính này đều quan trọng đối với sự thành công của giao thức HTTP (trên các mạng không đáng tin cậy!): Bạn đã cập nhật ( GET) trang bao nhiêu lần mà không cần đợi cho đến khi nó được tải đầy đủ?

Tạo một hành động và đặt nó vào URL rõ ràng phá vỡ hợp đồng của các phương thức HTTP. Một lần nữa, công nghệ cho phép bạn, bạn có thể làm điều đó, nhưng đó không phải là thiết kế RESTful.


Tôi tranh cãi với ý tưởng rằng gọi một hành động trên máy chủ, được chỉ định là một hành động trong URL, không phải là RESTful. POSTđược thiết kế để "cung cấp một khối dữ liệu ... cho quy trình xử lý dữ liệu" . Có vẻ như rất nhiều người phân biệt tài nguyên với hành động, nhưng thực sự hành động chỉ là một loại tài nguyên.
Jacob Stevens

1
@JacobStevens OP đã thay đổi câu hỏi một chút vì vậy tôi phải cập nhật câu trả lời của mình để làm cho câu hỏi trực tiếp hơn (kiểm tra câu hỏi ban đầu , có thể bạn sẽ thấy ý tôi là gì). Tôi đồng ý với POSTviệc "cung cấp một khối dữ liệu ... cho quy trình xử lý dữ liệu", nhưng sự khác biệt thực sự là, một khối dữ liệu , không phải là một khối dữ liệu và quy trình (hành động, phương thức, lệnh) thực hiện sau đó. Đó là POSTquá tải, và POSTquá tải là thiết kế kiểu RPC, không phải RESTful.
acdcjunior

Tôi đoán rằng logic hành động / phương thức sẽ được lưu trữ trên máy chủ, nếu không thì mục đích của cuộc gọi sẽ là gì? Trong trường hợp bạn mô tả, tôi đồng ý, đó sẽ không phải là thiết kế tốt. Nhưng phương thức hoặc chương trình con thực hiện hành động sẽ được chỉ định bởi URI (đó là một lý do khác khiến tài nguyên hành động được chỉ định là động từ ở cuối URL là hữu ích và RESTful, mặc dù nhiều người khuyên chống lại nó).
Jacob Stevens

6
Câu trả lời chúng tôi cập nhật. Nó hơi dài bởi vì một lời giải thích kỹ lưỡng dường như cần thiết ("Hãy nhớ rằng tôi có một sự hiểu biết thô sơ về REST."). Đó là một cuộc đấu tranh để làm cho nó hoàn chỉnh rõ ràng nhất có thể. Hy vọng nó hữu ích theo một cách nào đó.
acdcjunior

2
Giải thích tuyệt vời, tôi đã bỏ phiếu nhưng tiêu đề Vị trí không nên được sử dụng trong 202 phản hồi được chấp nhận. Nó dường như là một cách giải thích sai mà nhiều người làm từ RFC. Kiểm tra stackoverflow.com/questions/26199228/
Delmo

6

Tôi đã trả lời trước đó , nhưng câu trả lời này mâu thuẫn với câu trả lời cũ của tôi và tuân theo một chiến lược khác biệt hơn nhiều để đi đến một giải pháp. Nó cho thấy cách yêu cầu HTTP được xây dựng từ các khái niệm xác định REST và HTTP. Nó cũng sử dụng PATCHthay vì POSThoặc PUT.

Nó đi qua các ràng buộc REST, sau đó là các thành phần của HTTP, sau đó là một giải pháp khả thi.

NGHỈ NGƠI

REST là một tập hợp các ràng buộc dự định được áp dụng cho một hệ thống hypermedia phân tán để làm cho nó có thể mở rộng được. Ngay cả để hiểu ý nghĩa của nó trong bối cảnh điều khiển một hành động từ xa, bạn phải nghĩ đến việc điều khiển từ xa một hành động như một phần của hệ thống hypermedia phân tán - một phần của hệ thống để khám phá, xem và sửa đổi thông tin được kết nối với nhau. Nếu đó là rắc rối nhiều hơn giá trị của nó, thì có lẽ không tốt để cố gắng làm cho nó HOÀN TOÀN. Nếu bạn chỉ muốn GUI loại "bảng điều khiển" trên máy khách có thể kích hoạt các hành động trên máy chủ thông qua cổng 80, thì bạn có thể muốn có giao diện RPC đơn giản như JSON-RPC thông qua các yêu cầu / phản hồi HTTP hoặc WebSocket.

Nhưng REST là một cách suy nghĩ hấp dẫn và ví dụ trong câu hỏi có thể dễ dàng mô hình hóa với giao diện RESTful, vì vậy hãy tham gia thử thách để giải trí và giáo dục.

REST được xác định bởi bốn ràng buộc giao diện:

xác định nguồn lực; thao túng tài nguyên thông qua các đại diện; tin nhắn tự mô tả; và, hypermedia là động cơ của trạng thái ứng dụng.

Bạn hỏi làm thế nào bạn có thể xác định một giao diện, đáp ứng các ràng buộc này, qua đó một máy tính nói với một máy tính khác để tạo ra tiếng chó sủa. Cụ thể, bạn muốn giao diện của mình là HTTP và bạn không muốn loại bỏ các tính năng tạo HTTP RESTful khi được sử dụng như dự định.

Hãy bắt đầu với ràng buộc đầu tiên: xác định tài nguyên .

Bất kỳ thông tin nào có thể được đặt tên đều có thể là tài nguyên: tài liệu hoặc hình ảnh, dịch vụ tạm thời (ví dụ: "thời tiết hôm nay ở Los Angeles"), một tập hợp các tài nguyên khác, một đối tượng không ảo (ví dụ như một người), v.v. .

Vì vậy, một con chó là một nguồn tài nguyên. Nó cần phải được xác định.

Chính xác hơn, tài nguyên R là hàm thành viên thay đổi theo thời gian M R ( t ), theo thời gian t ánh xạ tới một tập hợp các thực thể hoặc giá trị, tương đương. Các giá trị trong tập hợp có thể là biểu diễn tài nguyên và / hoặc định danh tài nguyên .

Bạn mô hình một con chó bằng cách lấy một bộ định danh và đại diện và nói rằng tất cả chúng được liên kết với nhau tại một thời điểm nhất định. Hiện tại, chúng ta hãy sử dụng định danh "con chó số 1". Điều đó đưa chúng ta đến các ràng buộc thứ hai và thứ ba: biểu diễn tài nguyêntự mô tả .

Các thành phần REST thực hiện các hành động trên một tài nguyên bằng cách sử dụng một biểu diễn để nắm bắt trạng thái hiện tại hoặc dự định của tài nguyên đó và chuyển biểu diễn đó giữa các thành phần. Một đại diện là một chuỗi các byte, cộng với siêu dữ liệu đại diện để mô tả các byte đó.

Sau đây là một chuỗi các byte nắm bắt trạng thái dự định của con chó, tức là đại diện mà chúng ta muốn được liên kết với mã định danh "con chó số 1" (lưu ý rằng nó chỉ đại diện cho một phần của trạng thái vì nó không liên quan đến tên của con chó, sức khỏe hoặc thậm chí quá khứ sủa):

Nó đã sủa cứ sau 10 phút kể từ khi thay đổi trạng thái này được thực hiện và sẽ tiếp tục vô thời hạn.

Nó được cho là được gắn vào siêu dữ liệu mô tả nó. Siêu dữ liệu này có thể hữu ích:

Đó là một tuyên bố tiếng Anh. Nó mô tả một phần của trạng thái dự định. Nếu nó được nhận nhiều lần, chỉ cho phép người đầu tiên có hiệu lực.

Cuối cùng, chúng ta hãy nhìn vào ràng buộc thứ tư: HATEOAS .

REST ... xem một ứng dụng như một cấu trúc thông tin gắn kết và kiểm soát các lựa chọn thay thế thông qua đó người dùng có thể thực hiện một tác vụ mong muốn. Ví dụ, tìm kiếm một từ trong từ điển trực tuyến là một ứng dụng, như đang tham quan qua một bảo tàng ảo hoặc xem xét một tập các ghi chú lớp học để nghiên cứu cho một bài kiểm tra. ... Trạng thái kiểm soát tiếp theo của một ứng dụng nằm trong biểu diễn của tài nguyên được yêu cầu đầu tiên, do đó, việc có được đại diện đầu tiên là ưu tiên. ... Do đó, ứng dụng mô hình là một công cụ chuyển từ trạng thái này sang trạng thái tiếp theo bằng cách kiểm tra và lựa chọn trong số các chuyển đổi trạng thái thay thế trong bộ biểu diễn hiện tại.

Trong giao diện RESTful, máy khách nhận được một biểu diễn tài nguyên để tìm ra cách nó sẽ nhận hoặc gửi một đại diện. Phải có một đại diện ở đâu đó trong ứng dụng mà khách hàng có thể tìm ra cách nhận hoặc gửi tất cả các đại diện mà nó có thể nhận hoặc gửi, ngay cả khi nó tuân theo một chuỗi các đại diện để đến thông tin đó. Điều này có vẻ đơn giản:

Khách hàng yêu cầu đại diện cho một tài nguyên được xác định là trang chủ; để đáp lại, nó nhận được một đại diện có chứa một định danh của mỗi con chó mà khách hàng có thể muốn. Khách hàng trích xuất một mã định danh từ nó và hỏi dịch vụ làm thế nào nó có thể tương tác với con chó được xác định và dịch vụ nói rằng khách hàng có thể gửi một tuyên bố bằng tiếng Anh mô tả một phần trạng thái dự định của con chó. Sau đó, khách hàng gửi một tuyên bố như vậy và nhận được một thông báo thành công hoặc một thông báo lỗi.

HTTP

HTTP thực hiện các ràng buộc REST như sau:

xác định tài nguyên : URI

đại diện tài nguyên : thực thể-cơ thể

tự mô tả : phương thức hoặc mã trạng thái, các tiêu đề và có thể là các phần của phần thân thực thể (ví dụ: URI của lược đồ XML)

HATEOAS : siêu liên kết

Bạn đã quyết định http://api.animals.com/v1/dogs/1là URI. Giả sử khách hàng đã nhận được điều này từ một số trang trên trang web.

Hãy sử dụng phần thân thực thể này (giá trị của nextdấu thời gian; giá trị của 0phương tiện 'khi nhận được yêu cầu này'):

{"barks": {"next": 0, "frequency": 10}}

Bây giờ chúng ta cần một phương pháp. PATCH phù hợp với mô tả "một phần của trạng thái dự định" mà chúng tôi đã quyết định:

Phương thức PATCH yêu cầu một tập hợp các thay đổi được mô tả trong thực thể yêu cầu được áp dụng cho tài nguyên được xác định bởi URI yêu cầu.

Và một số tiêu đề:

Để chỉ ngôn ngữ của cơ thể thực thể: Content-Type: application/json

Để đảm bảo nó chỉ xảy ra một lần: If-Unmodified-Since: <date/time this was first sent>

Và chúng tôi có một yêu cầu:

PATCH /v1/dogs/1/ HTTP/1.1
Host: api.animals.com
Content-Type: application/json
If-Unmodified-Since: <date/time this was first sent>
[other headers]

{"barks": {"next": 0, "frequency": 10}}

Khi thành công, khách hàng sẽ nhận được 204mã trạng thái để phản hồi hoặc 205nếu đại diện của /v1/dogs/1/đã thay đổi để phản ánh lịch trình sủa mới.

Khi thất bại, nó sẽ nhận được một 403và một thông điệp hữu ích tại sao.

Không cần thiết cho REST để dịch vụ phản ánh lịch trình vỏ cây trong một đại diện để đáp ứng GET /v1/dogs/1/, nhưng sẽ có ý nghĩa nhất nếu một đại diện JSON bao gồm điều này:

"barks": {
    "previous": [x_1, x_2, ..., x_n],
    "next": x_n,
    "frequency": 10
}

Hãy coi công việc định kỳ là một chi tiết triển khai mà máy chủ ẩn khỏi giao diện. Đó là vẻ đẹp của giao diện chung. Máy khách không cần biết máy chủ làm gì sau hậu trường; tất cả những gì nó quan tâm là dịch vụ hiểu và đáp ứng với những thay đổi trạng thái được yêu cầu.


3

Hầu hết mọi người sử dụng POST cho mục đích này. Nó phù hợp để thực hiện "mọi hoạt động không an toàn hoặc không cần thiết khi không có phương pháp HTTP nào khác có vẻ phù hợp".

Các API như XMLRPC sử dụng POST để kích hoạt các hành động có thể chạy mã tùy ý. "Hành động" được bao gồm trong dữ liệu POST:

POST /RPC2 HTTP/1.0
User-Agent: Frontier/5.1.2 (WinNT)
Host: betty.userland.com
Content-Type: text/xml
Content-length: 181

<?xml version="1.0"?>
<methodCall>
   <methodName>examples.getStateName</methodName>
   <params>
      <param>
         <value><i4>41</i4></value>
         </param>
      </params>
   </methodCall>

RPC là ví dụ được đưa ra để chỉ ra rằng POST là sự lựa chọn thông thường của các động từ HTTP cho các phương thức phía máy chủ. Đây là những suy nghĩ của Roy Fielding về POST - anh ta nói khá nhiều về việc sử dụng các phương thức HTTP như được chỉ định.

Lưu ý rằng bản thân RPC không quá RESTful vì nó không được định hướng tài nguyên. Nhưng nếu bạn cần trạng thái không trạng thái, bộ nhớ đệm hoặc phân lớp, không khó để thực hiện các phép biến đổi phù hợp. Xem http://blog.perinfapi.com/2012/opinionated-rpc-apis-vs-restful-apis/ để biết ví dụ.


Tôi nghĩ rằng bạn sẽ URLencode các thông số không đặt nó trong chuỗi truy vấn
tacos_tacos_tacos

@Kirk Có, nhưng với một sửa đổi nhỏ, hãy bỏ dấu gạch chéo về phía trước: POST api.animals.com/v1/dogs1?action=bark
Raymond Hettinger

nếu bạn làm theo lời khuyên trong câu trả lời này, hãy nhớ rằng API kết quả sẽ không phải là RESTful.
Nicholas Shanks

2
Đây không phải là RESTful HTTP thiết lập URL là định danh của tài nguyên và URL /RPC2không có gì để xác định tài nguyên - nó xác định công nghệ máy chủ. Thay vào đó, điều này sử dụng methodNameđể cố gắng 'xác định' tài nguyên '- nhưng ngay cả khi đó, nó không được hưởng lợi từ sự phân biệt danh từ / động từ; điều duy nhất giống như động từ ở đây là methodCall. Điều này giống như 'lấy tên trạng thái' thay vì 'lấy tên trạng thái' - cái sau có ý nghĩa hơn rất nhiều.
Jordan

+1 cho các liên kết; rất nhiều thông tin và thí nghiệm "RPC có ý kiến" là sáng tạo.
Jordan

2

POSTphương thức HTTP được thiết kế cho

Cung cấp một khối dữ liệu ... cho quy trình xử lý dữ liệu

Các phương thức phía máy chủ xử lý các hành động không được ánh xạ CRUD là những gì Roy Fielding dự định với REST, vì vậy bạn rất tốt ở đó và đó là lý do tại sao POSTđược coi là không bình thường. POSTsẽ xử lý hầu hết việc đăng dữ liệu lên các phương thức phía máy chủ để xử lý thông tin.

Điều đó nói rằng, trong kịch bản sủa chó của bạn, nếu bạn muốn một tiếng sủa phía máy chủ được thực hiện cứ sau 10 phút, nhưng vì lý do nào đó cần kích hoạt bắt nguồn từ một khách hàng, PUTsẽ phục vụ mục đích tốt hơn, vì tính không hợp lý của nó. Chà, đúng theo kịch bản này, không có rủi ro rõ ràng về nhiều yêu cầu POST khiến con chó của bạn kêu meo meo, nhưng dù sao đó cũng là mục đích của hai phương pháp tương tự. Câu trả lời của tôi cho một câu hỏi SO tương tự có thể hữu ích cho bạn.


1
PUT so với POST là tất cả về URL. Đoạn thứ ba sau 9.6 PUT cho biết mục đích của hai phương thức là vì vậy PUTURL đề cập đến nội dung của khách hàng nên được thay thếPOSTURL đề cập đến nội dung của khách hàng nên xử lý nội dung của khách hàng.
Jordan

1

Nếu chúng ta giả sử Barking là một nguồn tài nguyên bên trong / phụ thuộc / phụ mà người tiêu dùng có thể hành động, thì chúng ta có thể nói:

POST http://api.animals.com/v1/dogs/1/bark

con chó số 1 sủa

GET http://api.animals.com/v1/dogs/1/bark

trả về dấu thời gian vỏ cây cuối cùng

DELETE http://api.animals.com/v1/dogs/1/bark

không áp dụng! nên bỏ qua nó


Đây chỉ là RESTful nếu bạn coi /v1/dogs/1/barklà tài nguyên mỗi lầnPOSTlà mô tả về cách thay đổi trạng thái bên trong của tài nguyên đó. Tôi thấy rằng nó có ý nghĩa hơn khi chỉ coi /v1/dogs/1/là một tài nguyên và để chỉ ra trong cơ thể thực thể rằng nó nên sủa.
Jordan

mmm .. tốt, đó là một tài nguyên mà bạn có thể thay đổi trạng thái của nó. Bởi vì kết quả của việc thay đổi trạng thái của nó là gây ra tiếng ồn, không làm cho nó ít tài nguyên hơn! Bạn đang xem Bark như một động từ (đó là) đó là lý do tại sao bạn không thể coi đó là một tài nguyên. Tôi đang xem nó như là một tài nguyên phụ thuộc mà trạng thái của nó có thể được thay đổi và vì trạng thái của nó là boolean, tôi không thấy bất kỳ lý do nào để đề cập đến nó trong cơ thể thực thể. Đó chỉ là ý kiến ​​của tôi.
bolbol

1

Bản sửa đổi trước đó của một số câu trả lời đề nghị bạn sử dụng RPC. Bạn không cần phải tìm đến RPC vì nó hoàn toàn có thể làm những gì bạn muốn trong khi tôn trọng những ràng buộc REST.

Thứ nhất, không đặt tham số hành động trong URL. URL xác định những gì bạn đang áp dụng hành động và các tham số truy vấn là một phần của URL. Nó nên được suy nghĩ hoàn toàn như một danh từ. http://api.animals.com/v1/dogs/1/?action=barklà một tài nguyên khác nhau - một danh từ khác - đến http://api.animals.com/v1/dogs/1/. [nb Asker đã xóa ?action=barkURI khỏi câu hỏi.] Ví dụ: so sánh http://api.animals.com/v1/dogs/?id=1với http://api.animals.com/v1/dogs/?id=2. Tài nguyên khác nhau, chỉ được phân biệt bởi chuỗi truy vấn. Vì vậy, hành động của yêu cầu của bạn, trừ khi nó tương ứng trực tiếp với loại phương thức hiện có (TRACE, TÙY CHỌN, ĐẦU, NHẬN, XÓA, v.v.) phải được xác định trong thân yêu cầu.

Tiếp theo, quyết định xem hành động đó có phải là " idempotent " hay không , nghĩa là nó có thể được lặp lại mà không có tác dụng phụ (xem đoạn tiếp theo để biết thêm giải thích). Ví dụ: đặt giá trị thành true có thể được lặp lại nếu máy khách không chắc chắn rằng hiệu ứng mong muốn đã xảy ra. Họ gửi yêu cầu một lần nữa và giá trị vẫn đúng. Thêm 1 vào một số không phải là idempotent. Nếu máy khách gửi lệnh Add1, không chắc nó đã hoạt động và gửi lại, máy chủ có thêm một hoặc hai không? Khi bạn đã xác định điều đó, bạn sẽ ở vị trí tốt hơn để lựa chọn giữa PUTPOSTcho phương pháp của mình.

Idempotent có nghĩa là một yêu cầu có thể được lặp lại mà không thay đổi kết quả. Những hiệu ứng này không bao gồm đăng nhập và hoạt động quản trị máy chủ khác. Sử dụng ví dụ thứ nhất và thứ hai của bạn, gửi hai email cho cùng một người sẽ dẫn đến một trạng thái khác với gửi một email (người nhận có hai trong hộp thư đến của họ, họ có thể coi là thư rác), vì vậy tôi chắc chắn sẽ sử dụng POST cho điều đó . Nếu barkCount trong ví dụ 2 được người dùng API của bạn nhìn thấy hoặc ảnh hưởng đến thứ gì đó có thể nhìn thấy được của khách hàng, thì đó cũng là thứ sẽ khiến yêu cầu không bình thường. Nếu nó chỉ được xem bởi bạn thì nó được tính là đăng nhập máy chủ và nên được bỏ qua khi xác định idempotentcy.

Cuối cùng, xác định xem hành động bạn muốn thực hiện có thể được dự kiến ​​sẽ thành công ngay lập tức hay không. BarkDog là một hành động hoàn thành nhanh chóng. RunMarathon thì không. Nếu hành động của bạn chậm, hãy xem xét trả lại một 202 Accepted, với một URL trong phần phản hồi để người dùng thăm dò ý kiến ​​xem hành động đó đã hoàn thành chưa. Ngoài ra, yêu cầu người dùng POST vào một URL danh sách như thế /marathons-in-progress/và sau đó khi hành động được thực hiện, hãy chuyển hướng chúng từ URL ID đang tiến hành sang /marathons-complete/URL.
Đối với các trường hợp cụ thể # 1 và # 2, tôi sẽ có máy chủ lưu trữ một hàng đợi và máy khách gửi các lô địa chỉ cho nó. Hành động sẽ không phải là SendEmails, mà giống như AddToDispatchQueue. Sau đó, máy chủ có thể thăm dò hàng đợi để xem có địa chỉ email nào đang chờ không và gửi email nếu tìm thấy địa chỉ nào. Sau đó, nó cập nhật hàng đợi để chỉ ra rằng hành động đang chờ xử lý đã được thực hiện. Bạn sẽ có một URI khác hiển thị cho khách hàng trạng thái hiện tại của hàng đợi. Để tránh gửi email hai lần, máy chủ cũng có thể ghi nhật ký người đã gửi email này và kiểm tra từng địa chỉ để đảm bảo rằng nó không bao giờ gửi hai đến cùng một địa chỉ, ngay cả khi bạn POST cùng một danh sách hai lần hàng đợi

Khi chọn một URI cho bất cứ điều gì, hãy cố gắng nghĩ về nó như một kết quả, không phải là một hành động. Ví dụ google.com/search?q=dogscho thấy kết quả tìm kiếm từ "chó". Nó không cần thiết thực hiện tìm kiếm.

Các trường hợp # 3 và # 4 từ danh sách của bạn cũng không phải là hành động bình thường. Bạn đề xuất rằng các hiệu ứng được đề xuất khác nhau có thể ảnh hưởng đến thiết kế API. Trong cả bốn trường hợp, tôi sẽ sử dụng cùng một API, vì cả bốn trường hợp đều thay đổi trạng thái thế giới.


Giả sử hành động là lướt qua một hàng đợi email khổng lồ và gửi tin nhắn cho một nhóm người. Đó có phải là idempotent? Là hành động bình thường cho PUT hoặc POST?
Kirk Ouimet

@kirk Tôi đã mở rộng câu trả lời của mình.
Nicholas Shanks

0

Xem câu trả lời mới của tôi - nó mâu thuẫn với câu trả lời này và giải thích REST và HTTP rõ ràng và chính xác hơn.

Đây là một khuyến nghị xảy ra là RESTful nhưng chắc chắn không phải là lựa chọn duy nhất. Để bắt đầu sủa khi dịch vụ nhận được yêu cầu:

POST /v1/dogs/1/bark-schedule HTTP/1.1
...
{"token": 12345, "next": 0, "frequency": 10}

token là một số tùy ý ngăn chặn tiếng sủa dư thừa cho dù yêu cầu này được gửi bao nhiêu lần.

nextcho biết thời gian của vỏ cây tiếp theo; một giá trị của 0phương tiện 'càng sớm càng tốt.

Bất cứ khi nào bạn GET /v1/dogs/1/bark-schedule, bạn sẽ nhận được một cái gì đó như thế này, trong đó t là thời gian của vỏ cây cuối cùng và ut + 10 phút:

{"last": t, "next": u}

Tôi đặc biệt khuyên bạn nên sử dụng cùng một URL để yêu cầu một tiếng sủa mà bạn sử dụng để tìm hiểu về trạng thái sủa hiện tại của con chó. Nó không cần thiết cho REST, nhưng nó nhấn mạnh hành động sửa đổi lịch trình.

Mã trạng thái thích hợp có lẽ là 205 . Tôi đang tưởng tượng một khách hàng nhìn vào lịch trình hiện tại, POSTđến cùng một URL để thay đổi nó và được dịch vụ hướng dẫn cung cấp cho lịch trình thứ hai để chứng minh rằng nó đã được thay đổi.

Giải trình

NGHỈ NGƠI

Hãy quên HTTP đi một lát. Điều cần thiết là phải hiểu rằng tài nguyên là một hàm mất thời gian làm đầu vào và trả về một tập hợp chứa các định danhbiểu diễn . Hãy đơn giản hóa đó để: một nguồn tài nguyên là một tập hợp R của định danh và cơ quan đại diện; R có thể thay đổi - các thành viên có thể được thêm, xóa hoặc sửa đổi. (Mặc dù nó xấu, thiết kế không ổn định để loại bỏ hoặc sửa đổi định danh.) Chúng ta nói một định danh đó là một yếu tố của R Xác định R , và đó là một đại diện đó là một yếu tố của R đại diện cho R .

Hãy nói R là một con chó. Bạn tình cờ xác định R/v1/dogs/1. (Nghĩa /v1/dogs/1là thành viên của R ). Đó chỉ là một trong nhiều cách để bạn có thể xác định R . Bạn cũng có thể xác định R/v1/dogs/1/x-raysvà như /v1/rufus.

Làm thế nào để bạn đại diện cho R ? Có lẽ với một bức ảnh. Có thể với một bộ tia X. Hoặc có thể với một dấu hiệu của ngày và thời gian khi R sủa lần cuối. Nhưng hãy nhớ rằng đây là tất cả các đại diện của cùng một tài nguyên . /v1/dogs/1/x-rayslà một định danh của cùng một tài nguyên được thể hiện bằng một câu trả lời cho câu hỏi "khi nào R cuối cùng sủa?"

HTTP

Nhiều đại diện của một tài nguyên không hữu ích nếu bạn không thể tham khảo tài nguyên bạn muốn. Đó là lý do tại sao HTTP hữu ích: nó cho phép bạn kết nối các định danh với các biểu diễn . Đó là, đó là một cách để dịch vụ nhận URL và quyết định đại diện nào sẽ phục vụ cho khách hàng.

Ít nhất, đó là những gì GETlàm. PUTvề cơ bản là nghịch đảo của GET: bạn PUTđại diện r tại URL nếu bạn muốn các GETyêu cầu trong tương lai tới URL đó trả về r , với một số bản dịch có thể có như JSON sang HTML.

POSTlà một cách lỏng lẻo hơn để sửa đổi một đại diện. Hãy nghĩ rằng có logic hiển thị và logic sửa đổi đối nghịch với nhau - cả hai đều tương ứng với cùng một URL. Yêu cầu POST là yêu cầu logic sửa đổi để xử lý thông tin và sửa đổi bất kỳ biểu diễn nào (không chỉ đại diện được đặt bởi cùng một URL) khi dịch vụ thấy phù hợp. Hãy chú ý đến đoạn thứ ba sau 9.6 PUT : bạn không thay thế điều đó tại URL bằng nội dung mới; bạn đang yêu cầu điều tại URL để xử lý một số thông tin và trả lời một cách thông minh dưới dạng biểu diễn thông tin.

Trong trường hợp của chúng tôi, chúng tôi yêu cầu logic sửa đổi tại /v1/dogs/1/bark-schedule(là đối tác của logic hiển thị cho chúng tôi biết khi nào nó sủa lần cuối và khi nào nó sẽ sủa tiếp theo) để xử lý thông tin của chúng tôi và sửa đổi một số biểu diễn cho phù hợp. Để đáp ứng với tương lai GET, logic hiển thị tương ứng với cùng một URL sẽ cho chúng ta biết rằng con chó hiện đang sủa như chúng ta muốn.

Hãy nghĩ về công việc cron như một chi tiết thực hiện. Giao dịch HTTP trong việc xem và sửa đổi các đại diện. Kể từ bây giờ, dịch vụ sẽ thông báo cho khách hàng khi con chó sủa lần cuối và khi nào nó sẽ sủa tiếp theo. Từ quan điểm của dịch vụ, điều đó là trung thực bởi vì những thời điểm đó tương ứng với các công việc định kỳ trong quá khứ và theo kế hoạch.


-1

REST là một tiêu chuẩn định hướng tài nguyên, nó không phải là hành động được điều khiển như RPC.

Nếu bạn muốn máy chủ của mình sủa , bạn nên xem xét các ý tưởng khác nhau như JSON-RPC hoặc vào giao tiếp websockets.

Mỗi cố gắng để giữ cho nó RESTful sẽ thất bại trong quan điểm của tôi: bạn có thể ra POSTvới actiontham số, bạn không tạo ra bất kỳ nguồn lực mới, nhưng như bạn có thể có tác dụng phụ, bạn đang an toàn hơn.


POSTđược thiết kế để "cung cấp một khối dữ liệu ... cho quy trình xử lý dữ liệu" . Có vẻ như rất nhiều người phân biệt tài nguyên với hành động, nhưng thực sự hành động chỉ là một loại tài nguyên. Gọi một tài nguyên hành động trên một máy chủ vẫn là một giao diện thống nhất, có thể lưu trong bộ nhớ cache, mô-đun và có thể mở rộng. Nó cũng không trạng thái, nhưng điều đó có thể bị vi phạm nếu khách hàng được thiết kế để mong đợi phản hồi. Nhưng gọi một "phương thức void" trên máy chủ là những gì Roy Fielding dự định với REST .
Jacob Stevens

Như tôi mô tả trong câu trả lời của mình , bạn có thể khiến REST hoàn toàn khiến máy chủ thực hiện một hành động bằng cách yêu cầu nó nói, từ bây giờ, "hành động của bạn đã hoàn thành", trong khi RPC dựa trên ý tưởng chỉ yêu cầu máy chủ thực hiện hành động. Cả hai đều có ý nghĩa hoàn hảo, giống như lập trình bắt buộc và khai báo đều có ý nghĩa.
Jordan
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.