Giao dịch trong REST?


147

Tôi đang tự hỏi làm thế nào bạn thực hiện trường hợp sử dụng sau trong REST. Thậm chí có thể làm mà không ảnh hưởng đến mô hình khái niệm?

Đọc hoặc cập nhật nhiều tài nguyên trong phạm vi của một giao dịch. Ví dụ: chuyển $ 100 từ tài khoản ngân hàng của Bob vào tài khoản của John.

Theo như tôi có thể nói, cách duy nhất để thực hiện điều này là bằng cách gian lận. Bạn có thể POST vào tài nguyên được liên kết với John hoặc Bob và thực hiện toàn bộ hoạt động bằng một giao dịch duy nhất. Theo như tôi quan tâm thì điều này phá vỡ kiến ​​trúc REST vì về cơ bản bạn đang thực hiện một cuộc gọi RPC thông qua POST thay vì thực sự hoạt động trên các tài nguyên riêng lẻ.

Câu trả lời:


91

Hãy xem xét một kịch bản giỏ mua hàng RESTful. Giỏ mua hàng về mặt khái niệm là gói giao dịch của bạn. Cũng giống như cách bạn có thể thêm nhiều mặt hàng vào giỏ mua hàng và sau đó gửi giỏ hàng đó để xử lý đơn đặt hàng, bạn có thể thêm mục nhập tài khoản của Bob vào trình bao bọc giao dịch và sau đó nhập tài khoản của Bill vào trình bao bọc. Khi tất cả các phần được đặt đúng chỗ, bạn có thể POST / PUT trình bao bọc giao dịch với tất cả các phần thành phần.


18
Tại sao TransferMoneyTransaction không phải là một tài nguyên ngân hàng khả thi?
Darrel Miller

8
Nếu bạn đảm bảo rằng các điểm cuối của bạn đề cập đến danh từ thì thường trực quan những động từ GET, PUT, POST, DELETE tiêu chuẩn sẽ làm gì với danh từ đó. RPC cho phép các điểm cuối là chính các động từ và do đó chúng có thể xung đột với các động từ HTTP và ý định trở nên khó hiểu.
Darrel Miller

10
ví dụ: Điều gì xảy ra nếu bạn thực hiện XÓA HTTP trên UpdateXYZ điểm cuối? Nó có xóa XYZ không? Nó có xóa Cập nhật không hay chỉ thực hiện Cập nhật và bỏ qua xóa động từ HTTP. Bằng cách giữ các động từ ra khỏi điểm cuối, bạn loại bỏ sự nhầm lẫn.
Darrel Miller

5
Và những gì về giao dịch trên nhiều dịch vụ? và điều gì xảy ra khi bạn muốn thực hiện một tập hợp các thay đổi 'không liên quan' mà dịch vụ không có bộ chứa giao dịch ngầm .. cộng với, tại sao lại có loại giao dịch cụ thể khi chúng tôi chuyển sang giao dịch mục đích chung hoàn toàn không liên quan đến dữ liệu thực tế của bạn thay đổi. Các giao dịch có thể không khớp với trạng thái nghỉ ngơi, nhưng có vẻ như các giao dịch nên được phân lớp, không liên quan đến các cuộc gọi còn lại ngoài thực tế là các tiêu đề yêu cầu sẽ chứa tham chiếu giao dịch.
meandmycode

4
@meandmycode Các giao dịch cơ sở dữ liệu nên được xếp sau một giao diện REST. Thay phiên, bạn có thể hiển thị một giao dịch kinh doanh (không phải là giao dịch cơ sở dữ liệu) dưới dạng tài nguyên và sau đó bạn cần thực hiện hành động bù trong trường hợp thất bại.
Darrel Miller

60

Có một vài trường hợp quan trọng không được trả lời bởi câu hỏi này, điều mà tôi nghĩ là quá tệ, bởi vì nó có thứ hạng cao trên Google cho các cụm từ tìm kiếm :-)

Cụ thể, một cách đúng đắn sẽ là: Nếu bạn POST hai lần (vì một số bộ đệm bị ẩn trong trung gian), bạn không nên chuyển số tiền hai lần.

Để có được điều này, bạn tạo một giao dịch như một đối tượng. Điều này có thể chứa tất cả dữ liệu bạn đã biết và đặt giao dịch ở trạng thái chờ xử lý.

