API REST - DTOs hay không? [đóng cửa]


154

Tôi hiện đang tạo một API REST cho một dự án và đã đọc bài viết trên bài viết về các thực tiễn tốt nhất. Nhiều người dường như chống lại DTO và chỉ đơn giản là phơi bày mô hình miền, trong khi những người khác dường như nghĩ rằng DTO (hoặc Mô hình người dùng hoặc bất cứ điều gì bạn muốn gọi nó) là thực tiễn tồi. Cá nhân, tôi nghĩ rằng bài viết này có rất nhiều ý nghĩa.

Tuy nhiên, tôi cũng hiểu những hạn chế của DTO với tất cả các mã ánh xạ bổ sung, các mô hình miền có thể giống hệt 100% với đối tác DTO của chúng, v.v.

API của chúng tôi chủ yếu được tạo để các khách hàng khác có thể sử dụng dữ liệu, tuy nhiên nếu chúng tôi làm đúng, chúng tôi cũng muốn sử dụng nó cho GUI web của riêng mình nếu có thể.

Vấn đề là chúng tôi có thể không muốn tiết lộ tất cả dữ liệu miền cho những người dùng máy khách khác. Phần lớn dữ liệu sẽ chỉ có ý nghĩa trong ứng dụng web của chúng ta. Ngoài ra, chúng tôi có thể không muốn tiết lộ tất cả dữ liệu về một đối tượng trong tất cả các tình huống, đặc biệt là mối quan hệ với các đối tượng khác, v.v. Ví dụ, nếu chúng ta để lộ danh sách một đối tượng cụ thể, chúng ta sẽ không nhất thiết muốn phơi bày toàn bộ hệ thống phân cấp đối tượng; để những đứa trẻ của đối tượng sẽ không bị lộ, nhưng có thể được phát hiện thông qua các liên kết (ghét).

Làm thế nào tôi nên đi giải quyết vấn đề này? Tôi đã suy nghĩ về việc sử dụng Jackson mixins trên các mô hình miền của chúng tôi để kiểm soát dữ liệu nào sẽ được đưa ra theo các kịch bản khác nhau. Hay chúng ta chỉ nên sử dụng DTO theo mọi cách - thậm chí còn đưa ra những hạn chế và tranh cãi của nó?


9
Đừng ngạc nhiên nếu câu hỏi này được đóng lại. Đó là nhiều hơn một câu hỏi dựa trên thảo luận có nghĩa là không có câu trả lời chính xác rõ ràng. Hỏi những người khác nhau và bạn sẽ nhận được một câu trả lời khác nhau.
Ben Thurley

2
Liên kết bài viết đó ( ibm.com/developerworks/community/bloss/barcia/entry/ mẹo ) bị hỏng.
Pinkpanther

7
@pinkpanther Đó là một bài viết tuyệt vời và thật đáng tiếc nó không còn nữa. Đây là phiên bản lưu trữ trên web .
cassiomolin

Câu trả lời:


251

Tại sao bạn nên sử dụng DTO trong API REST

DTO là viết tắt của D ata T ransfer O bject .

Mẫu này được tạo ra với mục đích được xác định rất rõ: chuyển dữ liệu sang giao diện từ xa , giống như các dịch vụ web . Mẫu này rất phù hợp trong API REST và DTO sẽ giúp bạn linh hoạt hơn trong thời gian dài.

Các mô hình đại diện cho miền ứng dụng của bạn và các mô hình đại diện cho dữ liệu được xử lý bởi API của bạn là (hoặc ít nhất nên là) các mối quan tâm khác nhau và nên được tách rời khỏi nhau. Bạn không muốn phá vỡ các ứng dụng khách API của mình khi bạn thêm, xóa hoặc đổi tên một trường khỏi mô hình miền ứng dụng.

