Điểm cuối REST để hiển thị bản xem trước trước khi gửi


17

Tôi đang thiết kế một ứng dụng web mới được cung cấp bởi phụ trợ REST và giao diện HTML + JS.

Có một phương thức POST trên đó để thay đổi một thực thể (hãy gọi Cấu hình), có một số tác dụng phụ ở trạng thái nhiều yếu tố của ứng dụng. Giả sử POST được thực hiện theo cách này:

POST /api/config BODY {config: ....}

Vì điều này, tôi muốn hiển thị bản xem trước trước khi những thay đổi đó được thực hiện, để người dùng cuối có thể nhận thấy những gì sẽ thay đổi.

Điều đầu tiên tôi nghĩ đến là tạo một điểm cuối GET cho phần xem trước, gửi phần thân của trạng thái mới của thực thể. Cách này:

GET /api/preview/items BODY {config: ....}

Có thể hiển thị trạng thái mới cho các mục với cấu hình mới.

GET /api/preview/sales BODY {config: ....}

Có thể hiển thị trạng thái mới cho doanh số với cấu hình mới.

Có vẻ là một ý tưởng tốt để sử dụng động từ GET vì tôi không thay đổi trạng thái của ứng dụng. Tuy nhiên, việc sử dụng nội dung yêu cầu với các yêu cầu GET dường như không được khuyến khích .

Có thực hành tốt về điều này? Lựa chọn khác có thể là lưu trữ cấu hình dưới dạng bản nháp với một phương thức và hiển thị kết quả với các phương thức khác, nhưng nó sẽ yêu cầu một bước bổ sung và phải quản lý các bản nháp trong máy chủ:

POST /api/preview/config BODY {config: ....}

GET /api/preview/items?idPreviewConfig=1

Chính xác thì cấu hình này là gì và nó ảnh hưởng đến itemshoặc salesnhư thế nào? Nó có ảnh hưởng đến đại diện của thực thể trả lại?
Andy

Giả sử cả mặt hàng và doanh số đều bị ảnh hưởng bởi những thay đổi bạn thực hiện trong cấu hình.
Xtreme Biker phục hồi Monica

Nhưng những thay đổi có ý nghĩa gì? Nó có thay đổi tập hợp các thực thể trả lại không? Nó có thay đổi cấu trúc trả lại không?
Andy

Trên thực tế, nó thay đổi các giá trị cho itemssales(không phải cấu trúc), tùy thuộc vào cấu hình bạn POST.
Xtreme Biker phục hồi Monica

Và cấu hình chính xác lớn đến mức nào? Có thể tăng lên đến vài trăm kilobyte hoặc thậm chí nhiều hơn?
Andy

Câu trả lời:


27

Điều này quá đặc trưng cho miền để có hỗ trợ riêng trong HTTP.

Thay vào đó, bạn có thể thực hiện một trong những điều sau đây:

  1. Có một POST /api/config/preview. Ở phía máy chủ, ứng dụng sẽ biết rằng nó không nên sửa đổi cấu hình thực tế, nhưng kết hợp cấu hình thực tế với cấu hình bạn đã đăng và trả về kết quả cho biết những gì đã thay đổi.

    Sau đó, nếu người dùng hài lòng với kết quả, cô ấy sẽ thực hiện POST /api/configchứa tải trọng tương tự như trong yêu cầu trước đó. Điều này sẽ ghi đè lên cấu hình một cách hiệu quả.

    Lợi ích của phương pháp này là bạn không thực hiện bất kỳ thay đổi đột phá nào đối với API hiện tại. Các khách hàng không cần tính năng xem trước vẫn có thể cập nhật các mục như trước đây.

    Hạn chế là khi cơ thể lớn, điều đó có nghĩa là cần phải gửi nó hai lần đến máy chủ. Nếu đây là trường hợp của bạn, bạn có thể sử dụng phương pháp tiếp theo.

  2. Có một bản POST /api/config/prepareghi nhớ những gì đã được gửi trong một bản ghi tạm thời và trả về hai thứ: ID của bản ghi tạm thời (ví dụ 12345) và bản xem trước của các thay đổi.

    Nếu người dùng hài lòng với kết quả, cô ấy sẽ thực hiện POST /api/config/commit/12345để lưu trữ chắc chắn các thay đổi. Nếu không, hồ sơ tạm thời có thể được lưu giữ trong một thời gian, và sau đó bị loại bỏ bởi một công việc định kỳ.

    Lợi ích là, ở đây một lần nữa, bạn có thể giữ nguyên bản gốc POST /api/configvà các khách hàng không cần xem trước sẽ không bị hỏng.

    Hạn chế là (1) xử lý loại bỏ các hồ sơ tạm thời có thể khó khăn (điều khiến bạn nghĩ rằng một giờ là đủ? Điều gì sẽ xảy ra nếu mười phút sau, bạn hết bộ nhớ? Làm thế nào khách hàng xử lý HTTP 404 khi thực hiện cam kết một bản ghi đã hết hạn?) và (2) việc nộp bản ghi hai bước có thể phức tạp hơn mức cần thiết.

  3. Di chuyển logic xem trước về phía khách hàng.