POST /transfer/txn
{"source":"john's account", "destination":"bob's account", "amount":10}

{"id":"/transfer/txn/12345", "state":"pending", "source":...}

Khi bạn có giao dịch này, bạn có thể cam kết nó, đại loại như:

PUT /transfer/txn/12345
{"id":"/transfer/txn/12345", "state":"committed", ...}

{"id":"/transfer/txn/12345", "state":"committed", ...}

Lưu ý rằng nhiều điểm không quan trọng tại thời điểm này; ngay cả một GET trên txn cũng sẽ trả về trạng thái hiện tại. Cụ thể, PUT thứ hai sẽ phát hiện ra rằng cái đầu tiên đã ở trạng thái thích hợp và chỉ cần trả lại nó - hoặc, nếu bạn cố gắng đặt nó ở trạng thái "rollback" sau khi nó ở trạng thái "đã cam kết", bạn sẽ nhận được lỗi, và giao dịch cam kết thực tế trở lại.

Miễn là bạn nói chuyện với một cơ sở dữ liệu hoặc cơ sở dữ liệu có trình giám sát giao dịch tích hợp, cơ chế này sẽ thực sự hoạt động tốt. Bạn cũng có thể giới thiệu thời gian chờ cho các giao dịch, thậm chí bạn có thể thể hiện bằng cách sử dụng các tiêu đề Hết hạn nếu bạn muốn.


Thảo luận thú vị! Tôi muốn thêm rằng bài viết ban đầu phải được thực hiện trong một bước. Không thể thêm vào sau này (khi đó chúng tôi ở trong khu vực giỏ hàng và giỏ mua hàng có nhiều kiểm tra và số dư để ngăn chúng gây hại cho người dùng cuối, thậm chí cả pháp luật, chuyển khoản ngân hàng không) ...
Erk

33

Trong thuật ngữ REST, tài nguyên là danh từ có thể được sử dụng với các động từ CRUD (tạo / đọc / cập nhật / xóa). Vì không có động từ "chuyển tiền", chúng tôi cần xác định tài nguyên "giao dịch" có thể được thực hiện với CRUD. Đây là một ví dụ trong HTTP + POX. Bước đầu tiên là TẠO (phương thức POST HTTP) một giao dịch trống mới :

POST /transaction

Điều này trả về ID giao dịch, ví dụ: "1234" và theo URL "/ giao dịch / 1234". Lưu ý rằng việc bắn POST này nhiều lần sẽ không tạo ra cùng một giao dịch với nhiều ID và cũng tránh được việc giới thiệu trạng thái "đang chờ xử lý". Ngoài ra, POST không phải lúc nào cũng là idempotent (yêu cầu REST), do đó, nói chung nên thực hành tốt để giảm thiểu dữ liệu trong POST.

Bạn có thể để lại việc tạo ID giao dịch cho khách hàng. Trong trường hợp này, bạn sẽ POST / giao dịch / 1234 để tạo giao dịch "1234" và máy chủ sẽ trả về lỗi nếu nó đã tồn tại. Trong phản hồi lỗi, máy chủ có thể trả về ID hiện không được sử dụng với một URL thích hợp. Không nên truy vấn máy chủ để tìm ID mới bằng phương thức GET, vì GET không bao giờ thay đổi trạng thái máy chủ và việc tạo / dự trữ ID mới sẽ thay đổi trạng thái máy chủ.

Tiếp theo, chúng tôi CẬP NHẬT (phương pháp PUT HTTP) giao dịch với tất cả dữ liệu, hoàn toàn cam kết:

PUT /transaction/1234
<transaction>
  <from>/account/john</from>
  <to>/account/bob</to>
  <amount>100</amount>
</transaction>

Nếu một giao dịch có ID "1234" đã được PUT trước đó, thì máy chủ sẽ đưa ra phản hồi lỗi, nếu không thì phản hồi OK và URL để xem giao dịch đã hoàn thành.

NB: in / account / john, "john" thực sự phải là số tài khoản duy nhất của John.


4
Đánh đồng REST với CRUD là một sai lầm nghiêm trọng. POST không có nghĩa là TẠO.

12
Sai lầm nghiêm trọng? Tôi biết có sự khác biệt giữa PUT và POST, nhưng có một ánh xạ lỏng lẻo đến CRUD. "Nghiêm túc"?
Ted Johnson

