プロジェクトで多数のhttp-requestを処理するときに、独自のAngular.js webApiモジュールを開発したいという要望が生じました。
定数を使用してファイルを作成するだけでなく、特定のモジュールを開発して既存の機能のサポートを簡素化することも重要でした。 次に、現在のモジュールコアの整合性を損なうことなく、その後の拡張の可能性に注意する必要がありました。
将来のwebApiモジュールが解決すべきタスク:
- プロジェクト内のhttpリクエストの重複を防ぎます。
- 特定のメソッドを編集しやすくするために、既存のクエリリストを機能カテゴリにグループ化します。
- 単純な依存性注入を使用して、他のAngular.jsプロジェクトに接続するアプリケーションの完全に独立した機能単位になること。
- 外部ソースを操作する際の問題を回避するために、内部実装をカプセル化します。
デモ
モジュールのソースコードを表示: github 。
重複したhttpリクエスト
これは、アプリケーションの複数の場所(コントローラー、サービス、工場)で1つの要求を使用することです。 メソッドが10〜20の場合、各リクエストに変更を加えることは大きな問題にはなりません。 しかし、100、200、またはそれ以上のURLの数になると、そのようなコードのサポートはますます困難になります。
例1
ユーザーグループのリストを取得するメソッドがあります。 対応するドロップダウンに表示されるとします。 グループが選択されると、そのユーザーは別の要求によってロードされ、グループIDが転送されます。 また、ページには、一部のユーザーデータを視覚化するための追加機能があります。
// $http.get("api/group-manage/get-all") // $http.get("api/group-manage/2/get-users")
別のコントローラーには、特定のグループのシステムのすべてのユーザーを表示する必要があるテーブルがあります。 このページには、分析とユーザー管理のための非常に多くのオプションがあります。
// $http.get("api/group-manage/2/get-users")
実際には、はるかに類似したクエリが存在する可能性があります。
問題解決
, http- , .. url'.
このアプローチにより、プロジェクトで必要な要求とその変更を検索する際の時間が節約されます。
繰り返しますが、そのようなファイルの操作は、サーバーへのリクエストが少数の場合にのみ機能します。 200を超える定数を持つファイルの便利なサポートを想像することは困難です。
カテゴリ別にクエリをグループ化する
このアプローチは、上記の問題を解決します。 独立したカテゴリの決定がどの程度正確に行われるかは、開発者自身が決定します。 簡単にするために、 api
からコントローラーメソッドの名前に焦点を当てることができます。
// http://yourapi.com/api/group-manage/2/get-users // http://yourapi.com/api/group-manage/get-all
上記の例は、リクエストに共通のルート/api/group-manage/
があることを示しています。 groupManage.js
対応する名前のカテゴリを作成します。
Angular.js環境では、このファイルはconstantとして宣言され、その後、メインのwebApiモジュール機能に接続されます。
プロジェクトには、このようなグループが複数存在する場合があります。 しかし、グループ管理に関連するクエリを探す場所は間違いなくわかっています。
追加したURLを直接呼び出すと、遅かれ早かれ同じタイプの一連の依存関係がコードに表示されます。 したがって、webApiの「 コア 」でそれらを操作するためのすべての既存の要求のリストを提供する共通ブロックを作成する必要があります。
機能的カプセル化
最も困難なタスクの1つは、すべてのサーバーリクエストを処理できるカーネルを開発することでした。その一方で、内部実装を開示するだけでなく、特定のAngular.jsアプリケーション用にwebApiモジュールを簡単に構成する機能も提供しました。
リクエストの例は次のとおりです。
{ Url: '/api/acc/login', CustomOptions: false, Method: 'post', InvokeName: 'login' }
- customOptions-追加のリクエスト設定を使用するかどうか。 通常、特定の要求のヘッダー、タイムアウト値、withCredentialsパラメーターなどをそこに示すことができます。
このアプローチにより、共通のタイプごとに複数のURLをグループ化するだけでなく、各メソッドがデータをどのように処理するかを把握できます。
webApi/config/
ディレクトリwebApi/config/
、API設定をwebApi/config/
ファイルがwebApi/config/
ます。 ドメインURLを指定するのはそこです。
例2
ほとんどすべての最新のAngular.jsアプリケーションは認証システムで動作します。 通常、これはユーザーデータ(ログイン、パスワード)をサーバーに送信するポストメソッドです。
応答が成功すると、メインアプリケーションルートに通知が送信され、その後、ユーザーは機能を備えたページにリダイレクトされます。
メソッドを呼び出します:
webApi.login({ "Login": "user", "Password": "qwerty" }).success(function(response, status, headers, config){ // - })
したがって、特別なレベルの抽象化で作業するため、アプリケーションロジックの構築プロセスに集中できます。 特定の呼び出しが何を行うかを理解できるように、メソッドに適切な名前を付けることをお勧めします。
// { Url: '/api/acc/logout', CustomOptions: false, Method: 'get', InvokeName: 'logout' } // - webApi.logout([]);
おそらく、getメソッドで空の配列を使用することは今のところ完全に明確ではありませんが、その後、誰もがこれについて後で説明されます。
クエリテンプレート
多くの場合、アプリケーションの開発時に、サーバー側は次のリクエスト形式をクライアントに提供します。
- / API /管理者/削除/プロファイル/ {id}
- / api / admin / update / profile / {id} /ブロック
そのため、アプリケーションの適切な場所にあるサーバーにリクエストを送信する際に、そのようなURLの作成で不必要な操作を行わないように、受信したパラメーターに基づいて正しいアドレスを自動的に生成する特別なコンポーネントが開発されました。
// { Url: '/api/admin/update/profile/{id}/block', CustomOptions: false, Method: 'put', InvokeName: 'blockAdminProfileById' } // - webApi.blockAdminProfileById({ "url": { "id": 5 } });
生成されたリクエスト: /api/admin/update/profile/5/block
(もちろんドメインURLも)。
そして、より複雑なリクエストをサーバーに送信する必要がある場合(たとえば、ブロック期間とタイプ)、残りのパラメーターを「url」オブジェクトのフィールドとして指定するだけです。
// { Url: '/api/admin/update/profile/{id}/block/{type}/{time}', CustomOptions: false, Method: 'put', InvokeName: 'blockAdminProfileById' } // - webApi.blockAdminProfileById({ "url": { "id": 5, "type": "week", "time": 2 } });
生成されたリクエスト: /api/admin/update/profile/5/block/week/2
そして今、ユーザーはシステムによって2週間ブロックされます。
パターン化は、getを含むすべてのタイプのクエリで機能します。 この方法ですべてのリクエストを作成することをお勧めします。時間を節約し、不必要な操作で内部コードを詰まらせないでください。
リクエスト本文のデータを転送する
テンプレートURLに加えてサーバーに他のデータ(たとえば、ポストリクエスト)を送信する場合は、次のように転送する必要があることに注意してください。
webApi.createPost({ "data": { "title": "Test post", "category": "sport", "message": "Content..." } });
当然、URLテンプレートとデータを含むオブジェクトの受け渡しの両方を同時に使用できます。 後者は、リクエスト本文でサーバーに送信されます。
GETメソッドを使用する
ここでは、リクエスト本体でデータは送信されませんが、getリクエストは次のように形成できることを誰もが知っています。
api/admin/news/10?category=sport&period=week
または:
api/admin/manage/get-statistic/5/2016
または:
api/admin/manage/get-all
。
各生成オプションを検討してください。
// Case #1 -> api/admin/manage/get-all // -> "Url" : 'api/admin/manage/get-all', ... // webApi.getAllAdmins([]).success(//...) // Case #2 -> api/admin/manage/get-statistic/5/2016 // -> "Url" : 'api/admin/manage/get-statistic/{id}/{year}', ... // webApi.getAdminStatsticById({ "url": { "id": 5, "year": 2016 } }).success(//...) // Case #3 -> admin/news/10?category=sport&period=week // -> "Url" : 'admin/news', ... // webApi.getNews({ before: ['10'], after: { "category": "sport", "period": "week" } }).success(//...)
上記の2番目のタイプのクエリはすでに処理しました。
最初のケースでは、サーバーにリクエストを送信する必要がある場合、常に空のコレクションを渡します。
ケース#3の場合、 beforeフィールドは、 「?」の前にあるいくつかのパラメーターを定義します また、 afterフィールドはキーと値のセットです。 当然、場合によっては、空のコレクションの前に残すことができます[]。
設定のCustomOptionsパラメーター
URLテンプレートなしでリクエストを取得:
webApi.getNewsById([10, {"headers": {"Content-Type": "text/plain"} } ]);
その他のすべての場合(URLテンプレートを使用したget要求を含む):
webApi.login({ options: {"timeout": 100, {"headers": {"Content-Type": "text/plain"} } });
新しいプロジェクトでwebApiを設定する
モジュールの構造は次のとおりです。
- module.jsファイル-モジュール自体の宣言。
- ディレクトリmain /-webApiのコアが含まれ、変更されません。
- カテゴリディレクトリ-リクエストグループ、1つのグループ-1つの* .jsファイル。
- Categories-handlerディレクトリ-webApiモジュールのすべてのリクエストのロガー。
最後の2つのディレクトリで作業する必要があります。
例3
ある大学で書籍会計システムが開発されているとしましょう。 要求を次のグループに分割する可能性が高い:
- account.js-認証、認証解除、パスワード回復などのリクエスト。
- bookManage.js-ブックを使用したCRUD操作のリクエスト。
- studentManage.js-学生管理。
- adminManage.js-アプリケーションの管理部分を管理するための一連のリクエスト。
もちろん、このリストは拡張できます。
- , .
(function(){ angular .module("_webApi_") .constant("cat.account", { "DATA": [ { Url: '/api/acc/login', CustomOptions: false, Method: 'post', InvokeName: 'login' }, // ] }); })();
要求ファイルが作成されました。 次に、それをwebApiコアに関連付ける必要があります。
(function(){ angular .module("_webApi_") .service("webApi.requests", webApiRequests); function webApiRequests(catAccount){ // // , } // IoC container. webApiRequests.$inject = [ "cat.account" ]; })();
この場合、すべての定数は「 cat.constants name 」を介して書き込まれ、「 catNameConstants 」 ロガーに接続されます。
したがって、webApiは追加のネームスペース「 cat。 」を使用するため、アプリケーション内の他の定数と競合することはありません。
次に、説明したテンプレートに従ってメソッドを呼び出します。
webApi.login( //- )
リポジトリを操作する
webApiの機能をアプリケーションの内部コードに公開しないために、追加の「リポジトリ」抽象化を使用することが決定されました。
, , http-. -webApi , .
特定の「 FoodController 」と対応するfoodManageリクエストグループがあるとします。 このカテゴリの各メソッドは、サーバー上のデータ管理の特定の実装を担当します。
リポジトリを宣言します:
(function() { "use strict"; angular .module("app.repositories") .factory("repository.food", foodRepository); function foodRepository(webApi){ return { get: getById getAll: getAll, remove: removeById, removeAll: removeAll } // , function getById(id){ return webApi.getFoodItemById({ "url": { "id": id } }); } function getAll(){ return webApi.getAllFoodItems([]); } // } // IoC container. foodRepository.$inject = [ "webApi" ]; })();
したがって、webApiの機能を公開せずに、コントローラーからのデータを管理するための抽象化ファクトリーを作成しました。 そして、いつでも現在の実装を他のものに置き換えることができます。
たとえば、アイテムに関する情報を受信する場合、「野菜」、「果物」、「牛乳」などのタイプを指定する必要があります。 特別なレベルの抽象化が存在するため、メソッドに次の変更を加えるだけで十分です。
function getById(id, category) { return webApi.getFoodItemById({ "url": { "id": id, "category": category } }); }
リポジトリをアプリケーションに接続する
前述のように、リポジトリは、webApiモジュールへの内部呼び出しを通じてデータを管理するためのパブリックメソッドを提供するエンティティです。
したがって、特定のメソッドを呼び出して適切なパラメーターを渡すだけで十分です。
(function() { "use strict"; angular .module("app") .controller("FoodController", FoodController); function FoodController(foodRepository){ /* jshint validthis:true */ var vm = this; // , vm.foodItems = []; vm.getAllFood = function(){ foodRepository.getAll().success(function(response){ vm.foodItems = response.data; }); }; // vm.getAllFood(); } // IoC container. FoodController.$inject = [ "repositories.food" ]; })();
データ視覚化のためのHTMLスニペット:
<div ng-controller="FoodController as fc"> <ul> <li ng-repeat="food in fc.foodItems track by food.Id"> Title: <span class="item-title"> {{food.title}} </span> Cost: <span class="item-cost"> {{food.cost}} </span> </li> </ul> </div>
したがって、リポジトリはデータを返し、Angular.jsはそれらを自動的にビューに置き換えます。 また、中央のコントローラーと調整せずにそこにあるアイテムを削除したり追加したりして、webApiに直接アクセスすることはできません。
, .
おわりに
Angular.jsを操作するための、構成可能で拡張可能なwebApiモジュールを作成するオプションを検討しました。
このアプローチは、コード内のロジックの重複を取り除き、必要なメソッドの編集にかかる時間を短縮し、複雑なクエリでの作業を容易にするのに役立ちます。