Mặc dù lớp dịch vụ của bạn hoạt động trên các mô hình miền / lưu trữ, bộ điều khiển API của bạn sẽ hoạt động trên một bộ mô hình khác. Ví dụ, khi các mô hình miền / mô hình bền vững của bạn phát triển để hỗ trợ các yêu cầu kinh doanh mới, bạn có thể muốn tạo các phiên bản mới của các mô hình API để hỗ trợ các thay đổi này. Bạn cũng có thể muốn loại bỏ các phiên bản API cũ của mình khi các phiên bản mới được phát hành. Và nó hoàn toàn có thể đạt được khi mọi thứ được tách rời.


Chỉ cần đề cập đến một vài lợi ích của việc phơi bày DTO thay vì các mô hình kiên trì:

  • Các mô hình kiên trì tách rời khỏi các mô hình API.

  • DTO có thể được điều chỉnh theo nhu cầu của bạn và chúng rất tuyệt khi chỉ hiển thị một tập các thuộc tính của các thực thể kiên trì của bạn. Bạn sẽ không cần các chú thích như @XmlTransient@JsonIgnoređể tránh việc xê-ri hóa một số thuộc tính.

  • Bằng cách sử dụng DTO, bạn sẽ tránh được các chú thích trong các thực thể kiên trì của mình, nghĩa là các thực thể kiên trì của bạn sẽ không bị đầy những chú thích không liên quan.

  • Bạn sẽ có toàn quyền kiểm soát các thuộc tính bạn đang nhận khi tạo hoặc cập nhật tài nguyên.

  • Nếu bạn đang sử dụng Swagger , bạn có thể sử dụng @ApiModel@ApiModelPropertychú thích để ghi lại các mô hình API của mình mà không làm rối các thực thể kiên trì của bạn.

  • Bạn có thể có các DTO khác nhau cho mỗi phiên bản API của mình.

  • Bạn sẽ linh hoạt hơn khi lập bản đồ các mối quan hệ.

  • Bạn có thể có các DTO khác nhau cho các loại phương tiện khác nhau.

  • DTO của bạn có thể có một danh sách các liên kết cho HATEOAS . Đó là loại điều không nên thêm vào các đối tượng kiên trì. Khi sử dụng Spring HATEOAS , bạn có thể làm cho các lớp DTO của mình mở rộng RepresentationModel(trước đây gọi là ResourceSupport) hoặc bọc chúng EntityModel(trước đây gọi là Resource<T>).

Xử lý mã soạn sẵn

Bạn sẽ không cần ánh xạ các thực thể kiên trì của mình sang DTO và ngược lại bằng tay . Có nhiều khung ánh xạ bạn có thể sử dụng để làm điều đó. Chẳng hạn, hãy xem MapSturation , dựa trên chú thích và hoạt động như một Bộ xử lý chú thích Maven. Nó hoạt động tốt trong cả ứng dụng dựa trên CDI và Spring.

Bạn cũng có thể muốn xem xét Lombok để tạo ra thu khí, setters, equals(), hashcode()toString()phương pháp cho bạn.


Liên quan: Để đặt tên tốt hơn cho các lớp DTO của bạn, hãy tham khảo câu trả lời này .


2
Nếu tôi đã đi theo cách DTO, bạn sẽ ánh xạ tất cả các đối tượng miền thành DTO hay chỉ những đối tượng không giống nhau? Ngoài ra, làm thế nào bạn sẽ giải quyết vấn đề phơi bày dữ liệu dựa trên các kịch bản / bối cảnh khác nhau? Nhiều DTO cho mỗi đối tượng tên miền?
benbjo

6
@benbjo Tùy bạn. Tôi thường chỉ ánh xạ các thực thể phức tạp nhất tới các DTO, các thực thể mà tôi không muốn có tất cả các thuộc tính được phơi bày và các thực thể có nhiều mối quan hệ. Các DTO cho tôi sự linh hoạt để có một danh sách các liên kết sẽ được sử dụng trong HATEOAS. Đó là điều mà tôi sẽ không thêm vào các đối tượng kiên trì của mình.
cassiomolin

