response.ok と失敗時の表示
このレッスンで分かること
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); // 500ok が 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 を読んで、そこに無いはずの配列を触ったところで落ちます。落ちる場所が本当の原因から離れるので、いちばん追いにくい壊れかたです- エラーをコンソールにだけ出す — 利用者の画面には何も起きません。画面に出したうえで、開発者向けの記録も残してください
課題
- response.ok が false のとき、response.status を含む文で throw する
- catch で #status にエラー文を出し、error クラスを付ける
- catch で renderWorks([]) を呼び、一覧を空の状態に戻す
- #retry が押されたら OK_URL で読み直し、成功したら件数を出して error クラスを外す