3
Vâng, rất nghiêm trọng. CRUD là một cách cấu trúc lưu trữ dữ liệu; REST là một cách cấu trúc luồng dữ liệu ứng dụng. Bạn có thể thực hiện CRUD trên REST, nhưng bạn không thể thực hiện REST trên CRUD. Chúng không tương đương.
Jon Watte

20

Câu hỏi tuyệt vời, REST chủ yếu được giải thích với các ví dụ giống như cơ sở dữ liệu, trong đó một cái gì đó được lưu trữ, cập nhật, truy xuất, xóa. Có một vài ví dụ như thế này, trong đó máy chủ có nhiệm vụ xử lý dữ liệu theo một cách nào đó. Tôi không nghĩ Roy Fielding bao gồm bất kỳ trong luận án của mình, mà dựa trên http sau tất cả.

Nhưng anh ấy nói về "chuyển trạng thái đại diện" như một cỗ máy trạng thái, với các liên kết chuyển sang trạng thái tiếp theo. Theo cách này, các tài liệu (các biểu diễn) theo dõi trạng thái máy khách, thay vì máy chủ phải thực hiện. Theo cách này, không có trạng thái máy khách, chỉ có trạng thái liên kết với bạn.

Tôi đã suy nghĩ về điều này và có vẻ hợp lý với tôi rằng để máy chủ xử lý thứ gì đó cho bạn, khi bạn tải lên, máy chủ sẽ tự động tạo các tài nguyên liên quan và cung cấp cho bạn các liên kết đến chúng (thực tế, nó sẽ không Bạn không cần phải tự động tạo chúng: nó chỉ có thể cho bạn biết các liên kết và nó chỉ tạo chúng khi và nếu bạn theo dõi chúng - tạo lười biếng). Và cũng cung cấp cho bạn các liên kết để tạo các tài nguyên liên quan mới - một tài nguyên có liên quan có cùng URI nhưng dài hơn (thêm một hậu tố). Ví dụ:

  1. Bạn tải lên ( POST ) đại diện cho khái niệm giao dịch với tất cả các thông tin. Điều này trông giống như một cuộc gọi RPC, nhưng nó thực sự tạo ra "tài nguyên giao dịch được đề xuất". ví dụ: URI: /transaction Glitches sẽ khiến nhiều tài nguyên như vậy được tạo, mỗi tài nguyên có một URI khác nhau.
  2. Phản hồi của máy chủ nêu URI của tài nguyên đã tạo, đại diện của tài nguyên - bao gồm liên kết ( URI ) để tạo tài nguyên liên quan của "tài nguyên giao dịch đã cam kết" mới. Các tài nguyên liên quan khác là liên kết để xóa giao dịch được đề xuất. Đây là những trạng thái trong máy trạng thái, mà máy khách có thể theo dõi. Về mặt logic, đây là một phần của tài nguyên đã được tạo trên máy chủ, ngoài thông tin khách hàng cung cấp. ví dụ: URI : /transaction/1234/proposed, /transaction/1234/committed
  3. Bạn POST vào liên kết để tạo "tài nguyên giao dịch đã cam kết" , tạo tài nguyên đó, thay đổi trạng thái của máy chủ (số dư của hai tài khoản) **. Về bản chất, tài nguyên này chỉ có thể được tạo một lần và không thể cập nhật. Do đó, trục trặc cam kết nhiều giao dịch không thể xảy ra.
  4. Bạn có thể NHẬN hai tài nguyên đó, để xem trạng thái của chúng là gì. Giả sử rằng POST có thể thay đổi các tài nguyên khác, đề xuất hiện sẽ được gắn cờ là "đã cam kết" (hoặc có lẽ, hoàn toàn không có sẵn).

Điều này tương tự như cách các trang web hoạt động, với trang web cuối cùng có nội dung "bạn có chắc chắn muốn làm điều này không?" Trang web cuối cùng đó tự nó là một đại diện cho trạng thái của giao dịch, bao gồm một liên kết để đi đến trạng thái tiếp theo. Không chỉ giao dịch tài chính; cũng (ví dụ) xem trước sau đó cam kết trên wikipedia. Tôi đoán sự khác biệt trong REST là mỗi giai đoạn trong chuỗi trạng thái có một tên rõ ràng (URI của nó).