2
@molin cảm ơn rất nhiều về thông tin và gợi ý. Tôi chắc chắn sẽ kiểm tra MapSturation. Nhìn thoáng qua có vẻ rất phù hợp với nhu cầu của tôi.
benbjo

6
Kính gửi downvoter, ít nhất bạn có thể giải thích lý do của downvote của bạn?
cassiomolin

8
Ngoài ra còn có một lý do kiến ​​trúc để sử dụng DTO thay vì các thực thể miền trong API REST. API REST không nên thay đổi để tránh phá vỡ các máy khách hiện có. Nếu bạn sử dụng mô hình miền trực tiếp trong API, bạn tạo khớp nối không mong muốn giữa API và mô hình miền. Theo nguyên tắc thiết kế dịch vụ khớp nối lỏng lẻo, hợp đồng dịch vụ không nên được kết hợp chặt chẽ với logic dịch vụ hoặc chi tiết triển khai.
Paulo Merson

25

Khi API của bạn ở chế độ công khai và bạn phải hỗ trợ nhiều phiên bản, bạn phải sử dụng DTO.

Mặt khác, nếu đó là API riêng tư và bạn kiểm soát cả máy khách và máy chủ, tôi có xu hướng bỏ qua các DTO và hiển thị mô hình miền trực tiếp.


Tôi đồng ý với bạn về phần cuối cùng và tôi thường làm như vậy, nhưng đây là API công khai đầu tiên của tôi. Tôi sẽ xem xét những gì bạn nói về việc sử dụng DTO cho phần công khai. Có lẽ các phần riêng tư và công khai của API thực sự nên tách biệt, ngay cả khi "ăn thức ăn cho chó của riêng bạn" là một nguyên tắc tốt.
benbjo

11

Tôi có xu hướng sử dụng DTOs.

Tôi không thích những nhược điểm nhưng dường như các tùy chọn khác thậm chí còn tồi tệ hơn:

Việc tiếp xúc với các đối tượng miền có thể dẫn đến các vấn đề bảo mật và rò rỉ dữ liệu. Chú thích của Jackson dường như có thể giải quyết vấn đề nhưng quá dễ để mắc lỗi và phơi bày dữ liệu không nên bị lộ. Khi thiết kế một lớp DTO, việc mắc một lỗi như vậy sẽ khó hơn nhiều.

Mặt khác, những hạn chế của cách tiếp cận DTO có thể được giảm bớt bằng những thứ như ánh xạ đối tượng sang ánh xạ đối tượng và Lombok để ít bị lu mờ hơn.


9

Như bạn đã nêu, đây rõ ràng là một câu hỏi liên quan đến ý kiến. Bản thân tôi bị cuốn hút hơn với cách tiếp cận No-DTOs, đơn giản là vì tất cả các mã soạn sẵn mà bạn cần.

Điều này chủ yếu đúng cho phía phản hồi của api json / rest. Tôi thậm chí đã viết một addon jackson để tránh viết nhiều lượt xem / bộ lọc json cho những trường hợp này: https://github.com/Antibrumm/jackson-antpathfilter

Mặt khác, các DTO là một điều tốt ở phía đầu vào yêu cầu của các API đó. Làm việc trực tiếp trên các thực thể có thể khá khó khăn khi tính đến các mối quan hệ hai chiều chẳng hạn. Ngoài ra, bạn không thực sự muốn để người gọi sửa đổi thuộc tính "người tạo" chẳng hạn. Vì vậy, bạn sẽ cần phải không cho phép các trường nhất định trong quá trình ánh xạ các yêu cầu đó.


2
Tôi đồng ý rằng câu hỏi của tôi có phần liên quan đến ý kiến ​​(và không được khuyến khích), tuy nhiên tôi cũng đang tìm kiếm lời khuyên về cách giải quyết vấn đề của mình. Tôi sẽ mất rất nhiều tại addon Jackson của bạn, tuy nhiên bạn có nghĩ rằng việc sử dụng mixins để kiểm soát dữ liệu nào nên được phơi bày trong các bối cảnh khác nhau là điều tốt để làm gì không?
benbjo
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.