fetch 入門
json を取得するまで。
fetch とは
Webサーバからリソースを取得する工程を開始して、promise オブジェクトを返す。
fetch を使用してみる
CodePen が手軽で確認しやすい。
console.log()で結果を確認していく。
fetch() の戻り値
- 第1引数は取得したいリソース。
- 今回は天気予報APIを使わせてもらう。
- https://weather.tsukumijima.net/
const promise = fetch('https://weather.tsukumijima.net/api/forecast/city/250010');
console.log(promise);
// 結果: Promise オブジェクトが返される.
Promise {<pending>}
pending は状態を示している。
そのままで待機中の状態を指している。
サイトによっては読み取り処理が進行中とも書かれている。
Promise の中を確認
Promise をクリックして中身を確認してみる。
[[PromiseState]]: "fulfilled" が確認できる。
fulfilled は非同期処理が成功しているときの状態。
次に引数のURLを適当なもの(http://localhost)に変更すると
[[PromiseState]]: "rejected" が確認できる。
rejected は非同期処理が失敗しているときの状態。
pending から fulfilles または rejected に状態が変化する。
ハンドラーを使用して更に処理をすすめる
Promise の状態によって呼び出される関数が変わる。
成功(fulfilled)であれば then()ハンドラーが呼び出され、
失敗(rejected)であれば catch()ハンドラーが呼び出される。
それぞれ確認してみる。
成功バージョン
then()メソッドを使用する。
使用するとthen()の引数に Response オブジェクトが渡る。
const promise = fetch('https://weather.tsukumijima.net/api/forecast/city/250010');
// ここから続き
promise
.then(response => {
console.log(response);
});
// 結果: Response オブジェクトが引数に渡る.
Response{...}
値として返るわけでなく、引数として渡るため若干違和感があるけど、こういうものという理解で。
失敗バージョン
catch() を使用する。
catch()はエラーが引数に渡る。
// 適当なURLを設定
const promise = fetch('http://localhost');
promise
// then を catch に書き換える. 引数も error に変更.
.catch(error => {
console.log(error);
});
// 結果: エラーメッセージが確認できる.
TypeError: Failed to fetch
失敗と聞くと 404 Not Found や 500 Internal Server Error 等も含まれるように感じるがそうではない。この場合は then() が呼び出される。
今回のlocalhostのように存在しないドメインにfetch()をしてもWebサーバーにアクセスできず、Webサーバーからレスポンスが返ってこない。
そのような場合にcatch()ハンドラーが呼び出される。
404 の動きは後で確認する。
チェーンで処理を繋げる。
ここまでの処理を繋げる。
// 正規のURLを設定
const promise = fetch('https://weather.tsukumijima.net/api/forecast/city/250010');
promise
.then(response => {
console.log(response);
})
.catch(error => {
console.log(error);
});
Promise の状態によって呼び出されるハンドラーが異なるため、競合は起こらない。
そのためハンドラーで処理をわけることができる。
次は then()の引数に渡った Response オブジェクトを確認していく。
Response オブジェクト
Response オブジェクトとは
サーバーのレスポンスが格納されたオブジェクト。
Response オブジェクトを確認
MDNにプロパティとメソッド一覧がある。
ok プロパティを確認してみる。
const promise = fetch('https://weather.tsukumijima.net/api/forecast/city/250010');
promise
.then(response => {
// ok を追加.
console.log(response.ok);
})
.catch(error => {
console.log(error);
});
// 結果
true
ok プロパティはHTTPステータスコードが 200-299 の成功レスポンスで true となる。
Response オブジェクトで 404 に対応する
このokプロパティを使用すれば先程の 404 等を判別できる。
今回はドメインは正規のものを使用し、以下適当なパスに変更し 404 を確認する。
const promise = fetch('https://weather.tsukumijima.net/api/foreca/250010');
promise
.then(response => {
console.log(response.ok);
})
.catch(error => {
console.log(error);
});
// 結果
false
catch()は呼び出されず、 then()が呼び出されている。
また、 200-299 以外なので false が返される。
ということで条件分岐を追加して処理を分けてみる。
ついでに Responseオブジェクトの json() メソッドも確認する。
const promise = fetch('https://weather.tsukumijima.net/api/forecast/city/250010');
promise
.then(response => {
if (response.ok) {
// json を追加.
console.log(response.json());
return response.json();
}
// 200-299 以外の処理.
throw new Error(`リクエストエラー ${response.status}`);
})
.catch(error => {
console.log(error);
});
// 結果: Promise オブジェクトが返される.
Promise
また Promise が返ってきた。
Response オブジェクトのMDNを確認すると json() によって Promise を返すと記載されている。
Promise の処理を進めるにはまた then() を使って処理を進める必要がある。
先に 404 の確認をしておく。
// ドメインはそのままで適当なパスに変更する.
const promise = fetch('https://weather.tsukumijima.net/api/fo/city/250010');
promise
.then(response => {
if (response.ok) {
console.log(response.json());
return response.json();
}
throw new Error(`リクエストエラー ${response.status}`);
})
.catch(error => {
// message プロパティで投げられたエラーメッセージを標示する.
console.log(error.message);
});
// 結果
リクエストエラー 404
このようにして、404 等のエラーは条件分岐で処理する必要がある。
Promise オブジェクトを処理する
Response オブジェクトは json() メソッドによって Promise オブジェクトを返すことがわかった。
同様に then() で チェーンを繋ぐと、また引数に何かしらの値が渡る。
promise
.then(response => {
if (response.ok) {
return response.json();
}
throw new Error(`リクエストエラー ${response.status}`);
})
// 引数を data とする.
.then(data => {
console.log(data);
})
.catch(error => {
console.log(error);
});
// 結果: json のデータが出力される.
{publicTime: '2023-01-20T20:00....'}
ようやく json のデータが取得できた。
表示してみる。
<div id="app"></div>
const promise = fetch('https://weather.tsukumijima.net/api/forecast/city/250010');
promise
.then((response) => {
if (response.ok) {
return response.json();
}
throw new Error(`リクエストエラー ${response.status}`);
})
.then((json) => {
const { forecasts } = json;
const today = forecasts[0];
const output = `
<section>
<img src="${today.image.url}" alt="${today.image.title}" width="${today.image.width}" height="${today.image.heght}"/>
<div>
<span>${today.temperature.max.celsius}° ${today.temperature.min.celsius}</span>
</div>
<ul>
<li>0-6: ${today.chanceOfRain.T00_06}</li>
<li>6-12: ${today.chanceOfRain.T06_12}</li>
<li>12-18: ${today.chanceOfRain.T12_18}</li>
<li>18-24: ${today.chanceOfRain.T18_24}</li>
</ul>
</section>
`;
const app = document.getElementById("app");
app.innerHTML = output;
})
.catch((error) => {
console.log(error);
});
終わります。
追記
成功レスポンス以外では throw を使っていたが、複雑な処理ではPromise.reject()を使用したほうが良い。
本来のエラーなのかスローされたエラーなのか判別がつかないから。
具体的には下記のようになる。
promise
.then(response => {
if (response.ok) {
return response.json();
}
// ここを promise.reject() に変更.
promise.reject(`リクエストエラー ${response.status}`);
})
.then(data => {
console.log(data);
})
.catch(error => {
console.log(error);
});
// 結果: json のデータが出力される.
{publicTime: '2023-01-20T20:00....'}
参考サイト
フェッチAPI: https://developer.mozilla.org/ja/docs/Web/API/Fetch_API
fetch(): https://developer.mozilla.org/ja/docs/Web/API/fetch
プロミス: https://developer.mozilla.org/ja/docs/Learn/JavaScript/Asynchronous/Promises
Request: https://developer.mozilla.org/ja/docs/Web/API/Request
Discussion