2011-04-16 35 views
21

Để được chính xác hơn:tôi nên sử dụng phương pháp PUT để cập nhật, nếu tôi cũng cập nhật một thuộc tính timestamp

Theo phong cách nghỉ ngơi, nó thường được assummed rằng POST, GET, PUT, và DELETE phương pháp http nên được sử dụng cho Các hoạt động CREATE, READ, UPDATE và DELETE (CRUD).

Trong thực tế, nếu chúng ta dính vào định nghĩa phương pháp http điều có thể không được như vậy rõ ràng

Trong this article nó giải thích rằng:

Tóm lại: Sử dụng PUT nếu và chỉ nếu bạn biết cả URL nơi tài nguyên sẽ hoạt động và toàn bộ nội dung của tài nguyên. Nếu không, hãy sử dụng POST.

Chủ yếu là vì

PUT là một động từ nhiều hạn chế hơn. Nó lấy một tài nguyên hoàn chỉnh và lưu trữ nó tại URL đã cho. Nếu có tài nguyên ở đó trước đó, nó được thay thế; nếu không, một cái mới được tạo ra. Các thuộc tính này hỗ trợ tính ngẫu nhiên, mà một hoạt động tạo hoặc cập nhật ngây thơ có thể không. Tôi nghi ngờ đây có thể là lý do tại sao PUT được định nghĩa theo cách của nó; nó là một hoạt động không cần thiết cho phép khách hàng gửi thông tin đến máy chủ.

Trong trường hợp của mình, tôi thường phát hành bản cập nhật chuyển tất cả dữ liệu tài nguyên, vì vậy tôi có thể sử dụng PUT để cập nhật, nhưng mỗi lần tôi cập nhật tôi lưu cột Người dùng cuối cùng và LastUpdate, với id người dùng đã sửa đổi và thời gian od hoạt động.

Vì vậy, tôi muốn biết ý kiến ​​của bạn, bởi vì nghiêm túc nói rằng hai cột không phải là một phần của tài nguyên, nhưng chúng ngăn chặn hoạt động từ idempotent.

saludos

sas

+0

Làm thế nào để bạn đại diện cho 'LastUser' và' LastUpdate' - chúng có phải là một phần của biểu diễn tài nguyên của bạn (tức là các nút trong XML) không? – MicE

+0

không, chúng thậm chí không tồn tại khi issiung cập nhật, nhưng tôi trả lại khi truy vấn với một get .... vì vậy tôi tạo một PUT, và sau đó là GET và tôi nhận được thời gian lastUpdate, tôi lại phát hành lại PUT, và một GET mang lại một lastUpdate khác nhau ... – opensas

+0

Ok, cảm ơn để xác nhận - xem câu trả lời của tôi dưới đây cho một thay thế về vấn đề này. – MicE

Trả lời

20

Bỏ qua nhận xét về lập bản đồ kiểu REST CRUD với các phương thức HTTP, đây là một câu hỏi hay.

Câu trả lời cho câu hỏi của bạn là, có bạn được tự do sử dụng PUT trong trường hợp này mặc dù có một số yếu tố của tài nguyên được máy chủ cập nhật theo cách không phải là không phụ thuộc. Thật không may, lý do đằng sau câu trả lời là khá mơ hồ. Điều quan trọng là hiểu được ý định của yêu cầu của khách hàng là gì. Khách hàng dự định thay thế hoàn toàn nội dung của tài nguyên bằng các giá trị được chuyển.Máy khách không chịu trách nhiệm đối với máy chủ đang thực hiện các hoạt động khác và do đó ngữ nghĩa của phương thức HTTP không bị vi phạm.

Đây là lý do được sử dụng để cho phép máy chủ cập nhật bộ đếm trang khi bạn thực hiện thao tác GET. Khách hàng không yêu cầu cập nhật vì thế GET an toàn mặc dù máy chủ chọn thực hiện cập nhật.

Toàn, tài nguyên hoàn so với cuộc tranh luận tài nguyên phần cuối cùng đã được nêu ra trong một bản cập nhật cho HTTP spec

Một máy chủ gốc NÊN từ chối bất kỳ PUT yêu cầu có chứa một header field Content-Range, kể từ nó có thể bị hiểu sai là một phần nội dung (hoặc có thể là một phần nội dung bị nhầm lẫn là PUT dưới dạng đại diện đầy đủ). Nội dung từng phần cập nhật có thể xảy ra bằng cách tấn công một tài nguyên được xác định riêng rẽ với trạng thái đó chồng lấp một phần của tài nguyên lớn hơn, hoặc bằng cách sử dụng một phương pháp khác nhau đã được đặc biệt được xác định cho từng phần cập nhật (ví dụ, PATCH phương thức được xác định trong [RFC5789]).

Vì vậy, những gì chúng tôi phải làm bây giờ là rõ ràng. Điều không rõ ràng là tại sao tồn tại ràng buộc này chỉ được phép gửi trả lời đầy đủ. Câu hỏi đó đã được hỏi và IMHO vẫn chưa được trả lời trong chủ đề này về thảo luận.