Trong các giao dịch / bán hàng thực tế, thường có các tài liệu vật lý khác nhau cho các giai đoạn khác nhau của giao dịch (đề xuất, đơn đặt hàng, biên lai, v.v.). Thậm chí nhiều hơn để mua một ngôi nhà, với sự định cư, vv

OTOH Cảm giác này giống như chơi với ngữ nghĩa đối với tôi; Tôi không thoải mái với việc đề cử chuyển động từ thành danh từ để biến nó thành RESTful, "bởi vì nó sử dụng danh từ (URI) thay vì động từ (gọi RPC)". tức là danh từ "tài nguyên giao dịch đã cam kết" thay vì động từ "cam kết giao dịch này". Tôi đoán một ưu điểm của danh nghĩa là bạn có thể tham khảo tài nguyên theo tên, thay vì cần chỉ định nó theo một cách khác (chẳng hạn như duy trì trạng thái phiên, vì vậy bạn biết giao dịch "này" là gì ...)

Nhưng câu hỏi quan trọng là: lợi ích của phương pháp này là gì? tức là theo cách nào thì kiểu REST này tốt hơn kiểu RPC? Là một kỹ thuật tuyệt vời cho các trang web cũng hữu ích để xử lý thông tin, ngoài việc lưu trữ / truy xuất / cập nhật / xóa? Tôi nghĩ rằng lợi ích chính của REST là khả năng mở rộng; một khía cạnh của điều đó là không cần phải duy trì trạng thái máy khách một cách rõ ràng (nhưng làm cho nó ẩn trong URI của tài nguyên và các trạng thái tiếp theo dưới dạng liên kết trong biểu diễn của nó). Theo nghĩa đó, nó giúp. Có lẽ điều này cũng giúp trong việc xếp lớp / đường ống? OTOH chỉ có một người dùng sẽ xem xét giao dịch cụ thể của họ, vì vậy không có lợi thế nào trong việc lưu trữ nó để người khác có thể đọc nó, chiến thắng lớn cho http.


Bạn có thể giải thích làm thế nào "không cần giữ trạng thái trên máy khách" giúp khả năng mở rộng? Những loại khả năng mở rộng? Khả năng mở rộng theo nghĩa nào?
jhegedus

11

Nếu bạn đứng lại để tóm tắt cuộc thảo luận ở đây, thì rõ ràng REST không phù hợp với nhiều API, đặc biệt là khi tương tác giữa máy khách và máy chủ vốn có trạng thái, như với các giao dịch không tầm thường. Tại sao phải nhảy qua tất cả các vòng được đề xuất, cho cả máy khách và máy chủ, để theo phương pháp sư phạm theo một số nguyên tắc không phù hợp với vấn đề? Một nguyên tắc tốt hơn là cung cấp cho khách hàng cách dễ nhất, tự nhiên nhất, hiệu quả nhất để soạn thảo với ứng dụng.

Tóm lại, nếu bạn thực sự thực hiện nhiều giao dịch (loại chứ không phải phiên bản) trong ứng dụng của mình, bạn thực sự không nên tạo API RESTful.


9
Đúng, nhưng điều gì sẽ là một sự thay thế trong trường hợp kiến ​​trúc dịch vụ vi mô phân tán?
Vitamon

11

Tôi đã rời xa chủ đề này trong 10 năm. Quay trở lại, tôi không thể tin rằng tôn giáo giả dạng là khoa học mà bạn lội vào khi bạn nghỉ ngơi + đáng tin cậy. Sự nhầm lẫn là huyền thoại.