Điều gì về việc gửi một tiêu đề có nội dung "không duy trì điều này, chỉ cho tôi biết nếu-nếu" thì sao? Tôi sẽ chỉnh sửa câu trả lời nếu điều đó tốt với bạn @ArseniMourzenko
marstato

1
@marstato: cá nhân, tôi không đặc biệt thích tiêu đề HTTP cho việc sử dụng đó. Mặc dù nó có thể có ý nghĩa với người khác, vì vậy tôi vẫn ổn nếu bạn chỉnh sửa câu trả lời của tôi. Lưu ý rằng bạn cũng có thể đăng câu trả lời của riêng mình, điều này sẽ cho phép người khác nâng cao câu trả lời (và sẽ giúp bạn có được điểm danh tiếng).
Arseni Mourzenko

Tôi đoán tùy chọn 1 phù hợp hơn cho trường hợp của tôi. Vì vậy, bạn POST cấu hình xem trước và bạn có các thay đổi trong kết quả, thay vì phải xác định điểm cuối xem trước cho từng thực thể được xác định. Có vẻ hợp lý. Điều duy nhất là bạn đang sử dụng POST để không thay đổi máy chủ, nói về mặt kỹ thuật. Tùy chọn 3 là không khả thi trong trường hợp của tôi.
Xtreme Biker phục hồi Monica

1
@PedroWerneck Bạn có thể mở rộng về điều đó? Dường như với tôi rằng tùy chọn 2 định nghĩa một thực thể khác (một cấu hình dự thảo) và cung cấp các cách không trạng thái để tương tác với chúng.
Andrew nói Phục hồi lại

1
@PedroWerneck Nó có trạng thái giống như cách lưu trữ một cấu hình trên máy chủ là trạng thái. Vì vậy, ứng dụng đã được nêu rõ theo quan điểm của bạn và tất cả các tùy chọn để thêm tính năng này.
jpmc26

10

Điểm của việc sử dụng các động từ HTTP cụ thể cho các cuộc gọi api khác nhau trong REST là để tận dụng các cơ chế và kỳ vọng HTTP hiện có.

Sử dụng một GET trong trường hợp này dường như đi ngược lại cả hai.

A. Khách hàng cần bao gồm một cơ thể với một GET? bất ngờ

B. Máy chủ trả về một phản ứng khác nhau để nhận tùy thuộc vào cơ thể? phá vỡ thông số kỹ thuật và bộ nhớ đệm

Nếu bạn đang vật lộn với các câu hỏi RESTful, quy tắc của tôi là tự hỏi chính mình.

"Làm thế nào là tốt hơn so với chỉ sử dụng POST cho tất cả mọi thứ?"

Trừ khi có một lợi ích ngay lập tức và rõ ràng, hãy sử dụng chiến lược Chỉ sử dụng POST St ngu (JUPS)


Hahaha bắt tốt
Xtreme Biker phục hồi Monica

@Ewan ... bất kể đó có phải là cách tiếp cận thực dụng hay không ... nếu bạn đang sử dụng POST cho mọi thứ thì cần lưu ý rằng nó không thực sự RESTful.
Allenph

1
tốt, trừ khi POST là lựa chọn thích hợp cho tất cả các phương thức của bạn. Và nó không giống như có một quy tắc khách quan mà bạn có thể áp dụng, chúng tôi sẽ chỉ tranh luận về những diễn giải chủ quan của chúng tôi về những gì ít hơn một hướng dẫn.
Ewan

6

Bạn có thể gửi một tiêu đề cho biết đến máy chủ "không duy trì điều này, chỉ cho tôi thấy kết quả sẽ như thế nào nếu bạn đã làm". Ví dụ

POST /api/config HTTP/1.1
Host: api.mysite.com
Content-Type: application/json
Persistence-Options: simulate

{
   "config": {
      "key": "value"
   }
}

Máy chủ có thể trả lời:

HTTP/1.1 200 OK
Persistence-Options: simulated
Content-Type: application/json

-- preview --

Lưu ý rằng, nếu bạn sử dụng các giao dịch O / RM và / hoặc mỗi yêu cầu dựa trên Đơn vị công việc với DB, bạn có thể dễ dàng thực hiện chức năng này cho tất cả các điểm cuối của mình mà không yêu cầu công việc trên bất kỳ điểm cuối cụ thể nào: Nếu một yêu cầu đi kèm với tùy chọn đó , khôi phục giao dịch / đơn vị công việc thay vì cam kết.



