LoginSignup
11
11

More than 3 years have passed since last update.

Angular 9/8 Tutorial: Build a Web App with HttpClient and RxJS 翻訳

Last updated at Posted at 2019-12-15

ng9-1.jpeg

Angular #2 Advent Calendar 2019 | 15日目

Medium BlogAngular 9/8 Tutorial: Build a Web App with HttpClient and RxJS
の翻訳です。

この Angular 9 チュートリアルでは、 REST API の作成/シミュレーション、新しいプロジェクトの足場、重要な API の設定、最終的なアプリケーションの構築とデプロイから必要なすべてのステップを経て Angular 9 サンプルアプリケーションを構築する方法を学びます クラウドへ。

  • 例として、URL クエリ文字列とパラメーターを使用して GET リクエストを送信し、JSON データを取得して消費するために Httplient を使用して、Angular 9/8 アプリケーションの REST API サーバーから HTTP 応答を処理する方法、 HTTP エラーのエラー処理方法を学習します。
    RxJS の throwError() および catchError()retry() および takeUntil() 演算子を使用して、失敗したネットワーク接続で失敗した HTTP リクエストを再試行し、保留中のリクエストをキャンセルする方法、最後に最新の Angualar 8.3 以上の機能です。
  • また、Angular サービスと RxJS Observables の使用方法を確認し、プロジェクトでAngular Material を設定し、Material Design コンポーネントでUIをスタイルする方法を学びます。
  • Angular 8.3+ の新しい ng deploy 機能を使用して、Angular 9 アプリケーションをコマンドラインから Firebase ホスティングに簡単にデプロイする方法について説明します。

現在、Angular 9 は RC バージョンであり、特に新しい Ivy レンダラーをはじめとするさまざまな新機能と改善が含まれています。

このチュートリアルは、最新の Angular 9 バージョンに更新されました。

注:HTTP クライアント API の改良バージョンである HttpClient を使用していることに注意してください。
これは、 Angular バージョン 4.3.0-rc.0 以降で利用可能です。
古い HTTP クライアントは、 Angular 9 では使用できません。

このチュートリアルでは、 Angular 9 で HttpClient を使用して、サードパーティの REST API から JSON データを取得するニュースアプリケーションを構築する方法も確認できます。

このステップバイステップのAngular 9チュートリアルでは、 @angular/common/http パッケージから入手できる HttpClient を使用して、 get() メソッドを使用して HTTP GET リクエストを作成する方法の実用的な例を見ていきます。

内容:mid_content 143
  • fake を作成し、機能する JSON REST API を完成させる方法、
  • Angular CLI v9 のインストール方法、
  • Angular CLI を使用して Angular 9 プロジェクトを作成する方法、
  • Angular Material をセットアップし、 Material Design で、アプリケーションをスタイルする方法、
  • Angular コンポーネントの作成方法、それらの間のルーティングとナビゲーション、
  • Angular サービスを作成および注入する方法、
  • HttpClient を使用してサーバーに HTTP GET リクエストを送信する方法、
  • HttpParams クラスを使用して、 HttpRequest に URL クエリ文字列を追加する方法、
  • HttpClient によって返された RxJS Observables を subscribe および unsubscribe する方法、
  • throwError() および catchError() を使用して HTTP エラーをハンドルする方法、
  • RxJS retry() オペレータを使用して失敗した HTTP 要求を再試行する方法、
  • HttpClient メソッドから返された RxJS Observables から、リクエストがキャンセルされたときに takeUntil() オペレータを使用して unsubscribe する方法、
  • Angular 8.3 以降で利用可能な新しい ng deploy コマンドを使用して、実稼働用のアプリケーションをビルドし、Firebase ホスティングにデプロイする方法

この Angular 9 チュートリアルの手順は次のとおりです。

  • ステップ01 — Angular CLI v9 のセットアップ
  • ステップ02 — 新しい Angular 9 サンプルプロジェクトの初期化
  • ステップ03 — (Fake) JSON REST API をセットアップする
  • ステップ04 — サンプルプロジェクトでAngular HttpClient v9を設定する
  • ステップ05 — Angular 9コンポーネントの作成
  • ステップ06 — Angular 9ルーティングを追加する
  • ステップ07 — Angular Material v9を使用してUIをスタイル設定する
  • ステップ08 — Angular HttpClient v9でJSON REST APIを使用する
  • ステップ09 — RxJS catchError() および HttpClient を使用したHTTPエラー処理の追加
  • ステップ10 — RxJS retry() および HttpClient を使用して失敗したHTTPリクエストを再試行する
  • ステップ11 — RxJS takeUntil() を使用した HttpClient Observablesからのサブスクライブ解除
  • ステップ12 — HttpClient get() メソッドに URL クエリパラメーターを追加する
  • ステップ13 — Angular HttpClient v9 で完全なHTTPレスポンスを取得する
  • ステップ14 — Angular HttpClient v9 で型指定されたHTTP応答を要求する
  • ステップ15 — Angular 9 アプリケーションを Firebase Hosting にビルドおよびデプロイする

Angular HttpClient の機能、およびそれを使用する理由を紹介することから始めましょう。

Angular HttpClient とは何ですか?

Angularなどのフレームワークを使用して構築されたフロントエンドアプリケーションは、 XMLHttpRequest インターフェイスまたは fetch() APIを使用して、REST API(HTTPプロトコルに基づく)を介してバックエンドサーバーと通信します。

Angular HttpClient は、最新のブラウザーとレガシーブラウザーの両方をサポートする XMLHttpRequest インターフェイスを利用します。

HttpClientは @angular/common/http パッケージから入手でき、簡単なAPIインターフェイスと、簡単なテスト容易性、型指定された要求および応答オブジェクト、要求および応答インターセプター、RxJS Observablesを備えたリアクティブAPI、合理化されたエラー処理などの強力な機能を備えています。

