Mẫu tốt nhất để thêm một mục hiện có vào bộ sưu tập trong API REST là gì?


23

Tôi đang thiết kế API REST thực dụng và tôi hơi băn khoăn về cách tốt nhất để thêm các thực thể hiện có vào bộ sưu tập. Mô hình miền của tôi bao gồm Dự án có bộ sưu tập Trang web. Đây là một mối quan hệ nhiều-nhiều nghiêm ngặt và tôi không cần phải tạo một thực thể mô hình hóa rõ ràng mối quan hệ (ví dụ ProjectSite).

API của tôi sẽ cho phép người tiêu dùng thêm Trang web hiện tại vào Dự án. Nơi tôi đang gác máy là dữ liệu duy nhất tôi thực sự cần là ProjectId và SiteId. Ý tưởng ban đầu của tôi là:

1. POST myapi/projects/{projectId}/sites/{siteId}

Nhưng tôi cũng nghĩ về

2. POST myapi/projects/{projectId}/sites

với một thực thể Trang web được gửi dưới dạng nội dung JSON.

Tùy chọn 1 đơn giản và hoạt động nhưng không cảm thấy hoàn toàn đúng và tôi có các mối quan hệ khác không thể theo mô hình này để nó thêm sự không nhất quán vào API của tôi.

Tùy chọn 2 cảm thấy tốt hơn nhưng dẫn đến hai mối quan tâm:

  • Tôi có nên tạo Trang web hay ném ngoại lệ nếu Trang mới được đăng (SiteId = 0) không?
  • Vì tôi chỉ cần ProjectId và SiteId để tạo mối quan hệ, nên Trang có thể được đăng với dữ liệu sai hoặc thiếu cho các thuộc tính khác.

Tùy chọn thứ 3 là cung cấp một điểm cuối đơn giản chỉ để tạo và xóa mối quan hệ. Điểm cuối này sẽ mong đợi một tải trọng JSON chỉ chứa ProjectId và SiteId.

Bạn nghĩ sao?



@RoryHunter Có một số cuộc thảo luận thú vị trong liên kết đó nhưng không có gì loại bỏ sự không chắc chắn của tôi. Tôi đặc biệt thích câu trả lời được chấp nhận nói rằng "Bạn đã hiểu đúng". và vị trí thứ 2 (mặc dù bằng một lề lớn) trả lời "Nói một cách đơn giản, bạn đang làm điều này hoàn toàn lạc hậu."
Jamie Ide

Tùy chọn đầu tiên của bạn là tốt mặc dù tôi sẽ sử dụng PUT thay vì POST vì máy khách kiểm soát danh tính được thêm vào bộ sưu tập. Mối quan tâm đầu tiên của bạn với tùy chọn 2 hoàn toàn phụ thuộc vào bạn, nếu bạn không muốn các trang web mới, đừng ném ngoại lệ mà trả lại một trong các mã 4xx. Mối quan tâm thứ hai của bạn là không ở đây và cũng không có. Bạn không nên đăng toàn bộ Trang web trừ khi bạn cho phép bổ sung. Thêm một trang web hiện tại chỉ nên có id khi bạn sửa đổi trang web mà chỉ có bộ sưu tập "ProjectSite" (ngay cả khi bạn không tạo tài nguyên riêng cho nó).
Marjan Venema

Câu trả lời:


14

POST là động từ "chắp thêm" và cũng là động từ "đang xử lý". PUT là động từ "tạo / cập nhật" (đối với các định danh đã biết) và gần như có vẻ là lựa chọn đúng ở đây, vì URI mục tiêu đầy đủ đã được biết. projectIdsiteIdđã tồn tại, vì vậy bạn không cần "POST vào bộ sưu tập" để tạo ID mới.

Vấn đề với PUT là nó đòi hỏi cơ thể phải là đại diện cho tài nguyên mà bạn PUTting. Nhưng mục đích ở đây là nối thêm tài nguyên thu thập "dự án / trang web", thay vì cập nhật tài nguyên Trang web.