Tôi sẽ chia câu hỏi rộng này thành ba:

  • Dịch vụ hạ nguồn. Bất kỳ dịch vụ web nào bạn phát triển sẽ có các dịch vụ tiếp theo mà bạn sử dụng và cú pháp giao dịch mà bạn không có lựa chọn nào khác ngoài việc tuân theo. Bạn nên thử và ẩn tất cả những điều này khỏi người dùng dịch vụ của bạn và đảm bảo tất cả các phần trong hoạt động của bạn thành công hay thất bại trong một nhóm, sau đó trả lại kết quả này cho người dùng của bạn.
  • Dịch vụ của bạn. Khách hàng muốn các kết quả rõ ràng cho các cuộc gọi dịch vụ web và mô hình REST thông thường của việc thực hiện các yêu cầu POST, PUT hoặc DELETE trực tiếp trên các tài nguyên quan trọng khiến tôi thấy kém, và dễ dàng cải thiện, cung cấp sự chắc chắn này. Nếu bạn quan tâm đến độ tin cậy, bạn cần xác định các yêu cầu hành động. Id này có thể là một hướng dẫn được tạo trên máy khách hoặc giá trị hạt giống từ DB quan hệ trên máy chủ, không thành vấn đề. Đối với ID của máy chủ được tạo, hãy sử dụng phản hồi yêu cầu 'preflight' để trao đổi id của hành động. Nếu yêu cầu này thất bại hoặc một nửa thành công, không có vấn đề gì, khách hàng chỉ cần lặp lại yêu cầu. Id không sử dụng không làm hại.

    Điều này rất quan trọng vì nó cho phép tất cả các yêu cầu tiếp theo hoàn toàn bình thường, theo nghĩa là nếu chúng được lặp lại n lần thì chúng sẽ trả về cùng một kết quả và không có gì xảy ra nữa. Máy chủ lưu trữ tất cả các phản hồi đối với id hành động và nếu thấy cùng một yêu cầu, nó sẽ phát lại cùng một phản hồi. Một điều trị đầy đủ hơn của mẫu là trong tài liệu google này . Tài liệu cho thấy một triển khai mà tôi tin rằng (!), Theo sau rộng rãi các hiệu trưởng REST. Các chuyên gia chắc chắn sẽ cho tôi biết làm thế nào nó vi phạm người khác. Mẫu này có thể được sử dụng một cách hữu ích cho bất kỳ cuộc gọi không an toàn nào đến dịch vụ web của bạn, cho dù có liên quan đến các giao dịch tiếp theo hay không.
  • Tích hợp dịch vụ của bạn vào "giao dịch" được kiểm soát bởi các dịch vụ ngược dòng. Trong ngữ cảnh của các dịch vụ web, các giao dịch ACID đầy đủ thường được coi là không đáng để bỏ công sức, nhưng bạn có thể giúp người tiêu dùng dịch vụ của bạn rất nhiều bằng cách cung cấp hủy và / hoặc xác nhận các liên kết trong phản hồi xác nhận của bạn và do đó đạt được các giao dịch bằng cách bồi thường .

Yêu cầu của bạn là một trong những cơ bản. Đừng để mọi người nói với bạn rằng giải pháp của bạn không nghiêm túc hơn. Đánh giá kiến ​​trúc của họ dưới ánh sáng tốt như thế nào, và đơn giản, họ giải quyết vấn đề của bạn.


9

Bạn sẽ phải cuộn loại quản lý tx "id giao dịch" của riêng mình. Vì vậy, nó sẽ là 4 cuộc gọi:

http://service/transaction (some sort of tx request)
http://service/bankaccount/bob (give tx id)
http://service/bankaccount/john (give tx id)
http://service/transaction (request to commit)

Bạn sẽ phải xử lý việc lưu trữ các hành động trong DB (nếu tải cân bằng) hoặc trong bộ nhớ hoặc như vậy, sau đó xử lý cam kết, khôi phục, hết thời gian.

Không thực sự là một ngày RESTful trong công viên.


4
Tôi không nghĩ rằng đây là một minh họa đặc biệt tốt. Bạn chỉ cần hai bước: Tạo giao dịch (tạo giao dịch ở trạng thái "đang chờ xử lý") và giao dịch Cam kết (cam kết nếu không được cam kết và chuyển tài nguyên sang trạng thái cam kết hoặc khôi phục).
Jon Watte

2

Tôi nghĩ rằng trong trường hợp này, việc phá vỡ lý thuyết thuần túy về REST trong tình huống này là hoàn toàn chấp nhận được. Trong mọi trường hợp, tôi không nghĩ có bất cứ điều gì thực sự trong REST nói rằng bạn không thể chạm vào các đối tượng phụ thuộc trong các trường hợp kinh doanh yêu cầu điều đó.

Tôi thực sự nghĩ rằng nó không đáng để bạn sử dụng để tạo một trình quản lý giao dịch tùy chỉnh, khi bạn có thể tận dụng cơ sở dữ liệu để thực hiện.


2