Angular HttpClient を使用する理由

HttpClient ビルトインサービスは、 Angular 開発者に多くの利点を提供します。

  • HttpClient を使用すると、HTTP 要求と応答を簡単に送信および処理できます。
  • HttpClient には、テストユニットを実装するための多くの組み込み機能があり、
  • HttpClient は、次のような一般的なWeb開発タスクを簡素化する Promise の代わりに、RxJS Observables を使用して非同期操作を処理します。
    • HTTP リクエストの集中
    • ダウンロードおよびアップロード操作の進行を聞いて
    • 簡単なエラー処理
    • 失敗したHTTP 要求などの再試行

HttpClient を紹介した後、Angular 9 チュートリアルを正しく完了するために必要な前提条件から始めて、サンプルアプリケーションの構築に進みましょう。

前提条件

始める前に、いくつかの前提条件が必要です。

  • TypeScript の基本的な知識。
    特に、TypeScript クラスやデコレータなどのオブジェクト指向の概念に精通している事。
  • NPM 6+ がインストールされた Node10+ を備えたローカル開発マシン。
    最近のほとんどのフロントエンドツールのように、 Angular CLI にはノードが必要です。
    公式Webサイトのダウンロードページにアクセスして、オペレーティングシステムのバイナリをダウンロードするだけです。
    パッケージマネージャを使用してNodeをインストールする方法については、特定のシステム手順を参照することもできます。
    ただし、推奨される方法は、NVM — Node Version Manager — POSIX準拠のbashスクリプトを使用して、複数のアクティブなNode.jsバージョンを管理することです。

注:Angular 開発用のローカル環境をインストールしたくないが、このチュートリアルのコードを試してみたい場合は、Angular CLI と互換性のある Angular プロジェクトを作成できるフロントエンド開発用のオンライン IDE である Stackblitz を使用できます 。

以前の前提条件が整った時、Angular 9 チュートリアルの次のステップ、Angular HttpClient を使用して JSON データを取得するための HTTP GETリクエストと、 catchError()tap()retry()takeUntil() などの様々な RxJS 演算子を送信してエラーなどの高度な機能を実装する方法や HTTPリクエストの再試行、保留中のリクエストのキャンセルを例で説明に進む準備ができています。

チュートリアルの最初のステップでは、Angular CLI 9をインストールし、ゼロからサンプルプロジェクトを作成する方法について説明します。

ステップ01 — Angular CLI v9 のセットアップ

このステップでは、最新の Angular CLI 9バージョンをインストールします(このチュートリアルの執筆時点)。

注:これらの手順は、Angular 8でも有効です。

rxjs-01.jpg

Angular CLI は、Angular プロジェクトを初期化して操作するための公式ツールです。 それをインストールするには、新しいコマンドラインインターフェイスを開き、次のコマンドを実行します。

$ npm install -g @angular/cli@next

このチュートリアルを書いている時点で、angular/cli v9.0.0-rc.2 がシステムにインストールされます。

Angular 9 が公式にリリースされるまで、 @next タグを使用して最新のプレリリースバージョンをインストールする必要があることに注意してください。

ng version コマンドを実行すると、同様の出力が得られます。

Angular CLI: 9.0.0-rc.2
Node: 10.16.3
OS: win32 ia32
Angular:
...Package                      Version
------------------------------------------------------
@angular-devkit/architect    0.900.0-rc.2
@angular-devkit/core         9.0.0-rc.2
@angular-devkit/schematics   9.0.0-rc.2
@schematics/angular          9.0.0-rc.2
@schematics/update           0.900.0-rc.2
rxjs                         6.5.3

次のステップでは、コマンドラインから新しいサンプルプロジェクトを初期化する方法を学習します。

ステップ02 — 新しい Angular 9 サンプルプロジェクトの初期化

このステップでは、サンプルプロジェクトの作成に進みます。
コマンドラインインターフェイスに戻り、次のコマンドを実行します。

$ cd ~
$ ng new angular-httpclient-example

CLIからいくつか質問があります。
Angular routing を追加しますか? [はい]にyと入力し、
どのスタイルシート形式を使用しますか? CSSを選択します。

これにより、プロジェクトにルーティングを自動的に設定するように CLI に指示されるため、アプリケーションにナビゲーションを実装するためにコンポーネントのルートを追加するだけで済みます。

プロジェクトのフォルダー内で ng version コマンドを実行すると、同様の出力が得られます。

Angular CLI: 9.0.0-rc.2
Node: 10.16.3
OS: win32 ia32
Angular: <error>
... animations, cli, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... routerPackage                         Version
---------------------------------------------------------
@angular-devkit/architect       0.900.0-rc.2 (cli-only)
@angular-devkit/build-angular   <error>
@angular-devkit/core            9.0.0-rc.2 (cli-only)
@angular-devkit/schematics      9.0.0-rc.2 (cli-only)
@schematics/angular             9.0.0-rc.2 (cli-only)
@schematics/update              0.900.0-rc.2 (cli-only)
rxjs                            6.5.3 (cli-only)
typescript                      3.6

次に、プロジェクトのフォルダーに移動し、次のコマンドを使用してローカル開発サーバーを実行します。

$ cd angular-httpclient-example
$ ng serve

ローカル開発サーバーは、アドレス http://localhost:4200/ で、開始します。

rxjs-02.jpg

Webブラウザーを開き、 http://localhost:4200/ アドレスに移動して、アプリが稼働していることを確認します。 これは、この時点でのスクリーンショットです。

rxjs-03.jpg

これで、開発サーバーを実行したままにして、次の手順の CLI コマンドを実行するための新しいコマンドラインインターフェイスを開始する必要があります。

次のステップでは、 Angular サンプルアプリケーションで使用する fake JSON REST API を作成する方法を学習します。

ステップ03 — (Fake) JSON REST API をセットアップする

