Các API RESTful có xu hướng khuyến khích các mô hình miền thiếu máu không?


34

Tôi đang làm việc trong một dự án mà chúng tôi đang cố gắng áp dụng cả thiết kế hướng tên miền và REST cho kiến ​​trúc hướng dịch vụ. Chúng tôi không lo lắng về việc tuân thủ REST 100%; có lẽ sẽ tốt hơn khi nói rằng chúng tôi đang cố gắng xây dựng các API HTTP hướng tài nguyên (~ Cấp độ 2 của mô hình trưởng thành REST của Richardson). Tuy nhiên, chúng tôi đang cố gắng tránh xa việc sử dụng các yêu cầu HTTP theo kiểu RPC, tức là chúng tôi cố gắng thực hiện các động từ HTTP theo RFC2616 thay vì sử dụng POSTđể làm IsPostalAddressValid(...), chẳng hạn.

Tuy nhiên, một sự nhấn mạnh về điều này dường như là chi phí cho nỗ lực của chúng tôi để áp dụng thiết kế theo hướng tên miền. Với chỉ GET, POST, PUT, DELETEvà một vài phương pháp ít được sử dụng khác, chúng ta có xu hướng để xây dựng các dịch vụ cruddy, và dịch vụ cruddy có xu hướng có các mô hình miền thiếu máu.

POST: Nhận dữ liệu, xác thực nó, kết xuất dữ liệu. GET: Lấy dữ liệu, trả lại. Không có logic kinh doanh thực sự ở đó. Chúng tôi cũng sử dụng tin nhắn (sự kiện) giữa các dịch vụ và dường như hầu hết logic kinh doanh cuối cùng được xây dựng xung quanh đó.

REST và DDD có căng thẳng ở một mức độ nào đó không? (Hoặc tôi có đang hiểu nhầm điều gì đó ở đây không? Có phải chúng ta có thể làm sai điều gì khác không?) Có thể xây dựng mô hình miền mạnh trong kiến ​​trúc hướng dịch vụ trong khi tránh các cuộc gọi HTTP kiểu RPC không?


1
POST được cố tình thiết kế để "mơ hồ có chủ ý;" kết quả của một POST là cụ thể thực hiện. Điều gì ngăn bạn thực hiện những gì Twitter và các nhà thiết kế API khác làm và xác định từng phương thức POST trong phần không CRUD của API theo yêu cầu cụ thể của riêng bạn?
Robert Harvey

@RobertHarvey Chúng tôi đã hiểu POST là một sáng tạo. Nhìn vào tiêu chuẩn một lần nữa, có lẽ đó là quá đơn giản. Ví dụ: bạn có nghĩ POST để thực hiện IsPostalAddressValid(...)sẽ phù hợp với "Cung cấp một khối dữ liệu, chẳng hạn như kết quả của việc gửi biểu mẫu, cho quy trình xử lý dữ liệu" không?
Kazark

Đó là bởi vì không có động từ TẠO (và không có động từ CẬP NHẬT, cho vấn đề đó). Tôi duy trì rằng những động từ đó bị thiếu trong tiêu chuẩn (vì bất kỳ lý do gì), đó là lý do tại sao bạn phải đồng chọn POST cho "mọi thứ khác". "Quy trình xử lý dữ liệu" của bạn, trong trường hợp này, là quy trình kiểm tra địa chỉ bưu chính và trả về một giá trị tương ứng với kết quả phân tích đó.
Robert Harvey

1
@RobertHarvey: Tôi tin rằng POST và PUT / PATCH chỉ đơn giản là động từ TẠO và CẬP NHẬT mà bạn đang muốn. Nó chỉ được đặt tên khác nhau để động từ vẫn có ý nghĩa ngay cả trong thiết kế phi RESTful.
Lie Ryan

@LieRyan: Tôi sẽ cấp cho bạn cái đó. Tôi chỉ nghĩ rằng CRUD ngụ ý các mô hình dữ liệu thiếu máu theo định nghĩa. Bạn có thể thực hiện một số hành vi nếu, giả sử, bạn đang ở trong M của MVC, nhưng chắc chắn không phải trên các hệ thống không đồng nhất. Đối với mọi thứ khác ngoài CRUD, bạn cần POST.
Robert Harvey

