2011-12-23 20 views
44

Đó là một yêu cầu khá phổ biến để hỗ trợ xóa hoặc xóa trễ/theo đợt cho các dịch vụ dữ liệu. Những gì tôi đang tự hỏi là làm thế nào để thực hiện điều này một cách RESTful. Tôi bị giằng xé giữa một vài lựa chọn khác nhau (không ai trong số đó có vẻ hấp dẫn khủng khiếp với tôi). Phổ biến trên các tùy chọn khác nhau này, tôi tin rằng, là sự cần thiết cho một API trả về tất cả các tài nguyên được đánh dấu là đã xóa cho một loại tài nguyên cụ thể.RESTful undelete

Dưới đây là một số tùy chọn Tôi đã nghĩ về và một số ưu của họ/nhược điểm:

Tùy chọn để đánh dấu tài nguyên như xóa:

  • Sử dụng HTTP DELETE để đánh dấu các tài nguyên như bị xóa.
  • Sử dụng HTTP PUT/POST để cập nhật cờ đã xóa. Điều này không cảm thấy đúng vì nó ánh xạ những gì cơ bản là một xóa khỏi phương thức HTTP DELETE và các phương thức HTTP khác.

Tùy chọn khi nguồn GET-ing đánh dấu để xóa:

  • Return HTTP Status 404 cho một nguồn tài nguyên được đánh dấu là bị xóa. Làm sạch & trong suốt, nhưng làm cách nào để chúng tôi biết sự khác biệt giữa tài nguyên thực sự bị xóa so với tài nguyên chỉ được đánh dấu là đã xóa.
  • Trạng thái HTTP trả lại 410. Cung cấp cách để cho biết sự khác biệt, nhưng 410 kỹ thuật nói rằng "được dự kiến ​​sẽ được coi là vĩnh viễn. Khách hàng có khả năng chỉnh sửa liên kết NÊN xóa tham chiếu đến URI yêu cầu sau khi người dùng chấp thuận". Có thể có đủ chỗ trống trong các từ "mong đợi" và "NÊN" ở đây. Không chắc là 410 được hỗ trợ/hiểu rõ như thế nào ở các khách hàng.
  • Trả lại trạng thái HTTP 200 và bao gồm trường cờ chỉ ra tài nguyên bị xóa. Điều này có vẻ kinh khủng vì ý tưởng xóa nó ngay từ đầu là bởi vì bạn thực sự muốn nó không xuất hiện. Điều này thúc đẩy trách nhiệm lọc ra các tài nguyên đã bị xóa cho khách hàng.

Tùy chọn cho câu trả lời trong đó bao gồm khu vực này đã bị xóa:

  • Bỏ qua nguồn makred như bị xóa. Làm sạch & đơn giản. Nhưng nếu bạn thực sự muốn biết về các tài nguyên đã bị xóa.
  • Bao gồm chúng cùng với trường cho biết chúng đã bị xóa. Điều này thúc đẩy trách nhiệm lọc ra các tài nguyên đã bị xóa cho khách hàng. Nó làm cho việc phân trang trở nên phức tạp nếu bạn chỉ muốn trang thông qua các tài nguyên đang hoạt động hoặc bị xóa.

Tùy chọn khi cập nhật một nguồn tài nguyên đánh dấu để xóa:

  • Sử dụng Status HTTP 404. Các nguồn tài nguyên đã biến mất phải không? Tuy nhiên, làm thế nào bạn có thể cho biết sự khác biệt giữa một tài nguyên được đánh dấu là đã xóa và một thực sự bị xóa. Cơ thể HTTP trong phản hồi 404 có thể phân biệt ở đây nhưng sau đó các khách hàng được để lại phân tích cú pháp/giải thích cho cơ thể của bạn phân biệt. Có thể tiêu đề phản hồi có thể trợ giúp ở đây? Cái nào? Tiêu đề tùy chỉnh?
  • Sử dụng Trạng thái HTTP 409 với thông báo về cách tài nguyên trước tiên phải được hủy xóa.

Tùy chọn để lấy lại tài nguyên đánh dấu để xóa:

  • Sử dụng HTTP PUT/POST để cập nhật hoạt động của tài nguyên và đánh dấu nó như là hoạt động trở lại. Điều này chỉ hoạt động miễn là bạn không trả lại một HTTP 404 cho hoạt động GET cho tài nguyên vì nó không thực hiện kể từ PUT/POST đến một tài nguyên "Không tìm thấy" (404).
  • Sử dụng HTTP PUT/POST để tạo hoạt động của tài nguyên. Vấn đề ở đây là dữ liệu nào được ưu tiên? Dữ liệu được gửi trong hoạt động tạo? Hoặc dữ liệu đang được hủy xóa? lọc nó ra khỏi bất kỳ truy vấn nào khác có thể đã trả về nó. Sau đó, xử lý HTTP PUT/POST để tạo tài nguyên dưới dạng hồi phục nếu mã định danh tài nguyên trỏ đến tài nguyên được đánh dấu là đã xóa.
  • Đường dẫn REST riêng biệt dành riêng cho phục hồi tài nguyên được đánh dấu để xóa.

