私は現在プロジェクト用のREST-APIを作成していて、ベストプラクティスに関する記事ごとに記事を読んでいます。多くはDTOに反対しているだけで、単にドメインモデルを公開しているだけですが、他の人はDTO(あるいはユーザーモデルあるいはあなたがそれを呼びたいものは何でも)を悪い習慣と考えているようです。個人的には、 この記事の は多くの意味があると思いました。
しかし、私はまた、すべての追加のマッピングコード、DTOと同等のドメインモデルなど、DTOの欠点も理解しています。
私たちのAPIはほとんど他のクライアントがデータを消費することができるように作成されています。
問題は、すべてのドメインデータを他のクライアントユーザーに公開したくないということです。データの多くは、私たち自身のWebアプリケーションでしか意味がありません。また、すべてのシナリオで、オブジェクトに関するすべてのデータ、特に他のオブジェクトとの関係などを公開したくない場合もあります。たとえば、特定のオブジェクトのリストを公開する場合、必ずしもオブジェクト階層全体を公開する必要はありません。そのため、オブジェクトの子は公開されませんが、リンク(hateoas)を通じて発見できます。
この問題を解決するにはどうすればいいですか。私は私たちのドメインモデルでJacksonミックスインを使用して、さまざまなシナリオで公開されるデータを制御することを考えていました。それとも、その欠点や論争を考慮しても、DTOをずっと使用するだけでよいのでしょうか。
DTOは、 D ata T transferの略です。 O bject 。
このパターンは、明確に定義された目的で作成されました。remote interfacesにデータを転送する、web servicesと同じです。 。このパターンはREST APIに非常によく適合し、DTOは長期的にはより多くの柔軟性を与えるでしょう。
RESTリソースの表現は、永続モデルと同じ属性を持つ必要はありません。属性を省略、追加、または名前変更する必要があるかもしれません。
持続モデルの代わりにDTOを公開することのいくつかの利点について言及するだけです。
あなたのAPIモデルからあなたの永続モデルを分離する。
DTOは、ニーズに合わせてtailoredにすることができ、永続エンティティの一連の属性のみを公開する場合に最適です。一部の属性の直列化を避けるために、 @XmlTransient
や @JsonIgnore
のようなアノテーションは必要ありません。
DTOを使用することで、永続エンティティ内の地獄の注釈を避けることができます。つまり、永続エンティティが非永続関連の注釈で肥大化することはありません。
リソースを作成または更新するときに受け取る属性をフルコントロールにします。
Swagger を使用している場合は、永続エンティティを乱すことなくAPIモデルを文書化するために @ApiModel
および @ApiModelProperty
アノテーションを使用できます。
APIのバージョンごとに異なるDTOを設定できます。
関係をマッピングするときには、もっと柔軟性があります。
メディアタイプごとに異なるDTOを設定できます。
あなたのDTOは HATEOAS へのリンクのリストを持つことができます。これは永続オブジェクトに追加してはいけないことの一種です。
あなたの永続化エンティティをDTOにマッピングする必要はなく、またその逆も同様です。mannually多くのマッピングフレームワーク あなたはそれをするために使うことができます。たとえば、 MapStruct をご覧ください。これはアノテーションベースで、Maven Annotation Processorとして機能します。 CDIとSpringベースのアプリケーションの両方でうまく機能します。
ゲッター、セッター、equals()
、hashcode()
およびtoString()
メソッドを生成するために Lombok を検討することをお勧めします。
関連:あなたのDTOクラスにもっと良い名前をつけるには、これを参照してください answer 。
APIが公開されていて複数のバージョンをサポートする必要がある場合は、DTOを使用する必要があります。
一方、プライベートAPIで、クライアントとサーバーの両方を制御している場合は、DTOをスキップしてドメインモデルを直接公開する傾向があります。
私はDTOを使う傾向があります。
私は欠点が好きではありませんが、他の選択肢はさらに悪いようです。
ドメインオブジェクトを公開すると、セキュリティ上の問題やデータの漏えいが発生する可能性があります。ジャクソンの注釈は問題を解決するように思われるかもしれませんが、間違えて公開されるべきでないデータを公開するのはあまりにも簡単です。 DTOクラスを設計するときは、このような間違いを犯すのははるかに困難です。
反対に、DTOアプローチの欠点は、オブジェクトからオブジェクトへのマッピングや、ボイラープレートを少なくするための Lombok などの方法で軽減できます。
あなたがすでにあなた自身を述べたように、これは明らかに意見関連の質問です。私は自分が必要としているすべての定型コードのせいで、DTOなしのアプローチにもっと惹かれています。
これは主にjson/rest apiの応答側に当てはまります。私はこれらの場合のために多くのjsonビュー/フィルタを書かないようにするためにjacksonアドオンさえ書きました: https://github.com/Antibrumm/jackson-antpathfilter
一方、DTOはそのようなAPIのリクエスト入力側には良いことです。エンティティに直接作業することは、例えば双方向の関係を考慮に入れるとかなり難しいことがあります。また、呼び出し側に「作成者」属性などを変更させたくない場合もあります。そのため、そのような要求のマッピング中は特定のフィールドを許可しないようにする必要があります。