Fetch API を使うときの適切なエラー処理方法

3 min read読了の目安(約2700字

TL;DR

Fetch API を使うときの簡単なエラー処理

まずは簡単なサンプルコードです。
エラーの処理はサービスごとにそれぞれやるべきことがあると思うので、
今回のサンプルコードでは一律 console.error() だけにしてあります。

fetch('http://example.com/movies.json', {
    method: 'GET'
  })
  .then(response => {
    if (!response.ok) {
      console.error('サーバーエラー');
    }
    // ここに成功時の処理を記述
  })
  .catch(error => {
    console.error('通信に失敗しました', error);
  });

の 「fetch が成功したかチェックする」の頁に書いてあるエラー処理は
だいたい上記のような感じですね。

ネットワークエラーに遭遇すると fetch() promise は TypeError を返して reject 状態になります。サーバー側の CORS が適切に設定されていない場合も同様です(アクセス権の問題ですけどね) — 一方で例えば 404 はネットワークエラーを構成しません。fetch() が成功したかどうかの明確な判定をするには、プロミスが解決されて、Response.ok (en-US) プロパティが true になっているかなどを確認します。次のようなコードになるでしょう。

と書いてあります。
response.ok が何を示すのかは Response についての記述の部分に書いてあり、

Response.ok (en-US) 読取専用
レスポンスが成功(200-299 の範囲のステータス)したか否かを通知する boolean 値を含む。

と記述されています。

Fetch API の Promise reject だけを見るのではダメなのか?

Fetch API は Promise を返すので
一見 catch さえしてあればエラー処理ができそうではあります。
しかし、引用に書いたように Fetch API はネットワークエラーに遭遇したときに reject になります。
逆にいえば、ネットワークエラーにはならずにサーバーエラー(HTTP 5xx など)の場合は
Promise は reject にならずに処理されるのです。

まとめると Fetch API は

  • ネットワーク通信に失敗したときに catch が動く
  • リクエストが失敗したか(response.status が 200-299 の範囲でなかったか)どうかは response.ok を確認してやる必要がある
  • !response.ok のとき、さらに詳細な情報が必要な場合は適宜 response.statusresponse.statusText などを参照してやる必要がる

ということです

catch で全てのエラー処理をしたいんだが?

Promise の中で throw new Error() してやればその時点で catch してくれますね。
なのでさっきのサンプルコードならこんな感じになります。

fetch('http://example.com/movies.json', {
    method: 'GET'
  })
  .then(response => {
    if (!response.ok) {
      console.error('response.ok:', response.ok);
      console.error('esponse.status:', response.status);
      console.error('esponse.statusText:', response.statusText);
      throw new Error(response.statusText);
    }
    // ここに成功時の処理を記述
  })
  .catch(error => {
    // ネットワークエラーでも !response.ok でもここで処理できる
    console.error('エラーが発生しました', error);
  });

簡単ですね。今回はここまでです。