Câu hỏi Giải pháp thay thế RESTful cho DELETE Request Body


Trong khi Thông số HTTP 1.1 dường như cho phép nội dung thư trên XÓA BỎ yêu cầu, có vẻ như chỉ ra rằng các máy chủ nên bỏ qua nó vì không có ngữ nghĩa được xác định cho nó.

4.3 Nội dung thư

Máy chủ NÊN đọc và chuyển tiếp phần thân thư trên bất kỳ yêu cầu nào; nếu   phương thức yêu cầu không bao gồm ngữ nghĩa được xác định cho một thực thể,   sau đó thông điệp-cơ thể NÊN được bỏ qua khi xử lý yêu cầu.

Tôi đã xem xét một số cuộc thảo luận có liên quan về chủ đề này về SO và hơn thế nữa, chẳng hạn như:

Hầu hết các cuộc thảo luận dường như đồng tình rằng việc cung cấp nội dung thư trên DELETE có thể là được phép, nhưng thường không được khuyến nghị.

Hơn nữa, tôi đã nhận thấy một xu hướng trong các thư viện máy khách HTTP khác nhau, nơi ngày càng có nhiều cải tiến dường như được ghi lại cho các thư viện này để hỗ trợ các đối tượng yêu cầu trên DELETE. Hầu hết các thư viện dường như bắt buộc, mặc dù đôi khi với một chút kháng cự ban đầu.

Trường hợp sử dụng của tôi yêu cầu thêm một số siêu dữ liệu bắt buộc vào DELETE (ví dụ: "lý do" để xóa, cùng với một số siêu dữ liệu khác cần thiết để xóa). Tôi đã xem xét các tùy chọn sau, không có tùy chọn nào trong số này có vẻ hoàn toàn phù hợp và nội tuyến với thông số kỹ thuật HTTP và / hoặc các phương pháp hay nhất của REST:

  • Nội dung thư - Thông số cho biết rằng các thông báo trên DELETE không có giá trị ngữ nghĩa; không được hỗ trợ đầy đủ bởi các máy khách HTTP; không thực hành tiêu chuẩn
  • Tiêu đề HTTP tùy chỉnh - Yêu cầu tiêu đề tùy chỉnh thường là chống thực hành tiêu chuẩn; sử dụng chúng không nhất quán với phần còn lại của API của tôi, không yêu cầu nào trong số các tiêu đề tùy chỉnh này; hơn nữa, không có phản hồi HTTP tốt để chỉ ra các giá trị tiêu đề tùy chỉnh xấu (có thể là một câu hỏi riêng biệt hoàn toàn)
  • Tiêu đề HTTP chuẩn - Không có tiêu đề chuẩn nào phù hợp
  • Tham số truy vấn - Thêm các tham số truy vấn thực sự thay đổi Yêu cầu-URI bị xóa; chống thực hành tiêu chuẩn
  • Phương thức POST - (ví dụ. POST /resourceToDelete { deletemetadata }) POST không phải là tùy chọn ngữ nghĩa để xóa; POST thực sự đại diện cho đối diện hành động mong muốn (tức là POST tạo cấp dưới tài nguyên, nhưng tôi cần xóa tài nguyên)
  • Nhiều phương pháp - Tách yêu cầu DELETE thành hai hoạt động (ví dụ: PUT xóa siêu dữ liệu, sau đó DELETE) tách một hoạt động nguyên tử thành hai, có khả năng để lại trạng thái không nhất quán. Lý do xóa (và siêu dữ liệu liên quan khác) không phải là một phần của bản thân tài nguyên.

Tùy chọn đầu tiên của tôi có lẽ sẽ là sử dụng nội dung thư, thứ hai cho tiêu đề HTTP tùy chỉnh; tuy nhiên, như đã chỉ ra, có một số nhược điểm đối với các phương pháp này.

Có bất kỳ đề xuất hay phương pháp hay nhất nào phù hợp với tiêu chuẩn REST / HTTP để bao gồm siêu dữ liệu yêu cầu như vậy đối với các yêu cầu DELETE không? Có bất kỳ lựa chọn thay thế khác mà tôi đã không xem xét?