Trước hết, chuyển tiền là không có gì bạn không thể làm trong một cuộc gọi tài nguyên. Hành động bạn muốn làm là gửi tiền. Vì vậy, bạn thêm một tài nguyên chuyển tiền vào tài khoản của người gửi.

POST: accounts/alice, new Transfer {target:"BOB", abmount:100, currency:"CHF"}.

Làm xong. Bạn không cần phải biết rằng đây là một giao dịch phải là nguyên tử, v.v. Bạn chỉ cần chuyển tiền aka. gửi tiền từ A đến B.


Nhưng đối với những trường hợp hiếm hoi ở đây, một giải pháp chung:

Nếu bạn muốn làm một cái gì đó rất phức tạp liên quan đến nhiều tài nguyên trong một bối cảnh xác định với rất nhiều hạn chế thực sự vượt qua những gì so với lý do tại sao rào cản (kinh doanh so với kiến ​​thức triển khai), bạn cần chuyển trạng thái. Vì REST sẽ không trạng thái khi bạn là khách hàng cần chuyển trạng thái xung quanh.

Nếu bạn chuyển trạng thái, bạn cần ẩn thông tin bên trong từ máy khách. Khách hàng không nên biết thông tin nội bộ chỉ cần thực hiện nhưng không mang thông tin liên quan về mặt kinh doanh. Nếu những thông tin đó không có giá trị kinh doanh, trạng thái sẽ được mã hóa và một phép ẩn dụ như mã thông báo, vượt qua hoặc một cái gì đó cần được sử dụng.

Bằng cách này, người ta có thể vượt qua trạng thái nội bộ xung quanh và sử dụng mã hóa và ký hệ thống vẫn có thể được bảo mật và âm thanh. Tìm kiếm sự trừu tượng phù hợp cho khách hàng tại sao anh ta chuyển qua thông tin trạng thái là một cái gì đó tùy thuộc vào thiết kế và kiến ​​trúc.


Giải pháp thực sự:

Hãy nhớ REST đang nói HTTP và HTTP đi kèm với khái niệm sử dụng cookie. Những cookie này thường bị lãng quên khi mọi người nói về API REST, quy trình làm việc và tương tác trải rộng trên nhiều tài nguyên hoặc yêu cầu.

Hãy nhớ những gì được viết trong Wikipedia về cookie HTTP:

Cookies được thiết kế để trở thành một cơ chế đáng tin cậy để các trang web ghi nhớ thông tin trạng thái (như các mục trong giỏ hàng) hoặc để ghi lại hoạt động duyệt của người dùng (bao gồm nhấp vào các nút cụ thể, đăng nhập hoặc ghi lại những trang nào được người dùng truy cập từ xa trở lại như tháng hoặc năm trước).

Vì vậy, về cơ bản nếu bạn cần chuyển qua trạng thái, hãy sử dụng cookie. Nó được thiết kế cho chính xác cùng một lý do, đó là HTTP và do đó nó tương thích với REST theo thiết kế :).


Giải pháp tốt hơn:

Nếu bạn nói về một khách hàng thực hiện một quy trình công việc liên quan đến nhiều yêu cầu, bạn thường nói về giao thức. Mỗi hình thức giao thức đi kèm với một tập hợp các điều kiện tiên quyết cho từng bước tiềm năng như thực hiện bước A trước khi bạn có thể làm B.

Điều này là tự nhiên nhưng phơi bày giao thức cho khách hàng làm cho mọi thứ phức tạp hơn. Để tránh điều đó, chỉ cần nghĩ những gì chúng ta làm khi chúng ta phải thực hiện các tương tác và những thứ phức tạp trong thế giới thực .... Chúng tôi sử dụng một Đại lý.

Sử dụng phép ẩn dụ Tác nhân, bạn có thể cung cấp tài nguyên có thể thực hiện tất cả các bước cần thiết cho bạn và lưu trữ các bài tập / hướng dẫn thực tế mà nó đang thực hiện trong danh sách của nó (vì vậy chúng tôi có thể sử dụng POST trên đại lý hoặc 'đại lý').

Một ví dụ phức tạp:

Mua một căn nhà:

