Part8: HTTP

海未「では、一応今回で一区切りになるはずですが、サーバとHTTP通信を行うことでより実際のアプリケーションに近付けてみましょう」
穂乃果「サーバ・・・なんてあったっけ?」
ことり「Node.jsとかで作るのかな?」
海未「そこまでやるのもいいのですが、AngularにはWebAPIをシミュレートする仕組みも用意されていますから、それを使ってサーバに代えることにします」


海未「最初に必要なのは、関連するモジュール類を読み込むことです。app.module.tsHttpModuleInMemoryWebApiModule、これから実装するInMemoryDataServiceを読み込みます」

海未「InMemoryWebApiModuleが提供するAPIはWebAPIと同様のインターフェイスを持ち同様の振る舞いをしますが、実体はリモートサーバ上ではなくメモリ内にあります」
ことり「それにサーバの代わりをしてもらうんだね」
海未「そうです。そして、WebAPIの背後にはデータを保持するデータベースに相当するものも必要ですから、それを実装しましょう。in-memory-data.service.tsを作成してください」

穂乃果「どっかで見たね」
ことり「mock-idols.tsかな」
海未「その通りです。あのファイルで定義していたデータをこちらに移した格好ですが、InMemoryDbServiceを実装することでInMemoryWebApiModuleのバックエンドとして扱えるようになります」
ことり「じゃあ、mock-idols.tsはもう使わないの?」
海未「はい。削除してしまいましょう」


海未「これでサーバの準備はできました。では、クライアントコードに進みましょう」
穂乃果「今までって、データはmock-idols.tsから取ってたから、一瞬で処理が終わるPromiseがあっただけだったよね」

穂乃果「こんなの」
海未「はい。今回も、実際にリモートサーバと通信するわけではありませんから、処理は一瞬で終わりますが・・・コードは少し複雑になりますね。idol.service.tsの抜粋です」

海未「Angularの提供するHttpを用いて通信するわけですが、これはObservableという型のデータを返してきます。ただ、toPromisePromiseに変換できますから、後はこれまで見たように扱えます」
ことり「ええと、Promiseの処理が終わったらthenに渡した処理が実行されて・・・このresponseIdol型じゃないんだよね?」
海未「はい。AngularのHTTP通信ではTypeScriptのオブジェクトはJSON形式でやりとりされますから、response.json().dataという書き方でHTTPレスポンスをTypeScriptのオブジェクトに変換する必要がありますね」
穂乃果「その後のcatchって、例外処理で出てきたcatchと同じような意味?」
海未「そうです。この一連の処理でエラーが発生すると、catchに渡した処理が実行されます」

海未「IdolServiceにはもうひとつ、指定したIDのアイドルを取得するgetIdolがありました。こちらもHTTP通信を行うように修正してみましょう」

海未「さきほどとあまり変わらないように見えますが、リクエストするURLに${id}が付加されています。api/idols/11のように展開されますから、一般的なRESTの規約に従ってID11のオブジェクトを返すようになります」
ことり「あとは一緒だね」


海未「では次に、アイドルの編集機能を見てみましょう。これまで、画面上で名前を変えることはできましたがそれを保存することはできませんでした」
穂乃果「ページ遷移すると元に戻っちゃうんだよね」
海未「それをサーバ側に保存できるようにしてみましょう。InMemoryWebApiModuleはデータの更新もサポートしています」

海未「まずは、idol-detail.component.htmlの一番下に保存ボタンを置きましょう」

海未「idol-detail.component.tsIdolDetailComponentにメソッドを追加します。updateはこの後実装しますから、エディタが何か言っても今は気にしないでください」

ことり「保存したら前へ・・・一覧かダッシュボードへ戻る動きだね」

海未「ではIdolServiceupdateを実装しましょう」

海未「さきほどまでのデータ取得系と違って、データを送信する必要がありますね。まず、データ形式がJSONであることを伝えるHTTPヘッダを用意します」
穂乃果「1行目だね」
海未「あとは、getIdolのときと同じURLにPUTメソッドでリクエストを送ります。このとき、JSON.stringifyを使うとIdolオブジェクトをJSON文字列に変換できます」
ことり「あとは同じ感じかな」
穂乃果「どれどれ・・・うん、保存できてるみたい」


海未「次に、アイドルの追加をやってみましょう」
穂乃果「増えるのっ?メンバー増えるのっ!?」
ことり「千歌ちゃんとかルビィちゃんとか来ちゃう?来ちゃう?」
穂乃果「きっと泣いて喜ぶよ~っ!」
海未「あと1人、ショック死しそうな人もいますね・・・」

海未「ではまず、アイドルを追加するUIを用意しましょう。idols.component.htmlのアイドル一覧の上に、テキストボックスとボタンを置きます」

海未「idols.component.tsにイベントハンドラaddを実装します」

海未「ここも、IdolServiceへの橋渡しだけですから難しくないでしょう」

海未「最後にIdolServiceです」

ことり「updateとほとんど同じだね」
海未「ほぼputpostに変わっただけです。これで、アイドルを追加できるようになりました」
穂乃果「ダイヤさん、ようこそμ’sへ!」