@PeterRader điểm tốt, đã xóaX-
marstato

Chào mừng bạn Bạn có thể nói một thực thể theo mô phỏng nên được biểu diễn là "theo mô phỏng" không?
Peter Rader

Không; đó là điểm của một mô phỏng, phải không? Giá trị tiêu đề cũng có thể là nonenhưng điều đó - theo sở thích của tôi - mâu thuẫn quá nhiều với bản chất của POSTphương pháp.
marstato

2

Tôi sẽ đề nghị đối xử với điều này giống như cách bạn đối xử với các tìm kiếm. Tôi sẽ thiết lập một điểm cuối POST /api/config/previewđể TẠO một bản xem trước mới. Sau đó, tôi sẽ thiết lập điểm cuối PUT hoặc PATCH api/configtùy thuộc vào việc bạn có ý định chỉnh sửa cấu hình hiện tại hay chỉ đơn giản là thay thế toàn bộ cấu hình (có thể trong trường hợp trước bạn sẽ gửi bản xem trước bạn vừa tạo).


0

Cùng với các câu trả lời hay khác, một tùy chọn khác có thể là đăng cấu hình như đã đề cập và cũng có sẵn quy trình khôi phục. Tôi nghĩ, giống như phương pháp Agile, tốt hơn là bớt sợ thay đổi bằng cách có các quy trình thử nghiệm chi tiết hơn, có thể lặp lại và được thử nghiệm và điều này sẽ cung cấp cho bạn một bản sao lưu khi bạn cần, giảm rủi ro xuống ít hoặc không, tùy thuộc vào ứng dụng .

Sau đó, một lần nữa, nếu bạn có thể có lỗi cấu hình ảnh hưởng đến toàn bộ hệ thống, bạn muốn xử lý nó tích cực hơn và nếu đó là lý do, tại sao bạn không nỗ lực xem trước các thay đổi tại thời điểm đó, từ góc độ máy chủ hoặc máy khách. Mặc dù, tôi có thể thấy tính năng xem trước này có thể tốn kém hơn để phát triển, nhưng trong các trường hợp sử dụng, có các bước khác nhau để theo dõi và kiểm tra.


0

RFC6648 không chấp nhận các X-cấu trúc mới vì vậy tôi phải bỏ phiếu chống lại ý tưởng để gửi trường tiêu đề mới. REST là một kiểu kiến ​​trúc, những gì chúng ta nói đến là RESTful - nhưng hãy bỏ qua điều đó cho thời điểm này.

Bởi vì REST là Đại diện (và một mô phỏng không có đại diện trong thực tế) và Stateful (và mô phỏng không phải là trạng thái cho đến khi cam kết), chúng ta phải có một phạm vi mới, như phạm vi mô phỏng. Nhưng chúng ta phải gọi nó là mô phỏng thay vì mô phỏng bởi vì mô phỏng bao gồm quá trình mô phỏng nhưng có nghĩa là chúng ta có trạng thái đứng, một giải pháp lý tưởng của mô phỏng: mô phỏng. Vì vậy, chúng ta cần gọi nó là mô phỏng trong URL. Đây cũng có thể là một giải pháp tốt:

GET  /api/emulation - 200 OK {first:1, last:123}
POST /api/emulation/124 - 200 OK
GET  /api/emulation/124/config - 200 OK {config:{tax:8}}
PUT  /api/emulation/124/config {config:{tax:16}} - 200 OK {config:{tax:16}}
GET  /api/emulation/124/items - 200 OK [first:1, last: 3000]
GET  /api/emulation/124/items/1 - 200 OK {price:1.79, name:'Cup'}
--- show emulation ---
--- commit emulation ---
PUT /api/config {config:{tax:16}}
DELETE /api/emulation/124 - 200 OK

Có một cách tiếp cận khác .... bạn có thể nhận thấy có rất nhiều yêu cầu từ ứng dụng khách HTML / JavaScript có thể tạo ra Quá nhiều yêu cầu , đạt đến giới hạn của khoảng 17 yêu cầu cùng một lúc (hãy xem trang này ). Bạn có thể trao đổi cách sử dụng REST và thay vì phân phối trạng thái đối tượng khập khiễng, bạn có thể phân phối trạng thái trang cụ thể của người dùng. Thí dụ:

GET /user/123/config - 200 OK {user:'Tim', date:3298347239847, currentItem:123, 
                  roles:['Admin','Customer'], config:{tax:16}, unsavedChanges:true, ...}

Trân trọng

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.