Bạn cần chứng minh uy tín của mình (như cung cấp các mục trong hồ sơ cảnh sát của bạn), bạn cần đảm bảo các chi tiết tài chính, bạn cần mua nhà thực tế bằng luật sư và bên thứ ba đáng tin cậy lưu trữ tiền, xác minh rằng ngôi nhà hiện thuộc về bạn và thêm các công cụ mua vào hồ sơ thuế của bạn, vv (như một ví dụ, một số bước có thể sai hoặc bất cứ điều gì).

Các bước này có thể mất vài ngày để hoàn thành, một số có thể được thực hiện song song, v.v.

Để làm điều này, bạn chỉ cần giao cho đại lý nhiệm vụ mua nhà như sau:

POST: agency.com/ { task: "buy house", target:"link:toHouse", credibilities:"IamMe"}.

Làm xong. Cơ quan gửi lại cho bạn một tài liệu tham khảo cho bạn mà bạn có thể sử dụng để xem và theo dõi trạng thái của công việc này và phần còn lại được thực hiện tự động bởi các đại lý của cơ quan.

Hãy suy nghĩ về một trình theo dõi lỗi chẳng hạn. Về cơ bản, bạn báo cáo lỗi và có thể sử dụng id lỗi để kiểm tra xem chuyện gì đang xảy ra. Bạn thậm chí có thể sử dụng một dịch vụ để lắng nghe những thay đổi của tài nguyên này. Nhiệm vụ đã hoàn thành.


1

Bạn không được sử dụng các giao dịch phía máy chủ trong REST.

Một trong những mâu thuẫn REST:

Không quốc tịch

Giao tiếp máy chủ của khách hàng bị hạn chế hơn nữa bởi không có bối cảnh máy khách nào được lưu trữ trên máy chủ giữa các yêu cầu. Mỗi yêu cầu từ bất kỳ máy khách nào đều chứa tất cả thông tin cần thiết để phục vụ yêu cầu và bất kỳ trạng thái phiên nào được giữ trong máy khách.

Cách RESTful duy nhất là tạo nhật ký làm lại giao dịch và đưa nó vào trạng thái máy khách. Với các yêu cầu khách hàng gửi nhật ký làm lại và máy chủ thực hiện lại giao dịch và

  1. khôi phục giao dịch nhưng cung cấp nhật ký làm lại giao dịch mới (thêm một bước nữa)
  2. hoặc cuối cùng hoàn thành giao dịch.

Nhưng có lẽ đơn giản hơn là sử dụng công nghệ dựa trên phiên máy chủ hỗ trợ các giao dịch phía máy chủ.


Các trích dẫn là từ mục REST của wikipedia. Đây có phải là nguồn thực sự hay wikipedia đã lấy nó từ đâu đó? Ai sẽ nói bối cảnh khách hàng và bối cảnh máy chủ là gì?
bbsimonbb

1

Tôi tin rằng đó sẽ là trường hợp sử dụng một mã định danh duy nhất được tạo trên máy khách để đảm bảo rằng trục trặc kết nối không ngụ ý trong một bản sao được lưu bởi API.

Tôi nghĩ rằng việc sử dụng trường GUID do khách hàng tạo cùng với đối tượng chuyển khoản và đảm bảo rằng cùng một GUID không được xác nhận lại sẽ là một giải pháp đơn giản hơn cho vấn đề chuyển khoản ngân hàng.

Không biết về các kịch bản phức tạp hơn, chẳng hạn như đặt vé máy bay hoặc kiến ​​trúc vi mô.

Tôi tìm thấy một bài báo về chủ đề này, liên quan đến kinh nghiệm xử lý tính nguyên tử giao dịch trong các dịch vụ RESTful .


0

Trong trường hợp đơn giản (không có tài nguyên phân tán), bạn có thể coi giao dịch là tài nguyên, trong đó hành động tạo ra nó đạt được mục tiêu cuối cùng.

Vì vậy, để chuyển giữa <url-base>/account/a<url-base>/account/b, bạn có thể đăng bài sau đây <url-base>/transfer.

<chuyển>
    <từ> <url-cơ sở> / tài khoản / a </ from>
    <đến> <url-cơ sở> / tài khoản / b </ to>
    <số tiền> 50 </ số tiền>
</ chuyển>

Điều này sẽ tạo ra một tài nguyên chuyển nhượng mới và trả lại url mới của chuyển khoản - ví dụ <url-base>/transfer/256.