76
2018-01-14 17:45


gốc


Một số triển khai nhất định như Jersey không cho phép cơ thể delete yêu cầu. - basiljames


Các câu trả lời:


Mặc dù một số khuyến nghị không sử dụng nội dung thư cho các yêu cầu DELETE, phương pháp này có thể phù hợp trong một số trường hợp sử dụng nhất định. Đây là cách tiếp cận mà chúng tôi đã sử dụng sau khi đánh giá các tùy chọn khác được đề cập trong câu hỏi / câu trả lời và sau khi cộng tác với người tiêu dùng dịch vụ.

Mặc dù việc sử dụng nội dung thư không phải là lý tưởng, nhưng không có tùy chọn nào khác hoàn toàn phù hợp. Cơ quan yêu cầu DELETE cho phép chúng tôi thêm dễ dàng và rõ ràng ngữ nghĩa xung quanh dữ liệu / siêu dữ liệu bổ sung cần thiết để đi cùng với thao tác DELETE.

Tôi vẫn còn cởi mở với những suy nghĩ và thảo luận khác, nhưng muốn đóng vòng lặp về câu hỏi này. Tôi đánh giá cao suy nghĩ và thảo luận của mọi người về chủ đề này!


35
2018-03-18 16:36



Đây là một ý tưởng tồi. Một nơi mà điều này sẽ khiến bạn gặp rắc rối là nếu sau này bạn quyết định sử dụng dịch vụ tăng tốc HTTP như Akamai EdgeConnect. Tôi biết một thực tế rằng EdgeConnect dải các cơ quan từ các yêu cầu DELETE HTTP (vì chúng tiêu thụ băng thông có khả năng không hợp lệ). Cũng có khả năng các dịch vụ tương tự cũng giống nhau (xem tính năng tăng tốc của Kindle và các dịch vụ giống như CDN khác). Bạn có lẽ nên thiết kế lại để không sử dụng các động từ HTTP cho dịch vụ của bạn. Hầu hết các API có ý nghĩa rất ít khi sử dụng các vấn đề vận chuyển động từ HTTP / cổ điển-REST và HTTP rất khó khắc phục sự cố. - Gabe
Tôi đồng ý với @Gabe, gửi một cơ thể với các phương pháp mà không có cơ thể theo định nghĩa là một cách chắc chắn để mất dữ liệu ngẫu nhiên khi các bit của bạn đi qua các đường ống internet, và bạn sẽ có một thời gian rất khó gỡ lỗi nó. - Nicholas Shanks


Điều bạn dường như muốn là một trong hai điều, không phải trong số đó là thuần khiết DELETE:

  1. Bạn có hai hoạt động, một PUT lý do xóa theo sau là DELETE của tài nguyên. Sau khi xóa, nội dung của tài nguyên không còn có thể truy cập được với bất kỳ ai. 'Lý do' không thể chứa siêu liên kết đến tài nguyên đã xóa. Hoặc là,
  2. Bạn đang cố gắng thay đổi tài nguyên từ state=active đến state=deleted bằng cách sử dụng DELETE phương pháp. Tài nguyên với trạng thái = bị xóa sẽ bị bỏ qua bởi API chính của bạn nhưng vẫn có thể đọc được với quản trị viên hoặc ai đó có quyền truy cập cơ sở dữ liệu. Điều này được cho phép - DELETE không phải xóa dữ liệu sao lưu cho tài nguyên, chỉ để xóa tài nguyên được hiển thị tại URI đó.

Bất kỳ thao tác nào yêu cầu nội dung thư trên DELETE yêu cầu có thể được chia nhỏ thành tổng quát nhất, POST để thực hiện tất cả các tác vụ cần thiết với nội dung thư và DELETE. Tôi không thấy lý do nào để phá vỡ ngữ nghĩa của HTTP.


10
2018-01-15 09:10



