Dev Study
← Angular コース

47. HTTPエラーへの備え — catchError と status

通信はサーバーの障害やネットワークの切断でかならず失敗することがあります。RxJSの catchError オペレーターを pipe に挟むと、エラーが起きたときの代替処理を流れの中に組み込めます。catchError(() => of([])) のように of で代替値を返せば、流れはエラーで止まらず「空の結果が届いた」ことにして画面を守れます。

エラーの内容は HttpErrorResponse で受け取れ、status プロパティで原因を見分けます。0 はサーバーに到達すらできなかったネットワーク断、404 はリソースが見つからない、500 はサーバー内部のエラーです。実務では status に応じて「通信環境を確認してください」「データが見つかりません」のようにユーザーへの通知メッセージを出し分けます。

つまずきやすいのは、エラー処理を「あとで足すもの」と考えてしまうことです。エラーは必ず起きるものとして、読み込み中・成功・失敗の3状態を最初から画面の設計に含めましょう。また catchError を pipe のどこに置くかでも動きが変わります。リクエストの直後に置けばそのリクエストの失敗だけを処理でき、流れ全体の最後に置けばまとめて処理できます。

サンプルコード(フレームワーク環境が必要なため表示のみ)

import { Component, inject, signal } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { toSignal } from '@angular/core/rxjs-interop';
import { catchError, of } from 'rxjs';

type Order = { id: number; total: number };

@Component({
  selector: 'app-order-history',
  template:
    '@if (message()) { <p>{{ message() }}</p> }' +
    '@for (o of orders(); track o.id) { <p>{{ o.total }} 円</p> }',
})
export class OrderHistoryComponent {
  private http = inject(HttpClient);
  message = signal('');

  orders = toSignal(
    this.http.get<Order[]>('/api/orders').pipe(
      // エラー時は status を見て通知を出し、代替値(空配列)で流れを続ける
      catchError((err: HttpErrorResponse) => {
        if (err.status === 0) {
          this.message.set('通信環境を確認してください');
        } else if (err.status === 404) {
          this.message.set('注文データが見つかりません');
        } else {
          this.message.set('サーバーでエラーが発生しました');
        }
        return of([] as Order[]);
      })
    ),
    { initialValue: [] as Order[] }
  );
}
サンプルコードで身につける(5本) →

学んだ概念を、素朴な例から実務寄りの例まで5つの具体例で確認します。

公式ドキュメントで詳しく ↗