Angular アプリケーションの開発に進む前に、 HttpClient を使用して使用できる JSON REST API を準備する必要があります。

サードパーティのREST APIサーバーからJSONデータを消費または取得することもできますが、この例では、fake REST APIを作成することを選択します。
実際のREST APIの例については、このチュートリアルをご覧ください。
Angular に関する限り、fake API と実際の REST API の使用に違いはありません。

前述のように、外部APIサービスを使用するか、実際の REST API サーバーを作成するか、 json-server を使用して偽のAPIを作成できます。
この例では、最後のアプローチを使用します。

したがって、新しいコマンドラインインターフェイスに進み、プロジェクトの npm から json-server をインストールすることから始めます。

$ cd ~/angular-httpclient-example
$ npm install --save json-server

次に、Angularプロジェクトのルートフォルダにサーバーフォルダを作成します。

$ mkdir server
$ cd server

サーバーフォルダで、 database.json ファイルを作成し、次の JSON オブジェクトを追加します。

{
    "products": []
}

この JSON ファイルは、 REST API サーバーのデータベースとして機能します。
REST API で提供するデータを追加するか、 Faker.js を使用して大量の現実的な fake データを自動的に生成できます。

コマンドラインに戻り、サーバーフォルダから戻って、次のコマンドを使用して npm から Faker.js をインストールします。

$ cd ..
$ npm install faker --save

この例を作成すると、 faker v4.1.0 がインストールされます。

次に、 generate.js ファイルを作成し、次のコードを追加します。

var faker = require('faker');var database = { products: []};for (var i = 1; i<= 300; i++) {
  database.products.push({
    id: i,
    name: faker.commerce.productName(),
    description: faker.lorem.sentences(),
    price: faker.commerce.price(),
    imageUrl: "https://source.unsplash.com/1600x900/?product",
    quantity: faker.random.number()
  });
}console.log(JSON.stringify(database));

最初に faker を輸入し、1つの空の配列を持つオブジェクトを定義しました。
次に、forループに入って、製品名を生成するために faker.commerce.productName() などの faker メソッドを使用して300の偽エントリを作成しました。
利用可能なすべての方法を確認してください。
最後に、データベースオブジェクトを文字列に変換し、標準出力に記録しました。

次に、生成スクリプトサーバースクリプトを package.json ファイルに追加します。

"scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e",
    "generate": "node ./server/generate.js > ./server/database.json",
    "server": "json-server --watch ./server/database.json"
  },

次に、コマンドラインインターフェイスに戻り、次のコマンドを使用して生成スクリプトを実行します。

$ npm run generate

最後に、次のコマンドを実行して REST API サーバーを実行します。

$ npm run server

通常のREST APIサーバーと同じように、サーバーにHTTPリクエストを送信できるようになりました。 サーバーは http://localhost:3000/ から利用できます。

これらは、 JSON REST API サーバーを介して使用できる API エンドポイントです。

  • GET /products 製品取得用
  • GET /products/ id 毎 製品取得
  • POST /products 製品作成
  • PUT /products/ id 毎 製品更新
  • PATCH /products/ id 毎 製品更新
  • DELETE /products/ id 毎 製品削除

_page および _limit パラメーターを使用して、ページ分割されたデータを取得できます。 リンクヘッダーには、最初最後のリンクが表示されます。

例:

データの最初のページを取得する場合は、 GET /products?_page=1 、データの最初のページの最初の5つの製品を取得する場合は、 GET /products?_page=1&_limit = 5

注:フィルタ、ソート、順序付けなどの他の機能を使用できます。
詳細については、ドキュメントをご覧ください。

JSON REST API サーバーを実行したままにして、次の手順のコマンドを入力するための新しいコマンドラインインターフェイスを開きます。

これまでの作業の概要として、 Angular CLI をインストールし、最新の Angular 9 バージョンに基づいて新しいプロジェクトを初期化しました。 次に、JSON ファイルに基づいてjson-server を使用して REST API を作成しました。 Angular 9 チュートリアルの次のステップでは、 Angular 9 プロジェクトで HttpClient を設定する方法を学びます。

ステップ04 — サンプルプロジェクトでAngular HttpClient v9を設定する

このステップでは、この例の HttpClient モジュールのセットアップに進みます。

HttpClient は別の Angular モジュールにあるため、使用する前にメインアプリケーションモジュールにインポートする必要があります。

コードエディターまたはIDEでサンプルプロジェクトを開きます。
Visual Studio Code を使用します。