Tại thời điểm đăng bài thành công, sau đó, giao dịch 'thực' được thực hiện trên máy chủ và số tiền được xóa khỏi tài khoản này và thêm vào tài khoản khác.

Tuy nhiên, điều này không bao gồm một giao dịch phân tán (nếu, nói 'a' được tổ chức tại một ngân hàng đằng sau một dịch vụ và 'b' được tổ chức tại một ngân hàng khác đằng sau một dịch vụ khác) - ngoài việc nói "cố gắng diễn đạt tất cả hoạt động theo những cách không yêu cầu giao dịch phân tán ".


2
Nếu bạn không thể "diễn đạt tất cả các hoạt động theo cách không yêu cầu giao dịch phân tán", thì bạn thực sự cần một cam kết hai giai đoạn. Ý tưởng tốt nhất tôi có thể tìm thấy để thực hiện cam kết hai pha trên REST là rest.blueoxen.net/cgi-bin/wiki.pl?TwoPhaseCommit , điều quan trọng là không làm rối không gian tên URL và cho phép một cam kết hai pha được xếp chồng lên nhau làm sạch ngữ nghĩa REST.
Phasmal

3
Vấn đề khác với đề xuất này là, nếu một lần nấc bộ nhớ cache và POST hai lần, bạn sẽ nhận được hai lần chuyển.
Jon Watte

Đúng, trong trường hợp bạn cần có quy trình hai bước - tạo tài nguyên "chuyển" với một URL duy nhất, sau đó thêm chi tiết chuyển vào đó như một phần của cam kết (hai phần như được đề cập trong các câu trả lời khác). Tất nhiên, điều này sau đó có thể được gọi là tạo ra một tài nguyên "giao dịch" sau đó thêm một hoạt động "chuyển" vào nó.
Phasmal

-3

Tôi đoán bạn có thể bao gồm TAN trong URL / tài nguyên:

  1. PUT / giao dịch để lấy ID (ví dụ: "1")
  2. [PUT, GET, POST, bất cứ điều gì] / 1 / tài khoản / bob
  3. [PUT, GET, POST, bất cứ điều gì] / 1 / tài khoản / hóa đơn
  4. XÓA / giao dịch với ID 1

Chỉ là một ý tưởng.


Tôi thấy có hai vấn đề với cách tiếp cận này: 1) Nó ngụ ý rằng bạn không thể truy cập tài nguyên bên ngoài giao dịch (mặc dù có thể đây không phải là vấn đề lớn). 2) Không có câu trả lời nào cho đến nay đã chạm vào thực tế là máy chủ không còn trạng thái nữa, mặc dù tôi nghi ngờ không có gì có thể được thực hiện về điều đó.
Gili

Chà, / 1 / tài khoản / bob và / tài khoản / bob chỉ là hai tài nguyên khác nhau. :) Và RE: không trạng thái, nó ngụ ý rằng tài nguyên luôn có sẵn và không phụ thuộc vào yêu cầu trước đó. Vì bạn đã yêu cầu giao dịch, nên không phải vậy. Nhưng sau đó, một lần nữa, bạn muốn giao dịch.
Đến

1
Nếu khách hàng phải lắp ráp các URI, thì API của bạn không phải là RESTful.
aehlke

1
Tôi không thể hiểu các bạn, thực sự! Nếu bạn coi giao dịch là tài nguyên (như trong ví dụ ở trên), bạn chỉ cần dừng xử lý giao dịch theo nghĩa cổ điển và sử dụng nó theo "cách REST thích hợp" để đơn giản hóa hơn nữa các quy trình giao dịch lập trình. Ví dụ, bạn có thể bao gồm một href cho giao dịch trong các phản hồi của mình để đi xung quanh sự dịch chuyển trong môi trường phía máy chủ phân tán, nó vẫn không trạng thái (nó chỉ là một tài nguyên, phải không?) Và dù sao bạn cũng có thể thực hiện cơ chế giao dịch thực tế muốn (điều gì sẽ xảy ra nếu bạn không có DB ở phía sau?)
Matthias Hryniszak

1
Bằng cách này hay cách khác nếu bạn đơn giản ngừng suy nghĩ SQL / SOAP và bắt đầu nghĩ HTTP (giống như trình duyệt), mọi thứ trở nên đơn giản
Matthias Hryniszak
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.