+0

Vâng, tôi đồng ý. Tuy nhiên, bằng cách sử dụng tiêu đề PATCH hoặc Content-Range không cảm thấy đúng, vì khách hàng đang cố gắng sửa đổi toàn bộ tài nguyên (ít nhất là các phần mà khách hàng được phép sửa đổi). Xem câu trả lời của tôi cho một sự khác biệt về vấn đề này.Tôi biết rằng nó cũng không chống đạn, nhưng nó cố gắng giảm thiểu vấn đề ít nhất một chút. – MicE

+2

http://williamdurand.fr/2014/02/14/please-do-not-patch-like-an-idiot/ - Tôi không gọi ai là thằng ngốc nhưng đó là một bài đọc hữu ích. – backdesk

3

Các bất lợi của việc sử dụng PUT để tạo nguồn lực là khách hàng phải cung cấp ID duy nhất đại diện cho đối tượng mà nó được tạo ra. Trong khi nó thường có thể cho khách hàng để tạo ID duy nhất này, hầu hết các nhà thiết kế ứng dụng thích rằng máy chủ của họ (thường là thông qua cơ sở dữ liệu của họ) tạo ID này. Trong hầu hết các trường hợp, chúng tôi muốn máy chủ của chúng tôi kiểm soát việc tạo ID tài nguyên. Vậy ta phải làm sao? Chúng tôi có thể chuyển sang sử dụng POST thay vì PUT.

Vì vậy:

Đặt = CẬP NHẬT

bài viết = INSERT

Hy vọng rằng, điều này giúp cho trường hợp cụ thể của bạn.

+0

tốt, tôi đang nói về một bản cập nhật mà tôi biết id ... Tôi không nói về một chèn ... – opensas

6

LastUserLastUpdate không thể sửa đổi được bởi khách hàng, tôi sẽ xóa chúng khỏi đại diện cho tài nguyên của bạn hoàn toàn. Hãy để tôi giải thích lý do của tôi với một ví dụ.

Hãy nói rằng chúng tôi ví dụ điển hình API sẽ trở lại với đại diện sau đây cho khách hàng khi được yêu cầu cung cấp một nguồn duy nhất:

GET /example/123 

<?xml version="1.0" encoding="UTF-8" ?> 
<example> 
    <id>123</id> 
    <lorem>ipsum</lorem> 
    <dolor>sit amet</dolor> 
    <lastUser uri="/user/321">321</lastUser> 
    <lastUpdate>2011-04-16 20:00:00 GMT</lastUpdate> 
</example> 

Nếu một khách hàng muốn sửa đổi các nguồn lực, nó sẽ lẽ lấy toàn bộ đại diện và gửi lại cho API.

PUT /example/123 

<?xml version="1.0" encoding="UTF-8" ?> 
<example> 
    <id>123</id> 
    <lorem>foobar</lorem> 
    <dolor>foobaz</dolor> 
    <lastUser>322</lastUser> 
    <lastUpdate>2011-04-16 20:46:15 GMT+2</lastUpdate> 
</example> 

Kể từ khi API tạo ra giá trị cho lastUserlastUpdate tự động và không thể chấp nhận dữ liệu được cung cấp bởi khách hàng, phản ứng thích hợp nhất sẽ là 400 Bad Request hoặc 403 Forbidden (kể từ khi khách hàng không có thể thay đổi các giá trị).

Nếu chúng tôi muốn tuân thủ REST và gửi một đại diện đầy đủ của tài nguyên khi thực hiện yêu cầu PUT, chúng tôi cần xóa lastUserlastUpdate khỏi phần trình bày tài nguyên. Điều này sẽ cho phép khách hàng để gửi các thực thể đầy đủ qua PUT:

PUT /example/123 

<?xml version="1.0" encoding="UTF-8" ?> 
<example> 
    <id>123</id> 
    <lorem>foobar</lorem> 
    <dolor>foobaz</dolor> 
</example> 

Các máy chủ sẽ chấp nhận một đại diện đầy đủ bây giờ mà nó không chứa lastUpdatelastUser.

Câu hỏi còn lại là cách cung cấp cho khách hàng quyền truy cập vào lastUpdatelastUser. Nếu họ không cần nó (và các lĩnh vực này được yêu cầu trong nội bộ của API), chúng tôi là tốt và giải pháp của chúng tôi là hoàn toàn yên tĩnh.Tuy nhiên, nếu khách hàng cần truy cập vào dữ liệu này, các phương pháp sạch sẽ sử dụng tiêu đề HTTP:

GET /example/123 

... 
Last-Modified: Sat, 16 Apr 2011 18:46:15 GMT 
X-Last-User: /user/322 
... 

<?xml version="1.0" encoding="UTF-8" ?> 
<example> 
    <id>123</id> 
    <lorem>foobar</lorem> 
    <dolor>foobaz</dolor> 
</example> 

