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