web-dev-qa-db-ja.com

APIとアプリケーションの間でオブジェクトを共有するためのパターン

私のWebアプリケーションの設計について深刻な疑いがあります。

ビジネスロジックをインターフェイスから分離したかったので、データベースへのすべての要求を処理するWeb APIを作成しました。

これは、エンティティフレームワークと作業ユニットおよび一般的なリポジトリパターンを備えたASP.NET Web APIです。これまでのところ、すべてが良好です。

[〜#〜]問題[〜#〜]

助けが必要なのは、APIとアプリケーションの間でオブジェクトを共有する効率的な方法を理解できないことです。

エンティティオブジェクトを直接シリアル化したくありません。エンティティモデルが変更された場合、理由もなく大きなオブジェクトがシリアル化される可能性があるため、これは悪い習慣だと思いました。

現在の実装方法

インターフェイスはC#のASP.NET Webアプリケーションであり、APIはC#であるため、共有するすべてのクラスの定義を含む共通ライブラリを作成しました。

Android=アプリを開発するとき、ソリューションが機能しないことを知っています。Javaでクラスを再度作成する必要がありますが、それは私の最大の問題ではありません。

問題は、常にオブジェクトを変換しているような気がすることです。

[〜#〜]例[〜#〜]

これが私のワークフローの例です:

すべてのオブジェクトとフォームのデータ注釈を含むモデルから始め、ユーザーはそのモデルをコントローラーにPOSTします。

コントローラでは、このモデルを共通ライブラリのクラスに変換してから、そのオブジェクトをAPIに送信する必要があります。

次に、私のAPIのコントローラーが呼び出しをキャッチし、そのオブジェクトをエンティティオブジェクトに変換して、データベースを更新します。

だから私は3つのクラスを持っています

  1. 検証用のすべてのデータ注釈を含むビューのモデル(クライアント)
  2. オブジェクトを共有するための共通ライブラリクラス(DLL)
  3. エンティティークラス(API)

何か間違ったことをしているような気がします。よりエレガントなものはありますか?プロジェクトが大きくなりすぎる前に、この問題に対する適切な解決策があることを確認したいと思います。

9
Marc

データベースオブジェクト、データ転送オブジェクト、検証ロジックを備えたクライアントオブジェクトなどの間でオブジェクトを常に前後に変換しているように見えるかもしれませんが、いいえ、あなたは何も間違っていません。

これらの各オブジェクトは同じ情報単位を表す場合がありますが、それらの責任は大きく異なります。データベースオブジェクトは、データベースとの通信インターフェースであり、データベースメタデータアノテーションやデータベース実装に関する不要な詳細が含まれている場合とそうでない場合があるため、データベースレイヤーに保持する必要があります。

データ転送オブジェクトは、APIコンシューマーとの通信インターフェースです。さまざまな言語/プラットフォームから簡単に利用できるように、これらはできるだけクリーンである必要があります。これにより、サポートするAPIコンシューマーに応じて、これらの外観と動作に特定の制限が課される場合があります。

検証ロジックを持つクライアントオブジェクトは、実際にはAPIプロジェクトの一部ではなく、コンシューマープロジェクトの一部です。これらは、サーバーが何も知らない(そして何も知らないはずの)クライアント固有のロジック(この場合は検証属性)を追加するため、この場合のデータ転送オブジェクトと同じにすることはできません。これらのオブジェクトは実際にはないため、APIの一部としてカウントします。これらは非常にコンシューマーアプリケーションに固有であり、APIを使用する一部のアプリケーションは実際にはこれらのオブジェクトを作成する必要すらなく、データ転送オブジェクトだけで存続することもできます。たとえば、検証の必要がない場合は、データ転送オブジェクトと完全に同一のオブジェクトの追加レイヤーは必要ありません。一般に、ここでの私の戦略は、プロジェクトを段階的に進化させることです。まず、データ転送オブジェクトをコンシューマーアプリケーションオブジェクトとして使用し、アプリケーション固有のデータ処理(検証、INotifyPropertyChangedの実装など)が必要になったときに開始します。迅速なリファクタリングを行い、必要に応じて新しいレイヤーを追加します。

私には、3つのオブジェクトタイプのそれぞれが、明確なコーディングと優れた実践である単一の責任に非常にうまく対応しているようです。悲しいことに、クリーンなコードと優れたプラクティスは、多くの追加のコードを作成し、「単に」という理由で追加のフープを飛び越えていることを意味します。そしてコーディング中、これがあなたに与える価値を理解するのは難しいかもしれません-しかし、あなたがアプリケーションをリリースしてそれをサポートし始めるか、次のバージョンのために新しい機能を追加するやいなや、あなたはおそらく時間をかけたことに感謝し始めるでしょうそもそもこれらの懸念を適切に分離してください。 (言うまでもなく、懸念の分離が不適切なために発生する可能性のある特定の問題を回避します。これらの問題を回避したため、懸念を解消しなかった場合の混乱を理解するのは難しいかもしれません。 )

このような異なるオブジェクトタイプ間の変換コードを書くのも嫌いですが、私の解決策は通常、次のいずれかです。

  • オブジェクト変換の大部分を行うライブラリを使用してください。たとえば、C#を使用している場合は、素晴らしいAutoMapperライブラリ( http://automapper.org/ )を使用できます。このようなライブラリは他にもいくつかあると思いますが、AutoMapperはこれまでに見た中で最も強力なライブラリです。
  • オブジェクトの変換に役立つライブラリが見つからない場合は、それらの間で変換するためのユーティリティメソッドのセットを記述します。これは面倒かもしれませんが、長い目で見ればそれだけの価値があります。何かを初めて変換する必要があるときに変換メソッドを記述してください-待ってはいけません。
12
wasatz