Câu trả lời:


38

Luật đầu tiên của Martin Fowler về các hệ thống phân tán: "Đừng phân phối các đối tượng của bạn!" Các giao diện từ xa phải được tạo hạt thô và các giao diện bên trong được tạo hạt mịn. Thông thường mô hình miền phong phú chỉ áp dụng trong bối cảnh giới hạn .

API REST tách hai bối cảnh khác nhau, cả hai đều có mô hình bên trong riêng. Các bối cảnh giao tiếp thông qua giao diện chi tiết thô (API REST) ​​bằng cách sử dụng các đối tượng "thiếu máu" (DTO).

Trong trường hợp của bạn, có vẻ như bạn đang cố gắng truyền bá một bối cảnh qua một ranh giới đó là API REST. Điều này có thể dẫn đến giao diện từ xa chi tiết hoặc mô hình thiếu máu. Tùy thuộc vào dự án của bạn, nó có thể hoặc không thể là một vấn đề.


1
Fowler có rất nhiều suy nghĩ tốt nhưng chúng ta đừng quên thảm họa mà các thông số và triển khai EJB ban đầu là gì. Chỉ sau khi họ phát hiện ra rằng các cuộc gọi phương thức cấp thấp cho mọi hoạt động nhỏ như getName () là một cơn ác mộng mạng / tải. Các giao diện chi tiết thô đã trở thành hướng đi và với nó khái niệm rằng toàn bộ biểu đồ / thông điệp thực thể đã được gửi và nhận trong ngữ cảnh động từ + danh từ.
Darrell Teague

9

POST được cố tình thiết kế để "mơ hồ có chủ ý;" kết quả của một POST là cụ thể thực hiện. Điều gì ngăn bạn thực hiện những gì Twitter và các nhà thiết kế API khác làm và xác định từng phương thức POST trong phần không CRUD của API theo yêu cầu cụ thể của riêng bạn? POST là động từ Catchall. Sử dụng nó khi không có động từ nào khác phù hợp với thao tác bạn muốn thực hiện.

Nói cách khác, câu hỏi của bạn có thể được đặt ra tương tự như các đối tượng "Thông minh" có khuyến khích thiết kế theo kiểu RPC không? " Ngay cả Martin Fowler (người đặt ra thuật ngữ "Mô hình miền thiếu máu") cũng thừa nhận rằng DTO trần có một số lợi ích:

Đặt hành vi vào các đối tượng miền không được mâu thuẫn với cách tiếp cận vững chắc của việc sử dụng phân lớp để tách logic miền khỏi những thứ như sự kiên trì và trách nhiệm trình bày. Logic nên có trong một đối tượng miền là logic miền - xác nhận, tính toán, quy tắc kinh doanh - bất cứ điều gì bạn muốn gọi nó.

Liên quan đến Mô hình trưởng thành của Richardson , bạn có thể lên cấp 3 mà không bao giờ liên quan đến bản thân về "Mô hình miền thiếu máu". Hãy nhớ rằng, bạn sẽ không bao giờ chuyển hành vi sang trình duyệt (trừ khi bạn có kế hoạch tiêm một số Javascript thông qua các mô hình của bạn).

REST chủ yếu là về sự độc lập của máy; triển khai mô hình REST ở mức độ mà bạn muốn các điểm cuối của bạn thể hiện các tài nguyên và để người tiêu dùng API của bạn có thể dễ dàng truy cập và duy trì các tài nguyên đó theo cách tiêu chuẩn. Nếu điều đó có vẻ thiếu máu, thì cũng vậy.

Xem thêm
Tôi cần thêm động từ


Tôi nghĩ rằng chắc chắn giải quyết vấn đề RFC2616 của câu hỏi. Điều gì về thực tế là chúng ta đang cố gắng định hướng tài nguyên, tức là ít nhất là cố gắng đạt được Cấp độ 2 trong mô hình trưởng thành của Richardson cho REST?
Kazark