Chuyện gì sẽ xảy ra nếu PUT lý do thành công và DELETE tài nguyên bị lỗi? Tình trạng không nhất quán có thể được ngăn chặn như thế nào? - Lightman
@Lightman the PUT chỉ xác định mục đích. Nó có thể tồn tại mà không có một DELETE tương ứng, điều này cho thấy rằng ai đó muốn xóa nhưng nó đã thất bại hoặc họ đã thay đổi suy nghĩ của họ. Đảo ngược thứ tự của các cuộc gọi cũng sẽ cho phép DELETE xảy ra mà không có lý do - cung cấp lý do sau đó sẽ được coi là chỉ đơn thuần là chú thích. Đó là vì cả hai lý do mà tôi khuyên bạn nên sử dụng tùy chọn 2 từ bên trên, tức là thay đổi trạng thái của bản ghi cơ bản như để làm cho tài nguyên HTTP biến mất khỏi URL hiện tại của nó. Người thu gom rác / quản trị viên có thể xóa hồ sơ - Nicholas Shanks


Với tình huống bạn có, tôi sẽ thực hiện một trong các cách tiếp cận sau:

  • Gửi PUT hoặc PATCH: Tôi đang suy luận rằng thao tác xóa là ảo, bởi bản chất của việc cần một lý do xóa. Do đó, tôi tin rằng việc cập nhật bản ghi thông qua thao tác PUT / PATCH là một cách tiếp cận hợp lệ, mặc dù nó không phải là một hoạt động DELETE mỗi lần.
  • Sử dụng tham số truy vấn: Uri tài nguyên không bị thay đổi. Tôi thực sự nghĩ rằng đây cũng là một cách tiếp cận hợp lệ. Câu hỏi bạn đã liên kết đang nói về việc không cho phép xóa nếu tham số truy vấn bị thiếu. Trong trường hợp của bạn, tôi sẽ chỉ có một lý do mặc định nếu lý do không được chỉ định trong chuỗi truy vấn. Tài nguyên vẫn sẽ là resource/:id. Bạn có thể làm cho nó có thể phát hiện với tiêu đề Liên kết trên tài nguyên vì mỗi lý do (với rel trên mỗi thẻ để xác định lý do).
  • Sử dụng điểm cuối riêng biệt cho mỗi lý do: Sử dụng url như resource/:id/canceled. Điều này thực sự thay đổi Request-URI và chắc chắn không phải là RESTful. Một lần nữa, các tiêu đề liên kết có thể làm cho điều này có thể phát hiện được.

Hãy nhớ rằng REST không phải là luật hoặc giáo điều. Hãy nghĩ về nó nhiều hơn như hướng dẫn. Vì vậy, khi nó có ý nghĩa để không làm theo hướng dẫn cho miền vấn đề của bạn, không. Chỉ cần đảm bảo người tiêu dùng API của bạn được thông báo về phương sai.


6
2018-01-15 05:37