Điều gì xảy ra nếu ai đó PUT đại diện JSON đầy đủ của Trang web hiện tại? Bạn có nên cập nhật bộ sưu tập cập nhật đối tượng? Bạn có thể ủng hộ điều đó, nhưng có vẻ như đó không phải là ý định. Như bạn đã nói,

dữ liệu duy nhất tôi thực sự cần là ProjectId và SiteId

Thay vào đó, tôi sẽ thử POST siteIdbộ sưu tập và dựa vào bản chất "chắp thêm" và "xử lý" của POST:

POST myapi / dự án / {projectId} / trang web

{'ID': '...' }

Vì bạn đang sửa đổi các trang web tài nguyên tuyển tập chứ không phải tài nguyên Trang , đó là URI bạn muốn. POST có thể biết "chắp thêm / xử lý" và thêm phần tử có id đó vào tuyển tập trang của dự án.

Điều đó vẫn để ngỏ khả năng tạo ra các trang web hoàn toàn mới cho dự án bằng cách làm sáng tỏ JSON và bỏ qua id. "Không có id" == "tạo từ đầu". Nhưng nếu URI của bộ sưu tập có id và không có gì khác, thì rõ ràng điều gì cần phải xảy ra.

Câu hỏi thú vị. :)


Tôi tin rằng POST là để tạo và PUT là để cập nhật nhưng kết luận của bạn là nơi tôi đã kết thúc ngày hôm qua. Điều thú vị là nhờ định tuyến thuộc tính trong API Web, tôi có mã trong trình điều khiển ProjectSites để mã được tổ chức tốt.
Jamie Ide

Tôi nghĩ lý do xác định bạn cần sử dụng POSTthay vì PUThoặc PATCHở đây là bạn không có toàn bộ Sitethực thể để đưa vào sitestài nguyên. Bạn chỉ có id, yêu cầu xử lý để thêm nó vào bộ sưu tập.
đè bẹp

4

Chúng tôi sử dụng Patchphương pháp cho những thứ như thế này. Những gì bạn muốn làm là sửa đổi một Dự án hiện có để thêm một Trang web vào đó.

Vì vậy, một cái gì đó như thế này sẽ làm việc

PATCH myapi/projects/{id} 

với thực thể (các) Trang web là JSON / JSONArray trong phần thân yêu cầu.

Bằng cách đó, bạn có thể sử dụng cùng một URL để sửa đổi các phần khác nhau của Dự án nếu bạn cần - mã của bạn trong quá trình triển khai phải đủ thông minh để xử lý việc sửa đổi một phần tài nguyên này.


Cách tiếp cận thú vị. Tôi có một mô hình miền cũ "giàu có" (nghĩa là phụ thuộc cao) và đặc biệt có nhiều bộ sưu tập treo trên đó. Phát hiện loại thực thể trong yêu cầu sẽ là một thách thức và không phù hợp với mục tiêu thực dụng của tôi.
Jamie Ide

Tại sao một thử thách? Nếu bạn có những hạn chế đó, bạn luôn có thể sử dụng JSON để thể hiện rõ ràng những gì nó đang gửi ... như thế {"sites": [], "other-stuff": {}}, sau đó bạn có thể phân nhánh mã của mình để xử lý tất cả các "subjsons" đó một cách dễ dàng. Nó thực sự phụ thuộc vào vấn đề cụ thể của bạn, nhưng tôi vẫn khuyên bạn nên sử dụng PATCH vì nó được thiết kế dành riêng cho những thứ này.
juan

Nhược điểm tôi thấy là 1) API không truyền đạt rõ ràng bộ sưu tập nào cho phép thay đổi; 2) không thể tận dụng ràng buộc tham số API Web; 3) chuyển đổi lớn hoặc nếu tuyên bố.
Jamie Ide

Tôi chưa bao giờ thấy phương pháp vá được sử dụng ở bất cứ nơi nào khác
NimChimpsky 13/03/2016

PATCHCũng không mong đợi thực thể đầy đủ sẽ được thông qua như giá trị của nó ở đây, chứ không phải là một id trỏ đến một thực thể nào đó?
đè bẹp
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.