1
Tôi đọc qua martinfowler.com/articles/richardsonMaturityModel.html . Bạn có thể đạt đến cấp 3 mà không bao giờ liên quan đến bản thân về "Mô hình miền thiếu máu". Hãy nhớ rằng, bạn sẽ không bao giờ chuyển hành vi sang trình duyệt (trừ khi bạn có kế hoạch tiêm một số Javascript thông qua các mô hình của bạn).
Robert Harvey

4

API REST chỉ là một loại lớp trình bày. Nó không có gì để làm với mô hình miền.

Câu hỏi bạn đăng lên xuất phát từ sự nhầm lẫn của bạn rằng bằng cách nào đó bạn cần phải thích ứng cái này với cái khác. Bạn không.

Bạn ánh xạ mô hình miền của mình tới API REST giống như cách bạn ánh xạ mô hình miền của mình sang RDBMS thông qua ORM - phải có lớp ánh xạ này.

Miền ← ORM → RDBMS
Miền ← Ánh xạ REST → API REST


3

IMHO Tôi không nghĩ họ có xu hướng khuyến khích các mô hình miền thiếu máu (ADM), nhưng họ yêu cầu bạn phải dành thời gian và suy nghĩ kỹ.

Trước hết tôi nghĩ đặc điểm chính của ADM là chúng có ít hoặc không có hành vi nào trong đó. Điều đó không có nghĩa là hệ thống không có hành vi, chỉ là nó thường ở một loại dịch vụ nào đó (xem http://vimeo.com/43598193 ).

Và tất nhiên nếu hành vi không tồn tại trong ADM, thì sao? Câu trả lời tất nhiên là dữ liệu. Và làm thế nào để ánh xạ này tới API REST? Có lẽ là ánh xạ dữ liệu đến nội dung của tài nguyên và ánh xạ hành vi tới các động từ HTTP.

Vì vậy, bạn có mọi thứ bạn cần để xây dựng một mô hình miền phong phú, bạn chỉ cần có thể xem cách các động từ HTTP ánh xạ tới các hoạt động miền trên dữ liệu, sau đó đặt các hoạt động đó vào cùng các lớp đóng gói dữ liệu của bạn.

Tôi nghĩ rằng nơi mọi người có xu hướng gặp vấn đề là họ gặp khó khăn khi xem các động từ HTTP ánh xạ tới hành vi miền của họ như thế nào khi hành vi vượt quá CRUD đơn giản, tức là khi có các tác dụng phụ trong các phần khác của miền ngoài tài nguyên đang được sửa đổi bởi yêu cầu HTTP. Một cách để giải quyết vấn đề đó là với các sự kiện trong miền ( http://www.udidahan.com/2009/06/14/domain-events-salvation/ ).


3

Bài viết này khá liên quan đến chủ đề và tôi tin rằng câu trả lời cho câu hỏi của bạn.

Một khái niệm cốt lõi mà tôi nghĩ rằng trả lời câu hỏi của bạn rất tốt, được tóm tắt trong đoạn văn sau từ bài viết được đề cập:

"Điều rất quan trọng là phải phân biệt giữa các tài nguyên trong API REST và các thực thể miền trong thiết kế hướng tên miền. Thiết kế theo hướng miền áp dụng cho phía triển khai của mọi thứ (bao gồm triển khai API) trong khi tài nguyên trong API API điều khiển thiết kế và hợp đồng API. lựa chọn không nên phụ thuộc vào chi tiết triển khai tên miền cơ bản. "


1

Một số triển khai hợp lý thành công mà tôi đã thấy / xây dựng trả lời câu hỏi về cách họ kết hợp ẩn dụ động từ + danh từ bằng cách sử dụng các phương pháp 'thân thiện với kinh doanh' chi tiết, hoạt động trên các thực thể.

Vì vậy, thay vì getName()phương thức / dịch vụ (cam chịu) , hãy phơi bày getPerson(), chuyển vào những thứ như kiểu định danh / ID, trả về toàn bộ Personthực thể.

Vì các hành vi của thực thể Person trong ngữ cảnh như vậy không thể được truyền đạt đầy đủ (có lẽ chúng cũng không nên ở trong bối cảnh tập trung vào dữ liệu như thế này), nên việc xác định mô hình dữ liệu (so với đối tượng) cho các cặp yêu cầu / phản hồi là hoàn toàn hợp lý các dịch vụ.

Bản thân các dịch vụ và động từ được xác định sẽ thêm một số hành vi, điều khiển cho phép tên miền và thậm chí các quy tắc chuyển đổi trạng thái cho các thực thể. Ví dụ, sẽ có logic cụ thể theo miền như những gì xảy ra trong lệnh transferPerson()gọi dịch vụ nhưng bản thân giao diện sẽ chỉ xác định các thực thể / dữ liệu đầu vào / đầu ra mà không xác định các hành vi bên trong THEIR.

Tôi sẽ không đồng ý với các tác giả sẽ nói, ví dụ, việc triển khai động từ chuyển thuộc về lớp Người hoặc được liên kết với dịch vụ Trung tâm cá nhân. Thật vậy, phương thức chuyển giao cho a Personvà các tùy chọn của chúng (trong ví dụ đơn giản này) sẽ được xác định rõ hơn bởi a Carrier, trong đó Personcó thể không có kiến ​​thức về ngay cả phương thức chuyển nào có sẵn hoặc cách thức chuyển giao diễn ra (ai biết cách thức hoạt động của động cơ phản lực dù sao).

Điều này có làm cho Personthực thể thiếu máu? Tôi không nghĩ vậy.

Có thể / nên có logic về những thứ cụ thể của Người bên trong đối với Người như trạng thái sức khỏe của họ, không được định nghĩa bởi một lớp bên ngoài.

Tuy nhiên, tùy thuộc vào các trường hợp sử dụng, hoàn toàn có thể chấp nhận rằng một lớp thực thể không có hành vi quan trọng / có liên quan trong một số hệ thống nhất định, chẳng hạn như dịch vụ phân công chỗ ngồi trong hệ thống giao thông. Một hệ thống như vậy có thể triển khai tốt các dịch vụ dựa trên REST xử lý các cá thể Person và các định danh liên quan nhưng không bao giờ xác định / thực hiện các hành vi bên trong của chúng.


Điểm hay --- điều này thực sự mang lại một số viễn cảnh mới mẻ mà các câu trả lời khác chưa có.
Kazark

0

Có phải vấn đề của bạn là bạn đang cố gắng nhồi nhét mô hình của mình vào nhóm động từ cơ bản, sử dụng POST càng nhiều càng tốt?

Không cần thiết - tôi biết rằng với hầu hết mọi người, REST có nghĩa là POST, GET, PUT và DELETE, nhưng http rfc nói:

Tập hợp các phương thức phổ biến cho HTTP / 1.1 được định nghĩa dưới đây. Mặc dù bộ này có thể được mở rộng, các phương thức bổ sung không thể được giả sử để chia sẻ cùng một ngữ nghĩa cho các máy khách và máy chủ được mở rộng riêng biệt.

Và các hệ thống như SMTP sử dụng cùng một kiểu phương thức dựa trên động từ nhưng với một bộ hoàn toàn khác.

Vì vậy, không có lý do tại sao bạn phải sử dụng những thứ này, bạn có thể sử dụng bất kỳ nhóm động từ nào bạn thích (mặc dù, thực sự bạn sẽ thấy rằng bạn có thể làm mọi thứ bạn cần trong 4 cơ bản với một chút suy nghĩ). Điều làm cho REST khác biệt so với các cơ chế khác là cách thức không trạng thái và nhất quán của nó khi thực hiện các động từ này. Bạn không nên cố gắng triển khai hệ thống chuyển tin nhắn giữa các tầng vì về cơ bản bạn không thực hiện REST, bạn đang thực hiện cơ chế truyền tin nhắn, RPC hoặc tin nhắn hàng đợi thay vào đó chắc chắn sẽ làm mất đi lợi ích của REST (tức là sự đơn giản của nó làm cho nó hoạt động thực sự tốt qua kết nối http).

Nếu bạn muốn có một giao thức nhắn tin phức tạp, đầy đủ tính năng, thì hãy xây dựng giao thức đó (nếu bạn có thể làm như vậy qua web, có một lý do tại sao REST rất phổ biến), nhưng nếu không thì hãy cố gắng tuân theo thiết kế kiến ​​trúc của REST.

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.