海未「さて、取得、更新、追加ときましたから、次は・・・」
穂乃果「ええっ!?削除しちゃうの!?」
海未「アイドルの世界は厳しいですから」
ことり「ダイヤさんが入ったら、生徒会長キャラは2人もいらないから、絵里ちゃんかな♪」
穂乃果「ことりちゃんって、時々すごくドライなこと言うよね・・・」

海未「idols.component.htmlで、各アイドルの隣に削除ボタンを置きましょう」

海未「スタイルシートにもクラスを1つ追加します」

海未「これに対応するイベントハンドラは」

海未「これも基本的な形は変わりませんね。削除が終わったらthis.idolsから削除したアイドルを取り除いて、画面上からも消えるようにしています」

海未「IdolServiceは」

海未「これもここまでで見たとおりでしょう」


海未「では最後に、検索機能を付けてみましょう。アイドルの名前を入力すると該当するアイドルを表示する、といったものです」

海未「はじめに、検索機能は新しいサービスとして実装することにしましょう。idol-search.service.tsに検索機能を実装します」

海未「これまで少しだけ出てきましたがあまり触れなかったのはObservableでしょう」
ことり「前は、toPromiseってしちゃってたけど・・・」
海未「ObservableはRxJSというライブラリの、非同期データを扱うための仕組みです。今回は、このObservableを直接使っていくことにします」

海未「HttpgetObservableを返すというのは今回の最初に見ましたが、RxJSのmapを使ってデータを取り出すことができます」
穂乃果「ねえねえ海未ちゃん、なんでAngularじゃなくてRxJSが出てくるの?」
海未「AngularもObservableを提供してはいるのですが・・・基本的な実装しか含まれていないので、実用的にはRxJSのObservableを使うことになります」
穂乃果「うーん、まだ作りかけなのかな・・・?」
海未「このコードで使っているmapも、AngularのObservableには含まれていないメソッドです。これを利用するために、import 'rxjs/add/operator/map';というimport文を使っています」
ことり「えーと、mapっていうメソッドをインポートしてる、でいいのかな」
海未「Observablemapを追加する、という動きになると考えてください」

海未「Promiseの代わりにObservableを返す、というところがこれまでとの相違点ですが、他は特に難しいところはないはずです。次に検索用のコンポーネントを実装します。はじめにidol-search.component.htmlidol-search.component.cssから」

海未「これまでと違うのは、asyncというパイプを使っているところでしょう。これから実装する部分ですがidolsIdolSearchServiceから返されたObservableになりますから、asyncパイプを使って非同期処理が完了したところでデータを処理するようにします」
穂乃果「・・・Observableだったらとりあえずasyncつければいいのかな?」
海未「まあ・・・間違ってはいませんが」

海未「最後に、idol-search.component.tsを実装しましょう」

穂乃果「なんか難しそうなんだけど~」
海未「実際複雑ですから、まずsearchTermsあたりから順に見ていきましょう」

海未「SubjectObservableの一種なのですが、nextを呼び出すことでこの場合では文字列をストリームに追加し、後続するイベントを発火させることができます」
ことり「後続するイベントって、今までだとthenとかswitchMapとかcatchとか、そういうのかな?」
海未「そうですね。この次に見るngOnInitsearchTermsに対して色々と下準備をしますから、それが検索ワードの追加に反応して実行されるという仕掛けです」
穂乃果「検索ワードは・・・#searchBoxから渡されてくるんだよね。keyupだから一文字打つたびに新しい検索ワードが追加されるんだ」
ことり「インクリメンタル検索だね」

海未「ではngOnInitの方を見てみましょう」

海未「概ね、コメントを付けた通りなのですが・・・ここでswitchMapを使っているのは、キーストロークの度に新しい検索ワードが流れ込んできますから、常に最新のものだけを処理するためです」
ことり「switchMapは、えーと、実行中の処理を中止して新しいリクエストを処理する、っと」

海未「それから、補足です。AngularのObservableは機能が限定されている、という話をしましたが、ここでもそれを補うためにRxJSからインポートしているものがあります。debounceTimedistinctUntilChangeなどはAngularのObservableにはないものです」


海未「では総仕上げです。ダッシュボードに検索機能を組み込んでみましょう」

海未「app.modules.tsdeclarationIdolSearchComponentを追加すれば完成です!」
穂乃果「わっ、文字打つ度に結果が絞り込まれるんだ!なんかかっこいいよ!」
ことり「長かったけど、結構しっかりしたのができたね♪」
海未「軽くではありますが、Angularの機能の多くを触ることができたと思います」


海未「次回ですが・・・」
穂乃果「えっ?まだあるの?」
海未「やるかやらないか考えているのですが・・・ngrxという、Angularの拡張があるのです」
穂乃果「むむむ、これは難しそう・・・」
海未「ここで扱う範囲を超えているような気もするので、迷っているのですが・・・もしかしたら、続けるかもしれません」
ことり「とりあえず、中締めかな?」
海未「そうですね」

穂乃果「では、ここまでのお相手は高坂穂乃果とっ!」
ことり「南ことりと♪」
海未「園田海未でした♡」
ほのことうみ「「「まったねーーーーっ!!」」」


LINEで送る
Pocket


返信を残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です