私の限られた経験では、エンティティをフロントエンドやREST経由で渡すのではなく、DTOを使用するように繰り返し言われています。
Spring Data Restはこれを正確に行いませんか?プロジェクションを簡単に調べましたが、これらは返されるデータを制限するだけで、データベースに保存するpostメソッドへのパラメーターとしてエンティティーを期待しています。ここに何か欠けているのでしょうか、それとも私(および私の同僚)は、あなたの周りに存在してはならず、実体化してはいけないという点で間違っていますか?
いいえ。DTOは、HTTPリソースで公開されている表現からサーバー側ドメインモデルを分離するための1つの手段にすぎません。また、Spring Data RESTが行うような、他の分離手段を使用することもできます。
はい。SpringData RESTは、サーバー側にあるドメインモデルを検査して、公開するリソースの表現がどのように見えるかを推論します。ただし、ドメインオブジェクトの単純な公開がもたらす問題を軽減するいくつかの重要な概念が適用されます。
素朴な「ドメインオブジェクトをジャクソンの前に投げる」の根本的な問題は、プレーンエンティティモデルから、合理的な表現の境界を推測するのが非常に難しいことです。特に、データベーステーブルから派生したエンティティモデルは、事実上すべてのものをすべてのものに接続する傾向があります。これは、集計のような重要なドメインの概念がほとんどの永続化テクノロジに存在しないという事実に由来します(特にリレーショナルデータベースを参照)。
ただし、この場合、「ドメインモデルを公開しない」のほうが、問題の核心よりもその症状に対応していると私は主張します。ドメインモデルを適切に設計すると、ドメインモデルのメリットと、状態の変化を通じてそのモデルを効果的に駆動するための適切な表現との間に大きなオーバーラップがあります。いくつかの簡単なルール:
Spring Data RESTは、これらのエンティティの関係をHTTPレベルの適切なメカニズムに実際に転送するためにかなりの数の処理を実行します。リンク一般、さらに重要なのは、これらの関係を管理する専用リソースへのリンクです。これは、エンティティーに対して宣言されたリポジトリーを検査することによって行われ、基本的に、関連するエンティティーのその他の必要なインライン化を、その関係を明示的に管理できる関連付けリソースへのリンクに置き換えます。
このアプローチは、通常、HTTPレベルでDDDアグリゲートによって記述される一貫性保証とうまく機能します。 PUT
リクエストは、デフォルトでは複数のアグリゲートにまたがることはありません。これは、ドメインの概念と一致するリソースの整合性の範囲を意味するため、これは良いことです。
ドメインオブジェクトのDTOはいくつでも導入できます。ほとんどの場合、ドメインオブジェクトにキャプチャされたフィールドは、何らかの形で表現に反映されます。エンティティCustomer
にfirstname
、lastname
、およびemailAddress
プロパティが含まれており、それらが表現と完全に無関係であることはまだわかりません。
DTOの導入は、決して分離を保証するものではありません。貨物養殖の理由で導入されたプロジェクトが多すぎて、それらを支えるエンティティのすべてのフィールドを複製しただけで、新しいフィールドもすべてDTOに追加する必要があったため、追加の作業が発生しただけです。しかし、ちょっと、デカップリング!ない。 ¯\ _(ツ)_ /¯
そうは言っても、特に強く型付けされた値オブジェクトを使用する場合など、これらのプロパティの表現を少し微調整したい場合もあります。 EmailAddress
(良い!)でも、これをJSONでプレーンなString
としてレンダリングしたい。しかし、それが問題であることは決してありません。SpringData RESTは、さまざまな方法で表現を微調整する手段を提供するJacksonを使用しています—アノテーション、ミックスイン、ドメインタイプの外部にアノテーションを保持するためのカスタムシリアライザなどの間にマッピング層があります。
デフォルトでDTOを使用しないこと自体は悪いことではありません。すべてに対してDTOを作成する必要がある場合に必要なボイラープレートの量について、ユーザーからの抗議を想像してみてください。 DTOは単にoneで終わりを意味します。その目的を別の方法で達成できる場合(通常は可能です)、なぜDTOを主張するのでしょうか。
カスタマイズの作業を続けると、APIの基本的なREST API実装パターンに従うAPIの部分を正確にカバーするためにSpring Data RESTが存在することに注目する価値があります。そしてその機能は、考える時間を増やすために用意されています。
これは、SpringOne Platform 2016で行った講演のスライドで、状況をまとめたものです。
完全なスライドデッキが見つかります ここ 。 InfoQでは トークの録音 も利用できます。
Spring Data RESTは、下線の付いた円に集中できるようにするためのものです。 Spring Data RESTをオンにするだけで、すばらしい本当にAPIを構築できるとは決して考えていません。おもしろいことを考える時間を増やすために、ボイラープレートの量を減らしたいだけです。
Spring Dataと同様に、一般に、標準の永続化操作用に作成するボイラープレートコードの量を削減します。実際にCRUD操作だけで実際のアプリを構築できると主張する人は誰もいません。しかし、退屈な部分から努力を取り除いて、実際のドメインの課題についてより集中的に考えることができます(そして、実際にそれを行う必要があります:))。
必要に応じてドメインタイプをDTOに手動でマッピングするなど、特定のリソースをオーバーライドしてその動作を完全に制御することもできます。また、Spring Data RESTが提供する機能の横にカスタム機能を配置して、2つをフックすることもできます。何を使用するかを慎重に選択してください。
RESTful Webサービスの本にあるRESTBucksサンプルのSpring(データREST)ベースの実装である Spring RESTBucks で説明したものの少し高度な例を見つけることができます。 Spring Data RESTを使用してOrder
インスタンスを管理しますが、その処理を微調整してカスタム要件を導入し、ストーリーの支払い部分を手動で完全に実装します。
Spring Data RESTを使用すると、データベース構造に基づいてプロトタイプを作成し、REST APIを作成する非常に高速な方法が可能になります。他のプログラミング技術と。
その代償として、REST APIがデータベース構造に密接に結合されています。それが大きな問題である場合もあります。そうでない場合もあります。基本的にはデータベース設計の品質に依存しますAPIユーザーのニーズに合わせて変更する機能。
要するに、Spring Data RESTは、特定の特別な状況下で多くの時間を節約できるツールであり、あらゆる問題に適用できる特効薬ではありません。
以前は、プロジェクト内のすべてのエンティティに完全に従来のレイヤー(データベース、DTO、リポジトリ、サービス、コントローラーなど)を含むDTOを使用していました。 DTOがいつか私たちの命を救うことを願っています:)
したがって、_id,name,country,state
_を含む単純なCity
エンティティの場合、次のようにしました。
City
テーブル、_id,name,county,....
_列CityDTO
with _id,name,county,....
_プロパティ(データベースとまったく同じ)CityRepository
とfindCity(id),....
CityService
with findCity(id) { CityRepository.findCity(id) }
CityController
with findCity(id) { ConvertToJson( CityService.findCity(id)) }
都市情報をクライアントに公開するだけの定型コードが多すぎます。これは単純なエンティティであるため、これらのレイヤーに沿ってビジネスは行われず、オブジェクトが通過するだけです。 City
エンティティの変更はデータベースから始まり、すべてのレイヤーが変更されました。 (たとえば、最後にlocation
プロパティをlocation
としてユーザーに公開する必要があるため、json
プロパティを追加します)。 findByNameAndCountryAllIgnoringCase
メソッドを追加するには、すべてのレイヤーを変更する必要があります(各レイヤーには新しいメソッドが必要です)。
Spring Data Rest(_of course with Spring Data
_)を考えると、これは簡単ではありません!
_public interface CityRepository extends CRUDRepository<City, Long> {
City findByNameAndCountryAllIgnoringCase(String name, String country);
}
_
city
エンティティは、最小限のコードでクライアントに公開されますが、都市の公開方法を制御できます。 Validation
、Security
、_Object Mapping
_ ...そこにすべてあります。だからあなたはすべてのものを微調整することができます。
たとえば、city
エンティティプロパティ名の変更(レイヤー分離)をクライアントに知らせないようにしたい場合は、言及したカスタムオブジェクトマッパーを使用できます https://docs.spring.io/spring- data/rest/docs/3.0.2.RELEASE/reference/html /#customizing-sdr.custom-jackson-deserialization
要約するには
可能な限りSpring Data Restを使用します。複雑なユースケースでも、従来の階層化を行って、Service
とController
にビジネスを任せることができます。