コース一覧
非同期JavaScript:API通信とモジュール
response.ok と失敗時の表示

非同期JavaScript:API通信とモジュール

Promise と async/await、非同期エラー、HTTP/REST、fetch による GET、読み込み・成功・失敗の表示、モジュールの読み方を学ぶ全 19 レッスン(380 分)のコースです。最後は承認済みの読み取り専用 API から作品データを取得して表示します。POST はリクエストの組み立てまでで、外部サービスへの書き込みは行いません。

1
非同期処理
01. 同期と非同期15分
02. Promise をつくって返す20分
03. async と await20分
04. Promise.all で同時に待つ20分
05. 非同期のエラーを捕まえる20分
06. つくる 読み込み中の表示を出す30分
07. 第1章まとめクイズ10分
2
fetch で外のデータを使う
01. HTTP と REST の読みかた15分
02. fetch でデータを取る25分
03. 取ったデータを描画する25分
04. response.ok と失敗時の表示25分
05. POST のリクエストを組み立てる20分
06. つくる 作品データを API から読む30分
07. 第2章まとめクイズ10分
3
モジュールと総仕上げ
01. ファイルを分けるという考えかた15分
02. named export と default export15分
03. つくる ポートフォリオアプリを仕上げる40分
04. ここから先の学びかた15分
05. 第3章まとめクイズ10分

response.ok と失敗時の表示

404 でも fetch は成功する
解説

このレッスンで分かること

  • fetch は 404 や 500 が返ってきても失敗扱いにしません
  • response.ok を見て、どこからを失敗と呼ぶかは自分で決めます

500 が返ってきているのに、catch が動かない

try と catch を書いたとき、失敗すれば catch に入るのが当たり前でした。fetch はここが違います。

JavaScript

try { const response = await fetch("https://yumesaku.tech/course-api/works.json?status=500"); const data = await response.json(); console.log("成功しました"); // 500 でもこの行に来る } catch (error) { console.log("失敗しました"); // 来ない }

fetch にとっての失敗は、返事そのものが受け取れなかったときだけです。サーバーが「そんなものは無い」と答えたのも、立派なやりとりの成立なので成功と数えます。それを失敗と呼ぶかどうかは、こちらが決める、という設計になっています。

起きたことfetch の扱いcatch に入るか
200 が返ってきた成功入らない
404 や 500 が返ってきた成功入らない
回線が切れていた失敗入る
本文が JSON になっていない失敗入る

いちばん下は fetch ではなく response.json() が投げます。Unexpected token < という文字を見たら、URL が間違っていて HTML のエラーページを読まされている合図です。

response.ok を見て、自分で失敗にする

判断に使うのが response.ok です。ステータスコードが 200 から 299 のときだけ true になります。

JavaScript

const response = await fetch(url); console.log(response.ok); // 200 なら true、500 なら false console.log(response.status); // 500

ok が false なら、自分でエラーを投げて catch へ流します。

JavaScript

async function showBio(url) { const notice = document.querySelector("#notice"); try { const response = await fetch(url); if (!response.ok) { throw new Error("読み込みに失敗しました (" + response.status + ")"); } const profile = await response.json(); notice.textContent = profile.headline; notice.classList.remove("error"); } catch (error) { notice.textContent = error.message; notice.classList.add("error"); } }

500 で断られた場合も、回線が切れていた場合も、同じ catch にまとまります。利用者にはどちらも「見られなかった」で同じなので、まとめてよい場面です。

throw するときは response.status を文にまぜてください。あとから何が起きたのかを聞くとき、番号があるかないかで分かる量がまるで違います。ただし利用者に見せる文には、内部の言葉をそのまま出さないでください。

解説

ok の確認と try は、どちらか一方では足りません。ok は断られたことを捕まえ、try はそもそも届かなかったことを捕まえます。守っている範囲が違います。

失敗したときこそ、画面を整える

いちばんまずいのは、画面が途中まで描かれた状態で止まることです。読み込み中の表示が残り、一覧は空で、押しても何も起きない画面だけが残ります。

catch の中では、失敗したなりに整った状態へ戻します。エラー文を出すだけでなく、古いカードが残っていれば消します。逆に、やり直して成功したときは、失敗のときに付けた印を外し忘れないでください。赤い文字が残ったまま新しいデータが並ぶと、利用者はどちらを信じてよいか分からなくなります。

やり直せる道も用意しておくと親切です。読み込みを 1 本の関数にまとめてあれば、ボタンからその関数をもう一度呼ぶだけで済みます。

よくある間違い

  • try で囲んだから安心してしまう — ok を見ずに response.json() へ進むと、エラーの JSON を読んで、そこに無いはずの配列を触ったところで落ちます。落ちる場所が本当の原因から離れるので、いちばん追いにくい壊れかたです
  • エラーをコンソールにだけ出す — 利用者の画面には何も起きません。画面に出したうえで、開発者向けの記録も残してください

課題

  1. response.ok が false のとき、response.status を含む文で throw する
  2. catch で #status にエラー文を出し、error クラスを付ける
  3. catch で renderWorks([]) を呼び、一覧を空の状態に戻す
  4. #retry が押されたら OK_URL で読み直し、成功したら件数を出して error クラスを外す

ヒント

fetch は 500 でも catch に入りません。if (!response.ok) を自分で書いて、そこから throw new Error(...) してください。

throw した文は catch の error.message で受け取れます。response.status を文に混ぜておくと、そのまま画面に出せます。

成功したときに classList.remove("error") を忘れると、取り直して成功しても赤い表示が残ります。付けた印は必ず外してください。

index.html
script.js
プレビュー

できているか

  • 失敗したときに番号を画面に出す
  • 失敗が分かる印を付ける
  • もう一度読み込むと一覧が出る
エディタを読み込んでいます