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

![ng9-1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28875/de2d737f-d222-0239-2c3d-0bb1e53268c5.jpeg)

## [Angular #2 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/angular-2) | [15日目]()
[Medium Blog](https://medium.com/) の [Angular 9/8 Tutorial: Build a Web App with HttpClient and RxJS](https://itnext.io/angular-9-8-tutorial-build-a-web-app-with-httpclient-and-rxjs-d76a262297b)
の翻訳です。

この 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 では使用できません。

この[チュートリアル](https://www.techiediaries.com/angular-tutorial-example-rest-api-httpclient-get-ngfor)では、 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サイト](https://nodejs.org/downloads)のダウンロードページにアクセスして、オペレーティングシステムのバイナリをダウンロードするだけです。  
  パッケージマネージャを使用してNodeをインストールする方法については、特定のシステム手順を参照することもできます。   
  ただし、推奨される方法は、[NVM](https://github.com/nvm-sh/nvm) — Node Version Manager — POSIX準拠のbashスクリプトを使用して、複数のアクティブなNode.jsバージョンを管理することです。

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

以前の前提条件が整った時、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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28875/c1273700-d6ea-4dc1-8d41-167093653a27.jpeg)

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

```bash
$ npm install -g @angular/cli@next
```

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

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

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

```bash
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 サンプルプロジェクトの初期化

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

```bash
$ cd ~
$ ng new angular-httpclient-example
```

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

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

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

```bash
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
```

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

```bash
$ cd angular-httpclient-example
$ ng serve
```

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

![rxjs-02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28875/9a26394a-d9c8-a233-4495-86c4c3bfc0b6.jpeg)

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

![rxjs-03.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28875/4cb77c6c-c703-b1ca-c148-cb213ff3e772.jpeg)

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

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

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

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

サードパーティのREST APIサーバーからJSONデータを消費または取得することもできますが、この例では、fake REST APIを作成することを選択します。 
実際のREST APIの例については、この[チュートリアル](https://www.techiediaries.com/angular-tutorial-example-rest-api-httpclient-get-ngfor)をご覧ください。 
Angular に関する限り、fake API と実際の REST API の使用に違いはありません。

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

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

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

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

```bash
$ mkdir server
$ cd server
```

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

```JSON
{
    "products": []
}
```

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

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

```bash
$ cd ..
$ npm install faker --save
```

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

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

```javascript
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の偽エントリを作成しました。
[利用可能なすべての方法を確認してください。](https://github.com/marak/Faker.js/#api-methods)
最後に、データベースオブジェクトを文字列に変換し、標準出力に記録しました。

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

```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"
  },
```

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

```bash
$ npm run generate
```

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

```bash
$ npm run server
```

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

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

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

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

例：

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

> 注：フィルタ、ソート、順序付けなどの他の機能を使用できます。 
> 詳細については、[ドキュメント](https://github.com/typicode/json-server)をご覧ください。

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](https://code.visualstudio.com/) を使用します。

次に、 `src/app/app.module.ts` ファイルを開き、 [HttpClientModule](https://angular.io/api/common/http/HttpClientModule#description) をインポートして、次のようにモジュールの `imports` 配列に追加します。

```typescript
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 コンポーネントの作成に進みます。

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

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

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


```bash
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 コンポーネントを作成しましょう。

```bash
$ ng generate component about
```

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

```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 を追加します。

```typescript
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](https://material.angular.io/) は、開発者がプロフェッショナルなUIを作成できるMaterial Designコンポーネントを提供します。 Angular CLI v7 +の新しい `ng add` コマンドを使用すると、プロジェクトで Angular Material を簡単に設定できます。

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

```bash
$ ng add @angular/material
```

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


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

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


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

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

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

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

- [MatToolbar](https://material.angular.io/components/toolbar/overview) ヘッダー、タイトル、またはアクションのコンテナーを提供する。
- [MatCard](https://material.angular.io/components/card/overview) 単一の件名のコンテキストでテキスト、写真、およびアクションのコンテンツコンテナーを提供する。
- [MatButton](https://material.angular.io/components/button/overview) マテリアルデザインのstyling と ink ripples で強化されたネイティブの `<button>` または `<a>` 要素を提供する。
- [MatProgressSpinner](https://material.angular.io/components/progress-spinner/overview) 進行状況とアクティビティの円形インジケータを提供する


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

```typescript
@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` ファイルを開き、次のように更新します。

```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 サービスを生成します。 コマンドラインインターフェイスに戻り、次のコマンドを実行します。

```bash
$ ng generate service data
```

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

```typescript
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()` メソッドを追加します。

```typescript
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);
  }
}
```

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

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

```typescript
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` ファイルを開き、次のように更新します。


```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` ファイルを開き、それに応じて更新します。

```typescript

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](https://angular.io/guide/http#http-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()` 演算子をインポートします。


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

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

```typescript
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()](https://rxjs.dev/api/operators/takeUntil) は、通知オブジェクトObservable が値を発行するまで、ソース Observable が発行した値を発行します。

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

[How to cancel/unsubscribe all pending HTTP requests angular 4+.](https://stackoverflow.com/questions/46068908/how-to-cancel-unsubscribe-all-pending-http-requests-angular-4)をご覧ください。

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

```typescript
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 チュートリアルの次のステップでは、 `HttpClient` の `get()` メソッドでURLクエリパラメーターを使用する方法について説明します。

### ステップ12 — HttpClient get() メソッドに URL クエリパラメーターを追加する
このステップでは、サンプルアプリケーションにページネーションを実装するためのロジックの追加を開始します。  [fromString](https://angular.io/guide/http#use-fromstring-to-create-httpparams) および [HttpParams](https://angular.io/guide/http#use-fromstring-to-create-httpparams) を介してURLクエリパラメーターを使用して、ページ分割されたデータを取得するための JSON REST API サーバーの `/products` エンドポイントの `_page` および `_limit` パラメーターに適切な値を提供する方法について説明します。

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

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

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

```typescript
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));
}
```

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

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

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

### ステップ13 — Angular HttpClient v9 で完全なHTTPレスポンスを取得する
このサイトでは、JSON REST API サーバーから受信した HTTP 応答に含まれる Link ヘッダーからページネーション情報を取得するロジックを実装することから始めます。

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

> HTTPのLinkヘッダーを使用すると、サーバーは、要求されたリソースに関するメタデータを含む別のリソースに関心のあるクライアントをポイントできます。 [Wikipedia](https://www.w3.org/wiki/LinkHeader)

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

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

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

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

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

```typescript
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()` を次のように更新します。


```typescript
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` をインポートするようにホームコンポーネントを更新する必要があります。

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

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

```typescript
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 ファイルに戻り、次のメソッドを追加します。


```typescript
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` ファイルに戻り、次のメソッドを定義して追加します。

```typescript
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` ファイルを開いて追加し、次のようにテンプレートを更新します。

```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 インターフェースを使用してカスタムタイプを定義します。

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

```bash
$ ng generate interface  product
```

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

```typescript
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` インターフェースをインポートします。

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

次：

```typescript
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` インターフェイスをインポートします。

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

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

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

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

```typescript
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 プロジェクトのルートフォルダ内にいることを確認して、次のコマンドを実行します。

```bash
$ ng add @angular/fire
```

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

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

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

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

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

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

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

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

```bash
$ 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](https://www.techiediaries.com/author/ahmed/)は、5年以上の経験を持つWeb開発者であり、ソフトウェア開発の工学学位を持つ技術著者です。 上記のリンクをクリックして彼を雇うか、[LinkedInアカウント](https://www.linkedin.com/in/mr-ahmed/)から彼に連絡することができます。 彼は、SitePoint、Smashing、DigitalOcean、RealPython、freeCodeCamp、JScrambler、Pusher、Auth0などの業界をリードするWebサイトの技術コンテンツを作成しました。 彼はまた、[Amazon](https://www.amazon.com/Ahmed-Bouchefra/e/B07J1XYKT4?ref=dbs_a_def_rwt_hsch_vu00_taft_p1_i0) や [Leanpub](https://leanpub.com/u/ahmedbouchefra) から入手できる最新のWeb開発に関するさまざまな本を共著しています。

- [Website](https://www.ahmedbouchefra.com/)
- [Twitter](https://twitter.com/ahmedbouchefra)
- [LinkedIn](https://www.linkedin.com/in/mr-ahmed/)
- [GitHub](https://github.com/techiediaries)

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

----
翻訳は以上です。
明日は、 [k_nao](https://qiita.com/k_nao) さんです。