Sử dụng một tiêu đề HTTP tùy chỉnh không phải là lý tưởng vì đại lý người dùng cần phải được dạy về cách đọc nó. Nếu chúng tôi muốn cung cấp cho khách hàng quyền truy cập vào cùng một dữ liệu theo cách dễ dàng hơn, điều duy nhất chúng tôi có thể làm là đưa dữ liệu vào biểu diễn và chúng tôi đang đối mặt với cùng một vấn đề như trong câu hỏi ban đầu của bạn. Tôi ít nhất sẽ cố gắng giảm thiểu nó bằng cách nào đó. Nếu kiểu nội dung được sử dụng bởi các API là XML, chúng ta có thể đưa dữ liệu vào thuộc tính nút thay vì phơi bày chúng trực tiếp như các giá trị nút, ví dụ:

GET /example/123 

... 
Last-Modified: Sat, 16 Apr 2011 18:46:15 GMT 
... 

<?xml version="1.0" encoding="UTF-8" ?> 
<example last-update="2011-04-16 18:46:15 GMT" last-user="/user/322"> 
    <id>123</id> 
    <lorem>foobar</lorem> 
    <dolor>foobaz</dolor> 
</example> 

Bằng cách này chúng ta sẽ ít nhất là tránh những vấn đề mà một khách hàng sẽ cố gắng gửi tất cả các nút XML trong một yêu cầu PUT tiếp theo. Điều này sẽ không làm việc với JSON, và giải pháp vẫn còn một chút trên cạnh của idempotency (vì API sẽ vẫn phải bỏ qua các thuộc tính XML khi xử lý yêu cầu).

Thậm chí tốt hơn, như Jonah chỉ ra trong các nhận xét, nếu khách hàng cần truy cập vào lastUserlastUpdate, chúng có thể được hiển thị dưới dạng tài nguyên mới, được liên kết từ tài nguyên gốc, ví dụ: như sau:

GET /example/123 

<?xml version="1.0" encoding="UTF-8" ?> 
<example> 
    <id>123</id> 
    <lorem>foobar</lorem> 
    <dolor>foobaz</dolor> 
    <lastUpdateUri>/example/123/last-update</lastUpdateUri> 
</example> 

... và sau đó:

GET /example/123/last-update 

<?xml version="1.0" encoding="UTF-8" ?> 
<lastUpdate> 
    <resourceUri>/example/123</resourceUri> 
    <updatedBy uri="/user/321">321</updatedBy> 
    <updatedAt>2011-04-16 20:00:00 GMT</updatedAt> 
</lastUpdate> 

(. Trên đây có thể cũng độc đáo mở rộng để cung cấp một bản ghi kiểm toán đầy đủ với những thay đổi cá nhân, cung cấp một changelog tài nguyên có sẵn)

Xin lưu ý:
tôi đồng ý với Darrel Miller 's take on the question, nhưng tôi muốn pro vide một cách tiếp cận khác nhau trên đầu trang của nó. Lưu ý rằng cách tiếp cận này không được sao lưu bởi bất kỳ tiêu chuẩn/RFC/etc nào, đó chỉ là vấn đề khác.

+0

Cảm ơn phương án thay thế. Sử dụng tiêu đề 'được sửa đổi lần cuối' có vẻ như một ý tưởng hay - đặc biệt là khi lưu vào bộ nhớ đệm hoặc từ chối các cập nhật lỗi thời (tức là tài nguyên đã được người khác chỉnh sửa trong khi bạn bận thay đổi chúng). Suy nghĩ? – backdesk

+1

tại sao không phơi bày nó tại điểm cuối mới? sau khi tất cả, như bạn đã tranh luận thuyết phục, nó là một khái niệm riêng biệt từ nguồn gốc: 'example/123/lastUpdate' – Jonah

+0

@Jonah - đó là một điểm tuyệt vời, cảm ơn bạn. Tôi đã cập nhật câu trả lời để kết hợp nó. (Lưu ý rằng ví dụ: URI trong bản chỉnh sửa có thể phù hợp hơn với tư cách thuộc tính nút XML. Định dạng hiện tại sẽ cho phép dịch trực tiếp hơn sang JSON khi cần.) – MicE

0

Phương thức HTTP POST và PUT không phải là HTTP tương đương với việc tạo và cập nhật CRUD. Cả hai đều phục vụ một mục đích khác nhau. Nó khá khả thi, hợp lệ và thậm chí được ưa thích trong một số trường hợp, để sử dụng PUT để tạo tài nguyên hoặc sử dụng POST để cập nhật tài nguyên.

Sử dụng PUT khi bạn có thể cập nhật tài nguyên hoàn toàn thông qua một tài nguyên cụ thể. Ví dụ: nếu bạn biết rằng một bài viết nằm ở số http://example.org/article/1234, bạn có thể PUT trình bày tài nguyên mới của bài viết này trực tiếp thông qua PUT trên URL này.

Nếu bạn không biết vị trí tài nguyên thực tế, khi bạn thêm một bài viết mới, nhưng không có ý tưởng lưu trữ nó, bạn có thể đăng nó vào URL và để máy chủ quyết định thực tế URL.