Đây không phải là danh sách đầy đủ. Tôi chỉ muốn liệt kê một số tùy chọn đã nảy ra trong đầu tôi.

Tôi biết câu trả lời cho cách thực hiện điều này, như thường lệ, "nó phụ thuộc". Điều tôi tò mò là bạn sẽ sử dụng trình độ/yêu cầu nào để đưa ra quyết định? Làm thế nào bạn đã thấy điều này được thực hiện hoặc thực hiện nó cho mình?

+2

Đây là một trong những câu hỏi được chuẩn bị tốt nhất và được suy nghĩ cẩn thận mà tôi từng thấy trên StackOverflow. Có một upvote. –

Trả lời

4

Tôi nghĩ cách RESTful nhất để giải quyết vấn đề này là sử dụng HTTP PUT để đánh dấu tài nguyên để xóa (và hủy xóa) và sau đó sử dụng DELETE HTTP để xóa vĩnh viễn tài nguyên. Để có được một danh sách các tài nguyên được đánh dấu để xóa, tôi sẽ sử dụng một tham số trong yêu cầu HTTP GET ví dụ. ?state=markedForDeletion. Nếu bạn yêu cầu tài nguyên được đánh dấu để xóa mà không có tham số, tôi nghĩ bạn nên trả lại trạng thái "404 Không tìm thấy".

8

Going by the book: RFC 2616-9.7:

The DELETE method requests that the origin server delete the resource 
    identified by the Request-URI. This method MAY be overridden by human 
    intervention (or other means) on the origin server. The client cannot 
    be guaranteed that the operation has been carried out, even if the 
    status code returned from the origin server indicates that the action 
    has been completed successfully. However, the server SHOULD NOT 
    indicate success unless, at the time the response is given, if it intends 
    to delete the resource or move it to an inaccessible location. 

Khi bạn xóa một tài nguyên máy chủ nên đánh dấu các tài nguyên để xóa đứng về phía nó. Nó không thực sự phải xóa tài nguyên, nó chỉ không thể đảm bảo rằng thao tác đã được thực hiện. Mặc dù vậy, máy chủ không nên nói rằng nó đã bị xóa khi nó không có.

A successful response SHOULD be 200 (OK) if the response includes an entity 
    describing the status, 202 (Accepted) if the action has not yet been enacted, 
    or 204 (No Content) if the action has been enacted but the response does not 
    include an entity. 

Nếu hoạt động bị trì hoãn, gửi 202 và thực thể mô tả kết quả của hành động. (Hãy suy nghĩ về "nhiệm vụ" có thể bỏ phiếu đại diện cho việc xóa bỏ tài nguyên của máy chủ; Về mặt lý thuyết nó có thể để nó ở trạng thái đó mãi mãi.) Tất cả những gì nó phải làm là ngăn máy khách lấy lại nó ở dạng ban đầu. Sử dụng mã 410 cho mã phản hồi và khi "tác vụ" kết thúc hoặc máy chủ nếu không xóa tài nguyên, hãy trả về 404.

Tuy nhiên, nếu ngữ nghĩa của DELETE không có ý nghĩa đối với tài nguyên được đề cập, có lẽ nó không phải là một xóa bạn đang tìm kiếm, nhưng một quá trình chuyển đổi trạng thái bổ sung làm thay đổi trạng thái tài nguyên nhưng giữ nó có thể truy cập? Trong trường hợp đó, hãy sử dụng PUT/PATCH để cập nhật tài nguyên và hoàn thành.

+3

Bất kỳ đề xuất nào về cách một người có thể RESTLY lấy lại một tài nguyên sau khi nó bị xóa? – Caleb

+0

Trong trường hợp đó, bạn không thực sự xóa tài nguyên, bạn chỉ đang hạn chế quyền truy cập vào tài nguyên đó. Về mặt lý thuyết, sẽ không có bất cứ điều gì ngăn cản bạn, có DELETE'd các nguồn tài nguyên, thêm một trạng thái chuyển đổi từ nhiệm vụ đó để một "tái tạo" nó. Tôi không thực sự thích cách tiếp cận đó từ quan điểm thuần khiết ngữ nghĩa, nhưng ít nhất nó còn sạch hơn là bỏ qua ngữ nghĩa HTTP. – jmkeyes

+0

Câu trả lời hay, nhưng kể từ năm 2616 đã được thay thế bởi 7231 trong đó có một mô tả khác nhau của ngữ nghĩa DELETE, và tôi đã có một số điều khác để thêm anyway, tôi đã đăng một cái mới. –

1

Phiên bản ngắn

Bạn không thể RESTfully lấy lại một nguồn tài nguyên sử dụng bất kỳ phương pháp trên URI gốc của nó - đó là vô lý, bởi vì bất kỳ hoạt động thực hiện trên một nguồn tài nguyên đã bị xóa nên trả lại hoặc 404 hoặc 410.Trong khi điều này không được quy định rõ ràng trong spec, nó ngụ ý mạnh mẽ trong định nghĩa của phương pháp DELETE 1 (nhấn mạnh thêm):