次に、 src/app/app.module.ts ファイルを開き、 HttpClientModule をインポートして、次のようにモジュールの imports 配列に追加します。

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HttpClientModule } from '@angular/common/http';@NgModule({
  declarations: [
    AppComponent,
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

以上で、プロジェクトで HttpClient サービスを使用する準備が整いましたが、その前にいくつかのコンポーネント( home コンポーネントと about コンポーネント)を作成する必要があります。 これは、次のステップで行うことを学ぶものです。

ステップ05 — Angular 9コンポーネントの作成

このステップでは、アプリケーション UI を制御する Angular コンポーネントの作成に進みます。

新しいコマンドラインインターフェイスに戻り、次のコマンドを実行します。

$ cd ~/angular-httpclient-example
$ ng generate component home

これはコマンドの出力結果です:

CREATE src/app/home/home.component.html (19 bytes)
CREATE src/app/home/home.component.spec.ts (614 bytes)
CREATE src/app/home/home.component.ts (261 bytes)
CREATE src/app/home/home.component.css (0 bytes)
UPDATE src/app/app.module.ts (467 bytes)

CLIは、コンポーネント用に4つのファイルを作成し、 src/app/app.module.ts ファイルの declarations 配列に追加しました。

次に、次のコマンドを使用して about コンポーネントを作成しましょう。

$ ng generate component about

次に、 src/app/about/about.component.html を開き、次のコードを追加します。

<p style="padding: 13px;">
An Angular 9 example application that demonstrates how to use HttpClient to consume REST APIs
</p>

次の手順で、 home コンポーネントを更新します。

Angular 9 チュートリアルの次のステップでは、これらのコンポーネントを router に追加します。

ステップ06 — Angular 9ルーティングを追加する

このステップでは、例に routing を追加します。

ルーティング構成用にAngular CLIによって自動的に作成された src/app/app-routing.module.ts ファイルに戻り、コンポーネントをインポートして、次のように routes を追加します。

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { AboutComponent } from './about/about.component';

const routes: Routes = [
  { path: '', redirectTo: 'home', pathMatch: 'full'},
  { path: 'home', component: HomeComponent },
  { path: 'about', component: AboutComponent },
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

最初に home と about コンポーネントについてインポートし、次に空のパスを home コンポーネントにリダイレクトするためのルートを含む3つのルートを追加しました。これにより、ユーザーがアプリにアクセスすると、ホームページにリダイレクトされます。

この例の次のステップでは、UI スタイルを設定するためにプロジェクトに Angular Material を設定します。

ステップ07 — Angular Material v9を使用してUIをスタイル設定する

Angular 9 チュートリアルのこの手順では、Angular Material をプロジェクトに追加し、アプリケーション UI のスタイルを設定します。

Angular Material は、開発者がプロフェッショナルなUIを作成できるMaterial Designコンポーネントを提供します。 Angular CLI v7 +の新しい ng add コマンドを使用すると、プロジェクトで Angular Material を簡単に設定できます。

コマンドラインインターフェイスに戻り、プロジェクトのルートから次のコマンドを実行します。

$ ng add @angular/material

テーマを選択するよう求められます。Indigo/Pink を選択します。

その他のオプション — ジェスチャー認識用にHammerJSをセットアップしますか?
そして Angular Materialのブラウザアニメーションを設定しますか?
キーボードのEnterキーを押すだけで、デフォルトの回答を選択でき
ます。

次に、 src/styles.css ファイルを開き、テーマを追加します。

@import "~@angular/material/prebuilt-themes/indigo-pink.css";

各 Angular Material コンポーネントには、コンポーネントを使用する前にインポートする必要がある個別のモジュールがあります。
src/app/app.module.ts ファイルを開き、次のインポートを追加します。

import { 
  MatToolbarModule,
  MatIconModule,
  MatCardModule,
  MatButtonModule,
  MatProgressSpinnerModule
} from '@angular/material';

次のモジュールをインポートしました。

  • MatToolbar ヘッダー、タイトル、またはアクションのコンテナーを提供する。
  • MatCard 単一の件名のコンテキストでテキスト、写真、およびアクションのコンテンツコンテナーを提供する。
  • MatButton マテリアルデザインのstyling と ink ripples で強化されたネイティブの <button> または <a> 要素を提供する。
  • MatProgressSpinner 進行状況とアクティビティの円形インジケータを提供する

次に、これらのモジュールを imports 配列に含める必要があります。

@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    AboutComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule,
    BrowserAnimationsModule,
    MatToolbarModule,
    MatIconModule,
    MatButtonModule,
    MatCardModule,
    MatProgressSpinnerModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

次に、src/app/app.component.html ファイルを開き、次のように更新します。

<mat-toolbar color="primary">
  <h1>
    ngStore 
  </h1>
  <button mat-button routerLink="/">Home</button>
  <button mat-button routerLink="/about">About</button>
</mat-toolbar>
<router-outlet></router-outlet>

home と about コンポーネントに関する2つのナビゲーションボタンを備えたトップバーを含むアプリケーションのシェルを作成しました。

チュートリアルの次のステップでは、 HttpClient v9 を使用して REST API サーバーから JSON データを取得する方法を学習します。

ステップ08 — Angular HttpClient v9 で JSON REST APIを使用する

このステップでは、サンプルアプリケーションの REST API サーバーから JSON データを使用します。

REST API サーバーからのデータの消費を処理するコードをカプセル化するために、Angular サービスを作成する必要があります。

サービスは、Angular 依存性注入を使用して他のサービスおよびコンポーネントによって注入できるシングルトンです。

ソフトウェアエンジニアリングでは、依存性注入は、あるオブジェクトが別のオブジェクトの依存性を提供する手法です。

次に、JSON REST API と連動する Angular サービスを生成します。 コマンドラインインターフェイスに戻り、次のコマンドを実行します。

$ ng generate service data

次に、 src/app/data.service.ts ファイルを開き、次のように HttpClient をインポートして注入します。

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable({
  providedIn: 'root'
})
export class DataService {  
  private REST_API_SERVER = "http://localhost:3000";

  constructor(private httpClient: HttpClient) { }
}

HttpClient サービスをプライベート httpClient インスタンスとしてインポートおよび注入しました。
また、 REST API サーバーのアドレスを保持する REST_API_SERVER 変数を定義しました。

次に、GET 要求を REST API エンドポイントに送信して JSON データを取得するsendGetRequest() メソッドを追加します。

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable({
  providedIn: 'root'
})
export class DataService {  
  private REST_API_SERVER = "http://localhost:3000";  

  constructor(private httpClient: HttpClient) { }  

  public sendGetRequest(){
    return this.httpClient.get(this.REST_API_SERVER);
  }
}

このメソッドは、単に HttpClientget() メソッドを呼び出して、GET 要求を REST API サーバーに送信します。

次に、 home コンポーネントでこのサービスを使用する必要があります。
src/app/home/home.component.ts ファイルを開き、次のようにデータサービスをインポートして注入します。

import { Component, OnInit } from '@angular/core';
import { DataService } from '../data.service';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {  
  products = [];  

  constructor(private dataService: DataService) { }  

  ngOnInit() {    
    this.dataService.sendGetRequest().subscribe((data: any[])=>{
      console.log(data);
      this.products = data;
    })  
  }
}

コンポーネントコンストラクターを使用して、プライベート dataService インスタンスとして DataService をインポートおよび注入しました。

次に、製品変数を定義し、 JSON REST API サーバーからデータを取得するためにサービスの sendGetRequest() メソッドを呼び出しました。

sendGetRequest() メソッドは RxJS Observable である HttpClient.get() メソッドの戻り値を返すため、Observable にサブスクライブして、実際に HTTP GET 要求を送信し、HTTP 応答を処理します。

データを受信したら、 products 配列に追加しました。

次に、 src/app/home/home.component.html ファイルを開き、次のように更新します。

<div style="padding: 13px;">
    <mat-spinner *ngIf="products.length === 0"></mat-spinner>    <mat-card *ngFor="let product of products" style="margin-top:10px;">
        <mat-card-header>
            <mat-card-title>{{product.name}}</mat-card-title>
            <mat-card-subtitle>{{product.price}} $/ {{product.quantity}}
            </mat-card-subtitle>
        </mat-card-header>
        <mat-card-content>
            <p>
                {{product.description}}
            </p>
            <img style="height:100%; width: 100%;" src="{{ product.imageUrl }}" />
        </mat-card-content>
        <mat-card-actions>
      <button mat-button> Buy product</button>
    </mat-card-actions>
    </mat-card>
</div>

製品の配列の長さがゼロに等しい場合、つまり REST API サーバーからデータを受信しない前に、ロードスピナーを表示するために <mat-spinner> コンポーネントを使用しました。

次に、製品の配列を繰り返し処理し、マテリアルカードを使用して各製品の名前価格数量説明画像 を表示しました。

これは、JSON データが取得された後のホームページのスクリーンショットです。

次に、サービスにエラー処理を追加する方法を確認します。

ステップ09 — RxJS catchError() および HttpClient を使用したHTTPエラー処理の追加

この手順では、サンプルアプリケーションにエラー処理を追加します。

Angular の HttpClient メソッドは、エラーをキャッチして処理するための pipe() メソッドを介して Observables を返すため、 RxJS の catchError() 演算子で簡単に使用できます。サービス内のエラーを処理するメソッドを定義するだけです。

フロントエンドアプリケーションには2種類のエラーがあります。

  • ネットワークの問題、JavaScript構文およびタイプエラーなどのクライアント側エラー。 これらのエラーは ErrorEvent オブジェクトを返します。
  • サーバーのコードエラーやデータベースアクセスエラーなどのサーバー側エラー。 これらのエラーはHTTPエラー応答を返します。

そのため、エラーが ErrorEvent のインスタンスであるかどうかを確認して、エラーの種類を取得するだけで、適切に処理できます。

それでは、例を見てみましょう。 src/app/data.service.ts ファイルを開き、それに応じて更新します。


import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse } from "@angular/common/http";
import { throwError } from 'rxjs';
import { retry, catchError } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class DataService {  
  private REST_API_SERVER = "http://localhost:3000/products";  

  constructor(private httpClient: HttpClient) { }  
  handleError(error: HttpErrorResponse) {
    let errorMessage = 'Unknown error!';
    if (error.error instanceof ErrorEvent) {
      // Client-side errors
      errorMessage = `Error: ${error.error.message}`;
    } else {
      // Server-side errors
      errorMessage = `Error Code: ${error.status}\nMessage: ${error.message}`;
    }
    window.alert(errorMessage);
    return throwError(errorMessage);
  }  public sendGetRequest(){
    return this.httpClient.get(this.REST_API_SERVER).pipe(catchError(this.handleError));
  }
}

ご覧のとおり、これはアプリケーション内の各サービスに対して行う必要があります。
この例では1つのサービスしか含まれていませんが、アプリケーションがエラーをスローする可能性のある多くのサービスで成長し始めると、代わりに優れたソリューションを使用する必要があります。
エラーが発生しやすい各サービスごとに handleError メソッドを使用します。
1つの解決策は、 HttpClient interceptors を使用して Angular アプリケーションでエラーをグローバルに処理することです。

これは、サーバーに到達できない場合のコンソール上のエラーのスクリーンショットです。

次のステップでは、失敗した HTTP リクエストの送信を自動的に再試行することにより、データサービスを改善する方法を確認します。

ステップ10 — RxJS retry() および HttpClient を使用して失敗したHTTPリクエストを再試行する

Angular 9 チュートリアルのこのステップでは、 HttpClient で RxJS の retry() 演算子を使用して、返された Observable を自動的に再サブスクライブし、失敗したHTTPリクエストを再送信する方法を説明します。

多くの場合、エラーは一時的なものであり、ネットワークの状態が悪いため、再試行するだけで自動的に消えます。 たとえば、モバイルデバイスでは、ネットワークの中断が頻繁に発生するため、ユーザーが再試行すると、成功した応答が返される場合があります。 ユーザーに手動で再試行させるのではなく、サンプルアプリケーションで自動的に再試行する方法を見てみましょう。

RxJS ライブラリには、いくつかの再試行演算子が用意されています。 その中には、指定した回数だけ RxJS Observable を自動的に再サブスクライブできる retry() 演算子があります。 HttpClient メソッドから返された Observable を再サブスクライブすると、サーバーにHTTP 要求を再送信する効果があるため、ユーザーは操作を繰り返したり、アプリケーションをリロードしたりする必要はありません。

エラーハンドラーの前に HttpClient メソッドから返された Observable に(pipe() メソッドを使用して)パイプすることにより、RxJS の retry() 演算子を使用できます。

src/app/data.service.ts ファイルに移動して、 retry() 演算子をインポートします。

import { retry, catchError } from 'rxjs/operators';

次に、 sendGetRequest() メソッドを次のように更新します。

public sendGetRequest(){
  return this.httpClient.get(this.REST_API_SERVER)
             .pipe(retry(3), catchError(this.handleError));
}

これにより、失敗したHTTP要求の送信が3回再試行されます。

次のステップでは、サンプルの home コンポーネントで RxJS Observables の登録を解除する方法を確認します。

ステップ11 — RxJS takeUntil() を使用した HttpClient Observablesからのサブスクライブ解除

Angular 9 チュートリアルのこのステップでは、takeUntil() 演算子を使用して、コードでObservablesが必要な理由と購読を解除する方法について学習します。

まず、 HttpClient メソッドによって返される Observables からサブスクライブを解除する必要がありますか?

一般的に、メモリリークを避けるために、 Angular コンポーネントのサブスクライブされた RxJS Observable を手動で subscribe 解除する必要がありますが、 HttpClient の場合、これは HTTP 応答の受信時に unsubscribe することにより、 Angular によって自動的に処理されます。 ただし、ユーザーがコンポーネントを離れようとしているときに保留中のリクエストをキャンセルするなど、手動で登録解除する必要がある場合があります。

コンポーネントの ngOnDestroy() ライフサイクルメソッドの subscribe() メソッドによって返されるSubscription オブジェクトから unsubscribe() メソッドを呼び出すだけで、Observable から subscribe() を解除できます。

また、 takeUntil() を使用して、Observables をサブスクライブ解除または完了するより良い方法があります。

takeUntil() は、通知オブジェクトObservable が値を発行するまで、ソース Observable が発行した値を発行します。

コンポーネントが破壊されたときにこの演算子を使用して Observables を完了する方法を見てみましょう。

How to cancel/unsubscribe all pending HTTP requests angular 4+.をご覧ください。

src/app/home_home.component.ts ファイルを開き、次のように更新します。

import { Component, OnInit, OnDestroy } from '@angular/core';
import { DataService } from '../data.service';
import { takeUntil } from 'rxjs/operators';

import { Subject } from 'rxjs';@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit, OnDestroy {  

  products = [];
  destroy$: Subject<boolean> = new Subject<boolean>();  

  constructor(private dataService: DataService) { }  

  ngOnInit() {    
    this.dataService.sendGetRequest()
      .pipe(takeUntil(this.destroy$))
      .subscribe((data: any[])=>{
        console.log(data);
        this.products = data;
    })  
  }

  ngOnDestroy() {
    this.destroy$.next(true);
    // Unsubscribe from the subject
    this.destroy$.unsubscribe();
  }
}

最初に、 OnDestroy インターフェース、 Subject 、および takeUntil() をインポートしました。
次に、OnDestroyインターフェイスを実装し、 OnDestroy ライフサイクルフックをコンポーネントに追加しました。

次に、 takeUntil() の通知機能として使用されるブール値(この例では値のタイプは実際には重要ではありません)を発行できる Subject のインスタンスを作成しました。

次に、 ngOnInit() ライフサイクルフックで、データサービスの sendGetRequest() を呼び出し、返された Observable の pipe() メソッドを呼び出して takeUnitl() 演算子をパイプ処理し、結合された Observable に subscribe します。
subscribe() メソッドの本体に、取得したHTTP応答のデータを products 配列に入れるロジックを追加しました。

takeUnitl() オペレーターは、通知 Observable から値が発行されるまで、通知された Observable が値を発行できるようにします。

Angular がコンポーネントを破棄するとき、 ngOnDestroy() ライフサイクルメソッドを呼び出します。この場合、このメソッドは next() メソッドを呼び出して値を発行し、 RxJS がすべての subscribe 済み Observable を完了するようにします。

このステップでは、HTTP 応答を受信する前にユーザーがコンポーネントから移動することを決定した場合に、返された Observable から unsubscribe することにより、保留中の HTTP 要求をキャンセルするロジックを追加しました。

Angular 9 チュートリアルの次のステップでは、 HttpClientget() メソッドでURLクエリパラメーターを使用する方法について説明します。

ステップ12 — HttpClient get() メソッドに URL クエリパラメーターを追加する

このステップでは、サンプルアプリケーションにページネーションを実装するためのロジックの追加を開始します。 fromString および HttpParams を介してURLクエリパラメーターを使用して、ページ分割されたデータを取得するための JSON REST API サーバーの /products エンドポイントの _page および _limit パラメーターに適切な値を提供する方法について説明します。

src/app/data.service.ts ファイルを開き、 HttpParams の次のインポートを追加して開始します。

import { HttpClient, HttpErrorResponse, HttpParams } from "@angular/common/http";

次に、 sendGetRequest() メソッドを次のように更新します。

public sendGetRequest(){
  // Add safe, URL encoded_page parameter 
  const options = { params: new HttpParams({fromString: "_page=1&_limit=20"}) };
  return this.httpClient.get(this.REST_API_SERVER, options).pipe(retry(3), catchError(this.handleError));
}

HttpParamsfromString を使用して、 _page=1&_limit=20 文字列から HTTP クエリパラメーターを作成しました。 これにより、20個の製品の最初のページが返されます。

これで、 sendGetRequest() を使用してデータの最初のページを取得します。 受信したHTTP応答には、データページの最初、前、次、および最後のリンクに関する情報を含むリンクヘッダーが含まれます。

リンクヘッダーには、最初、前、次、最後のリンクが表示されます。 次のステップでは、完全なHTTP 応答を解析してこれらのページネーションリンクを抽出する方法を確認します。

ステップ13 — Angular HttpClient v9 で完全なHTTPレスポンスを取得する

このサイトでは、JSON REST API サーバーから受信した HTTP 応答に含まれる Link ヘッダーからページネーション情報を取得するロジックを実装することから始めます。

デフォルトでは、 HttpClient は応答本文のみを提供しますが、この場合、ページネーションリンクのリンクヘッダーを解析する必要があるため、 observe オプションを使用して完全なHttpResponse が必要であることを HttpClient に伝える必要があります。

HTTPのLinkヘッダーを使用すると、サーバーは、要求されたリソースに関するメタデータを含む別のリソースに関心のあるクライアントをポイントできます。 Wikipedia

src/app/data.service.ts ファイルに移動し、RxJS tap() をインポートします。

import { retry, catchError, tap } from 'rxjs/operators';

次に、文字列変数を定義します。

public first: string = "";
public prev: string = "";
public next: string = "";
public last: string = "";

次に、Link ヘッダーを解析し、それに応じて前の変数を設定する parseLinkHeader() メソッドを定義します。

parseLinkHeader(header) {
  if (header.length === 0) {
    return ;
  }    
  let parts = header.split(',');
  var links = {};
  parts.forEach( p => {
    let section = p.split(';');
    var url = section[0].replace(/<(.*)>/, '$1').trim();
    var name = section[1].replace(/rel="(.*)"/, '$1').trim();
    links[name] = url;    });    this.first  = links["first"];
  this.last = links["last"];
  this.prev = links["prev"];
  this.next = links["next"]; 
}

次に、 sendGetRequest() を次のように更新します。

public sendGetRequest(){
  // Add safe, URL encoded _page and _limit parameters     
  return this.httpClient.get(this.REST_API_SERVER, {  params: new HttpParams({fromString: "_page=1&_limit=20"}), observe: "response"}).pipe(retry(3), catchError(this.handleError), tap(res => {
    console.log(res.headers.get('Link'));
    this.parseLinkHeader(res.headers.get('Link'));
  }));
}

ヘッダー付きの完全な HTTP 応答を取得できるように、 get() メソッドのoptionsパラメーターに 応答値 を持つ observe オプションを追加しました。 次に、 RxJS tap() 演算子を使用してLinkヘッダーを解析し、最後の Observable を返します。

sendGetRequest() が完全なHTTP応答でObservableを返すようになったため、次のように src/app/home/home.component.ts ファイルを開いて HttpResponse をインポートするようにホームコンポーネントを更新する必要があります。

import { HttpResponse } from '@angular/common/http';

次に、 subscribe() メソッドを次のように更新します。

ngOnInit() {
  this.dataService.sendGetRequest().pipe(takeUntil(this.destroy$))
  .subscribe((res: HttpResponse<any>) => {
    console.log(res);
    this.products = res.body;
  })  
}

これで、受信したHTTP応答の body オブジェクトのデータにアクセスできます。

次に、 src/app/data.service.ts ファイルに戻り、次のメソッドを追加します。

public sendGetRequestToUrl(url: string){
  return this.httpClient.get(url, { observe: "response"})
    .pipe(retry(3), catchError(this.handleError), tap(res => {
    console.log(res.headers.get('Link'));
    this.parseLinkHeader(res.headers.get('Link'));
  }));
}

このメソッドは sendGetRequest() に似ていますが、HTTP GET リクエストを送信する必要がある URL を取得する点が異なります。

src/app/home/home.component.ts ファイルに戻り、次のメソッドを定義して追加します。

public firstPage() {
  this.products = [];
  this.dataService.sendGetRequestToUrl(this.dataService.first).pipe(takeUntil(this.destroy$)).subscribe((res: HttpResponse<any>) => {
    console.log(res);
    this.products = res.body;
  })
}
public previousPage() {    if (this.dataService.prev !== undefined && this.dataService.prev !== '') {
    this.products = [];
    this.dataService.sendGetRequestToUrl(this.dataService.prev).pipe(takeUntil(this.destroy$)).subscribe((res: HttpResponse<any>) => {
      console.log(res);
      this.products = res.body;
    })
  }  }
public nextPage() {
  if (this.dataService.next !== undefined && this.dataService.next !== '') {
    this.products = [];
    this.dataService.sendGetRequestToUrl(this.dataService.next).pipe(takeUntil(this.destroy$)).subscribe((res: HttpResponse<any>) => {
      console.log(res);
      this.products = res.body;
    })
  }
}
public lastPage() {
  this.products = [];
  this.dataService.sendGetRequestToUrl(this.dataService.last).pipe(takeUntil(this.destroy$)).subscribe((res: HttpResponse<any>) => {
    console.log(res);
    this.products = res.body;
  })
}

最後に、 src/app/home/home.component.html ファイルを開いて追加し、次のようにテンプレートを更新します。

<div style="padding: 13px;">
  <mat-spinner *ngIf="products.length === 0"></mat-spinner>    <mat-card *ngFor="let product of products" style="margin-top:10px;">
      <mat-card-header>
          <mat-card-title>#{{product.id}} {{product.name}}</mat-card-title>
          <mat-card-subtitle>{{product.price}} $/ {{product.quantity}}
          </mat-card-subtitle>
      </mat-card-header>
      <mat-card-content>
          <p>
              {{product.description}}
          </p>
          <img style="height:100%; width: 100%;" src="{{ product.imageUrl }}" />
      </mat-card-content>
      <mat-card-actions>
    <button mat-button> Buy product</button>
  </mat-card-actions>
  </mat-card>
</div>
<div>
  <button (click) ="firstPage()" mat-button> First</button>
  <button (click) ="previousPage()" mat-button> Previous</button>
  <button (click) ="nextPage()" mat-button> Next</button>
  <button (click) ="lastPage()" mat-button> Last</button>
</div>

これは、アプリケーションのスクリーンショットです。

ステップ14 — Angular HttpClient v9 で型指定されたHTTP応答を要求する

この手順では、サンプルアプリケーションで型指定された HTTP 応答を使用する方法について説明します。

Angular HttpClient を使用すると、要求オブジェクトで応答オブジェクトのタイプを指定できるため、応答を簡単かつ簡単に使用できます。 これにより、コンパイル時に型アサーションも有効になります。

まず、必要なプロパティを備えた TypeScript インターフェースを使用してカスタムタイプを定義します。

コマンドラインインターフェイスに戻り、プロジェクトのルートから次のコマンドを実行します。

$ ng generate interface  product

次に、 src/app/product.ts ファイルを開き、次のように更新します。

export interface Product {
    id: number;
    name: string;
    description: string;
    price: number;
    quantity: number;
    imageUrl: string;
}

次に、データサービスで HttpClient.get() 呼び出しのtypeパラメーターとしてProduct インターフェースを指定します。 src/app/data.service.ts ファイルに戻って、 Product インターフェースをインポートします。

import { Product } from './product';

次:

public sendGetRequest(){
  return this.httpClient.get<Product[]>(this.REST_API_SERVER,
        {  params: new HttpParams({fromString: "_page=1&_limit=20"}), observe: "response"})
        .pipe(retry(3), catchError(this.handleError), tap(res => {
    console.log(res.headers.get('Link'));
    this.parseLinkHeader(res.headers.get('Link'));
  }));
}

public sendGetRequestToUrl(url: string){
  return this.httpClient.get<Product[]>(url, { observe: "response"})
    .pipe(retry(3), catchError(this.handleError), tap(res => {
    console.log(res.headers.get('Link'));
    this.parseLinkHeader(res.headers.get('Link'));
  }));
}

次に、 src/app/home/home.component.ts ファイルを開き、 Product インターフェイスをインポートします。

import { Product } from '../product';

次に、 products 配列のタイプを次のように変更します。

export class HomeComponent implements OnInit, OnDestroy {  
  products: Product[] = [];

次に、 sendGetRequest() 呼び出しでHTTP応答のタイプを変更します。

ngOnInit() {    
  this.dataService.sendGetRequest()
    .pipe(takeUntil(this.destroy$)).subscribe((res: HttpResponse<Product[]>) => {
      console.log(res);
      this.products = res.body;
    })
}

他の firstPage()previousPage()nextPage()lastPage() メソッドについても同じことを行う必要があります。

ステップ15 — Angular 9 アプリケーションを Firebase Hosting にビルドおよびデプロイする

この手順では、 Angular 8.3 以降で使用可能な ng deploy コマンドを使用して、サンプルアプリケーションをビルドして Firebase ホスティングにデプロイする方法を説明します。

fake JSON サーバーなしでフロントエンドアプリケーションをデプロイする方法のみを見ていきます。

Angular CLI 8.3+ では、プロジェクトに関連付けられた deploy CLI ビルダーを使用して、Angularアプリケーションを以前より簡単にデプロイできる新しい ng deploy コマンドが導入されました。さまざまなプラットフォームに展開機能を実装するサードパーティビルダーが多数あります。 ng add コマンドを実行して、プロジェクトにそれらを追加できます。

展開パッケージを追加すると、選択したプロジェクトの展開セクションでワークスペース構成(つまり、 angular.json ファイル)が自動的に更新されます。 その後、 ng deploy コマンドを使用して、そのプロジェクトをデプロイできます。

プロジェクトを Firebase ホスティングに展開することで、例を見てみましょう。

コマンドラインインターフェイスに戻り、 Angular プロジェクトのルートフォルダ内にいることを確認して、次のコマンドを実行します。

$ ng add @angular/fire

これにより、Firebase 展開機能がプロジェクトに追加されます。

このコマンドは、次のセクションを追加して、プロジェクトの package.json も更新します。

"deploy": {
          "builder": "@angular/fire:deploy",
          "options": {}
        }

CLIは、ここに認証コードを貼り付けるように求めます。デフォルトのWebブラウザーを開き、Firebase アカウントを管理するための Firebase CLI 権限を付与するように求めます。

Firebase アカウントに関連付けられた Google アカウントでログインすると、認証コードが付与されます:

次に、プロンプトが表示されます:プロジェクトを選択してください:(矢印キーまたはタイプを使用して検索します)。 前に Firebase プロジェクトを作成しておく必要があります。

CLIは firebase.json および .firebaserc ファイルを作成し、それに応じて angular.json ファイルを更新します。

次に、次のコマンドを使用して、アプリケーションを Firebase にデプロイします。

$ ng deploy

このコマンドは、アプリケーションの最適化されたビルド( ng deploy --prod コマンドと同等)を生成し、実稼働アセットを Firebase ホスティングにアップロードします。

結び:

この Angular 9 チュートリアルを通して、最新バージョンを使用した完全な Angular アプリケーションの実例を作成しました。

要約すると、 HttpClient を設定し、 HttpClient.get() メソッドを使用してパラメーターを指定して HTTP GET リクエストを送信する方法、 RxJS throwError() および catchError() を使用して HTTPエラーを処理する方法、 takeUntil() を使用してキャンセルされた HTTP リクエストの RxJS Observables から、 retry() で失敗したリクエストを再試行し、最後に Angular 8.3+ から利用可能な最新の ng deploy 機能を使用してアプリケーションを Firebase ホスティングにデプロイする方法

著者について

Ahmed Bouchefraは、5年以上の経験を持つWeb開発者であり、ソフトウェア開発の工学学位を持つ技術著者です。 上記のリンクをクリックして彼を雇うか、LinkedInアカウントから彼に連絡することができます。 彼は、SitePoint、Smashing、DigitalOcean、RealPython、freeCodeCamp、JScrambler、Pusher、Auth0などの業界をリードするWebサイトの技術コンテンツを作成しました。 彼はまた、AmazonLeanpub から入手できる最新のWeb開発に関するさまざまな本を共著しています。

当初、2019年12月5日にhttps://www.techiediaries.com で公開されました。


翻訳は以上です。
明日は、 k_nao さんです。

11
11
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
11