Về việc sử dụng các tham số truy vấn, sự hiểu biết của tôi là truy vấn là một phần của URI yêu cầu cho mỗi phần 3.2và do đó sử dụng phương pháp này (hoặc tương tự, các điểm cuối riêng biệt) đi ngược lại với định nghĩa của XÓA BỎ phương pháp, chẳng hạn như "tài nguyên được xác định bởi Yêu cầu-URI" sẽ bị xóa. - shelley
Tài nguyên được xác định bởi đường dẫn uri. Vì vậy, một GET để /orders/:id sẽ trả về cùng một tài nguyên như /orders/:id?exclude=orderdetails. Chuỗi truy vấn chỉ đưa ra gợi ý cho máy chủ - trong trường hợp này để loại trừ các orderetetails trong phản hồi (nếu được hỗ trợ). Tương tự, nếu bạn đang gửi DELETE đến /orders/:id hoặc là /orders/:id?reason=canceled hoặc là /orders/:id?reason=bad_credit, bạn vẫn đang hành động trên cùng một tài nguyên cơ bản. Để giữ một 'giao diện đồng bộ', tôi sẽ có một lý do mặc định để gửi tham số truy vấn là không cần thiết. - codeprogression
@shelley Bạn đang ở trong mối quan tâm của bạn về chuỗi truy vấn. Chuỗi truy vấn là một phần của URI. Gửi yêu cầu DELETE tới /foo?123có nghĩa là bạn đang xóa một tài nguyên khác nếu bạn gửi DELETE đến /foo?456. - Nicholas Shanks
@codeprogression Xin lỗi, nhưng phần lớn những gì bạn nói là sai. Tài nguyên được xác định bởi toàn bộ URI, không chỉ là đường dẫn. Các chuỗi truy vấn khác nhau là các tài nguyên khác nhau (theo nghĩa HTTP của từ 'tài nguyên'). Ngoài ra, một lý do mặc định là không cần thiết cho một giao diện thống nhất. Thuật ngữ đó đề cập đến việc sử dụng GET, PUT, POST, PATCH và DELETE theo cách họ định nghĩa HTTP. Tính phổ biến là giữa các nhà cung cấp (đại lý người dùng, nhà cung cấp API, nhà cung cấp proxy bộ nhớ đệm, ISP, v.v) và không nằm trong API của chính mình (mặc dù điều đó cũng phải đồng nhất về thiết kế cho sự tỉnh táo của người dùng!). - Nicholas Shanks
@ Nicholas Tôi không hiểu nhu cầu của bạn để tranh luận về một cuộc thảo luận đã kết thúc cách đây ba năm. Câu trả lời và nhận xét tôi đã đưa ra là hợp lệ và chính xác từ khung nhìn REST-centric. REST không phải là HTTP (cũng như bất kỳ triển khai HTTP nào của nhà cung cấp). Trong bối cảnh REST, các tài nguyên đều giống nhau. Và như tôi đã nói trong câu trả lời của tôi, REST không phải là luật pháp hay giáo điều, mà là sự hướng dẫn. - codeprogression


Tôi khuyên bạn nên bao gồm siêu dữ liệu bắt buộc như một phần của chính phân cấp URI. Một ví dụ (Naive):

Nếu bạn cần xóa các mục dựa trên phạm vi ngày, thay vì chuyển ngày bắt đầu và ngày kết thúc trong nội dung hoặc dưới dạng tham số truy vấn, hãy cấu trúc URI theo cách bạn chuyển thông tin được yêu cầu như một phần của URI.

ví dụ.

DELETE /entries/range/01012012/31122012 - Xóa tất cả các mục nhập từ ngày 1 tháng 1 năm 2012 đến ngày 31 tháng 12 năm 2012

Hi vọng điêu nay co ich.


0
2018-01-15 07:07



Không bao gồm các trường hợp như gửi lý do xóa, tức là trường commment. - Kugel
Wow. đó là một ý tưởng khủng khiếp. Nếu bạn có quá nhiều dữ liệu meta, nó sẽ làm tăng giới hạn kích thước trên URI. - Balaji Boggaram Ramanarayan
Cách tiếp cận này không tuân theo các thực hành RESTful và không được khuyến nghị vì bạn sẽ có cấu trúc URI phức tạp. Điểm cuối bị lẫn lộn với việc xác định tài nguyên gắn bó với dữ liệu meta và trong thời gian sẽ trở thành cơn ác mộng bảo trì khi thay đổi API của bạn. Nó được ưa thích hơn nhiều để có range được chỉ định trong thông số truy vấn hoặc trọng tải là thịt của câu hỏi này: để hiểu cách tiếp cận thực tiễn tốt nhất cho vấn đề mà tôi sẽ nói không phải là điều này. - digitaldreamer
@ digitaldreamer - Tôi không hiểu ý bạn là gì bởi cấu trúc URI phức tạp? Ngoài ra, đây là một DELETE HTTP để tải trọng không phải là một lựa chọn nhưng các tham số truy vấn có. - Suresh Kumar