Trong thực tế, phương pháp này cũng tương tự như lệnh rm trong UNIX: nó thể hiện một thao tác xóa trên ánh xạ URI của máy chủ gốc thay vì một kỳ vọng rằng thông tin trước đó được xóa trước đó bị xóa.

Nói cách khác, khi bạn DELETEd tài nguyên, máy chủ không còn ánh xạ URI đó với dữ liệu đó nữa. Vì vậy, bạn không thể PUT hoặc POST cho nó vv (Hãy nhớ rằng một tài nguyên được định nghĩa là một ánh xạ giữa một URI và một số dữ liệu cơ bản).

Một số giải pháp

Kể từ khi nó được tuyên bố một cách rõ ràng rằng các dữ liệu cơ bản không nhất thiết phải xóa, nó không ngăn cản các máy chủ thực hiện một mới lập bản đồ URI như một phần của việc thực hiện DELETE, do đó hiệu quả thực hiện một bản sao lưu có thể được khôi phục sau này.

Bạn có thể có bộ sưu tập "/ deleted /" chứa tất cả các mục đã xóa - nhưng làm cách nào bạn thực sự thực hiện việc khôi phục? Có lẽ cách RESTful đơn giản nhất là để khách hàng truy xuất mục bằng GET và sau đó POST nó tới URL mong muốn.

Điều gì xảy ra nếu bạn cần khôi phục mục đã xóa về vị trí ban đầu? Nếu bạn đang sử dụng loại phương tiện hỗ trợ nó, bạn có thể bao gồm URI gốc trong phản hồi cho GET từ/xóa/bộ sưu tập. Khách hàng sau đó có thể sử dụng nó để POST. Phản hồi như vậy có thể trông giống như thế này trong JSON:

{ 
    "original-url":"/some/place/this/was/deleted/from", 
    "body":<base64 encoded body> 
} 

Sau đó, khách hàng có thể BẬT cơ thể đó để thực hiện khôi phục. Ngoài ra, nếu định nghĩa tài nguyên của bạn cho phép khái niệm di chuyển (bằng cách cập nhật thuộc tính "vị trí" hoặc thứ gì đó tương tự) thì bạn có thể thực hiện cập nhật một phần và tránh chuyến đi khứ hồi của toàn bộ đối tượng. Hoặc, làm những gì hầu hết mọi người làm và thực hiện một hoạt động giống như RPC để yêu cầu máy chủ di chuyển tài nguyên! UnRESTful, có nhưng nó có thể sẽ hoạt động tốt trong hầu hết các tình huống.

Làm thế nào bạn quyết định những hồ sơ này

Về vấn đề làm thế nào bạn quyết định những điều này: bạn phải xem xét những gì xóa phương tiện trong bối cảnh ứng dụng của bạn, và tại sao bạn muốn nó. Trong nhiều ứng dụng, không có gì bị xóa và "xóa" thực sự chỉ có nghĩa là "loại trừ mục này khỏi tất cả các truy vấn/danh sách khác, v.v. trừ khi tôi hủy xóa nó một cách rõ ràng". Vì vậy, nó thực sự chỉ là một phần của siêu dữ liệu, hoặc một hoạt động di chuyển. Trong trường hợp đó, tại sao phải bận tâm với HTTP DELETE? Một lý do có thể là nếu bạn muốn xóa 2 tầng - phiên bản mềm hoặc tạm thời không thể hoàn tác và phiên bản cứng/vĩnh viễn, tốt ... không.

Vắng mặt bất kỳ bối cảnh ứng dụng cụ thể, tôi muốn được xu hướng thực hiện chúng như thế này:

Tôi không muốn nhìn thấy khu vực này nữa, để thuận tiện của tôi: POST một bản cập nhật phần để đánh dấu tài nguyên là "tạm thời xóa"

tôi không muốn bất cứ ai có thể đạt đến khu vực này nữa bởi vì nó lúng túng/buộc tội/chi phí cho tôi tiền/etc: HTTP DELETE

01.

Câu hỏi tiếp theo cần xem xét là: nên xóa vĩnh viễn chỉ unmap URI vĩnh viễn, để không ai có thể liên kết với nó nữa, hoặc nó là cần thiết để thanh lọc dữ liệu cơ bản? Rõ ràng nếu bạn giữ dữ liệu, thì quản trị viên có thể khôi phục ngay cả tài nguyên đã bị xóa "vĩnh viễn" (không thông qua bất kỳ giao diện RESTful nào). Nhược điểm của điều này là nếu chủ sở hữu dữ liệu thực sự muốn nó bị xóa, thì một quản trị viên phải làm điều đó bên ngoài giao diện REST.

0

Các mục đã xóa cũng là tài nguyên, phải không? Hãy để nó được như vậy. Sau đó, chúng ta có thể truy cập vào tài nguyên này theo cách này (nói, chúng tôi đã xóa một người dùng):

PATCH deleted_users/{id} // I personally use this one 

hoặc theo cách này:

PATCH deleted/users/{id} 

hoặc một số người có thể nghĩ rằng đây là cách ngon hơn:

PATCH deleted/{id}?type=users