FetchAPIとは
Fetch APIとは、クライアント側からサーバー側へ非同期通信(HTTPリクエストを送った後、レスポンスが返ってくるのを待たずに、他の作業を並行して進めること)を行うための標準的な仕組み(Web API)です。具体的には、ブラウザが提供している機能で、JavaScriptがfecth()メソッドを使うことで呼び出します。
以前は非同期通信を実現するためにXMLHttpRequestという仕組みが使われていましたが、よりシンプルで強力な後継としてFetch APIが登場しました。
両者の違いは以下のGETリクエストの例を見れば可読性の違いが見て取れると思います。
// 1. インスタンスの作成
var xhr = new XMLHttpRequest();
// 2. 通信設定
xhr.open('GET', 'https://api.example.com/data', true);
// 3. 成功時・失敗時の処理をイベントハンドラで記述
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) {
// 自分でJSONパースが必要
var data = JSON.parse(xhr.responseText);
console.log('成功:', data);
} else {
console.error('サーバーエラー:', xhr.status);
}
};
xhr.onerror = function() {
console.error('ネットワークエラーが発生しました');
};
// 4. リクエスト送信
xhr.send();
async function getData() {
try {
// 1. 通信開始(設定と送信が1行で完結)
const response = await fetch('https://api.example.com/data');
// 2. HTTPエラーのチェック
if (!response.ok) throw new Error(response.status);
// 3. JSONパース(メソッドとして用意されている)
const data = await response.json();
console.log('成功:', data);
} catch (error) {
// 4. ネットワークエラーと上記throwの両方をキャッチ
console.error('エラー:', error);
}
}
getData();
FetchAPIの特徴
1. Promiseベース
Fetch API最大の特徴は、JavaScriptの非同期処理であるPromiseを前提に設計されていることです。具体的には、FetchAPIで使われるfetch関数はPromise型(のオブジェクト)を扱います。実行したら「とりあえず」 Promise型を返し、中身は後で届くことを約束するため、次のコードに進むことができ、非同期処理を実現します。
Promiseは以下3つのステータスを持ちます。
- Pending: 待機(まだ結果が出ていない「進行中」の状態)
- Fulfille: 完了(通信が完了し、「値」が手に入った状態)
- Rejected: 拒否(何らかの問題で通信ができず、拒否された理由が出た状態)
2. 「2段階」のデータ取得
Fetch APIのデータ取得は2段階に分かれています。分かりやすく例えると「手紙(レスポンス)が届く」ことと、「その封筒を開けて中身(ボディ)を読む」といったイメージです。
第1段階:fetch() — ヘッダーの受信
fetch() メソッドを実行すると、ブラウザはまずサーバーと接続し、情報のヘッダーだけを先に受け取ります。
- タイミング
サーバーから「OKです(200)」や「見つかりません(404)」という返事の第一弾が届いたとき。 - 確認できること
response.ok: 通信が成功したか。
response.status: ステータスコード(200, 404など)。
response.headers: データの形式(JSONか画像か)やサイズ。
第2段階:.json() など — ボディの受信と解析
第1段階で「この通信は成功だ」と確認できたら、次にデータの中身を取り出すメソッド(.json()や.text()など)を呼び出します。
- タイミング
.json() などを実行し、データの全断片が届き、解析が終わったとき。 - 内部での動き
細切れに流れてくるデータ(ストリーム)を最後まで受け取る。届いた「ただの文字列」を、JavaScriptで扱える「オブジェクト」に変換する。
3. リクエストとレスポンスの「オブジェクト化」
Fetch APIは、通信の要素をオブジェクト(Promise型)として扱います。具体的にはリクエスト、レスポンス、更にそれらに付帯するHeaderもオブジェクト型になります。
FetchAPIの通信ライフサイクル
FechAPIは単に「投げて、受け取る」だけではなく、ブラウザ内部で以下のような処理に分かれています。
1. Promiseの生成とリクエストの構築
fetch() を呼び出すと、ブラウザは即座にPromiss型オブジェクトを作成して返します。ブラウザは引数で渡されたURLやオプション(メソッド、ヘッダーなど)を解析し、HTTPリクエストの準備をします。この時点ではまだ通信は始まっておらず、JavaScript側は「将来、結果を返すよ」という予約チケットを受け取った状態です。
2. HTTPリクエストの送信(バックグラウンド)
JavaScriptのメイン処理とは別に、ブラウザの「ネットワークスレッド」が実際の通信を開始します。具体的には、DNS解決(ドメインをIPアドレスに変換)、TCP接続、TLSハンドシェイク(暗号化の確立)などが行われ、サーバーにデータが送られます。この間、JavaScriptの他のコードは止まることなく動き続けます。
3. レスポンスヘッダーの受信(第1の解決)
サーバーからデータの「最初の断片(ヘッダー)」が届いた瞬間に、fetch()メソッドが完了します。具体的には、ステータスコード(200 OK, 404など)や、コンテンツの種類(Content-Type)などのヘッダー情報を持つResponseオブジェクトを返します。
注意: この時点では、データ本体(Body)はまだ届き終わっていないことがほとんどです。
4. ボディデータの受信とストリーミング(第2の解決)
次に、.json() や .text() を実行することで、データ本体(ボディ)の読み込みを開始します。サーバーから送られてくる大きなデータを、ブラウザは細切れの「ストリーム」として受け取ります(ストリーミング処理)。全データが届き次第、指定された形式(JSONオブジェクトなど)に変換します。
5. 通信の完了とクリーンアップ
データがJavaScript側に渡されると、ライフサイクルは終了します。ブラウザはコネクションを閉じたり、一時的なメモリを解放したりします(クリーンアップ)。
FechAPIの仕様
Request(リクエスト)オブジェクト
fetch() メソッドはブラウザからHTTP リクエストを送るための関数で、fetch()メソッドを使ってRequestオブジェクトを送信します。
構文: fetch(resource, options)
- resource: 取得したいURL、またはRequestオブジェクト
- options (任意): リクエストの詳細設定
代表的なオプションは以下になります。
* url: 送信先のURL
* method: メソッド(GET, POST, DELETEなど)
* headers: 関連付けられたHeadersオブジェクト
* bodyUsed: bodyが既に読み取られたかどうかのフラグ
* mode: クロスドメイン(CORS)などのモード設定
* credentials: クッキーを送信するかどうかの設定
fetchの使われ方として、Requestオブジェクトを事前に準備する方法と直接引数に書く方法の二つがあります。
事前に準備する方法:
const myRequest = new Request('https://api.example.com/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer my-token'
},
body: JSON.stringify({ name: 'Taro' })
});
// 送信するときは、このオブジェクトを fetch に渡すだけ
fetch(myRequest)
直接書く方法(より一般的):
// URL文字列と、各種設定をそのまま引数に指定します。
fetch('https://api.example.com/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer my-token'
},
body: JSON.stringify({ name: 'Taro' })
})
Response(レスポンス)オブジェクト
サーバーから返ってきた「結果」を表すオブジェクトです。主に以下二つの要素を使って処理を行います。
1. 通信結果を知るための「プロパティ」
Responseオブジェクトは以下のようなプロパティを持ちます。これらのプロパティを使ってサーバーからの返信内容を確認します。
-
response.ok: 成功フラグ
(ステータスコードが200〜299ならtrue、それ以外ならfalse) -
response.status: ステータスコード
(200(成功), 500(サーバーエラー) などの数値) -
response.statusText: ステータスメッセージ
(OKやNot Foundなどの文字列) -
response.url: 最終的なURL
(リダイレクトがあった場合、最終的に辿り着いたURL) -
response.headers: レスポンスヘッダー
(サーバーが返してきた情報の詳細)
2. データを取り出すための「Bodyメソッド」
Responseオブジェクトそのものは、まだ「生」のデータです。私たちが使いやすい形式に変換するために、専用のメソッドを呼び出す必要があります。以下が代表的なメソッドです。
- response.json(): 中身をJSONとして解析し、JavaScriptのオブジェクト(または配列)に変換します。API通信で最も使われます。
- response.text(): 中身を単純な文字列として取り出します。HTMLやCSVなどを取得する際に使います。
- response.blob(): 画像やファイルなどのバイナリデータ(Blob)として取り出します。
- response.formData(): フォーム形式のデータとして取り出します。
注意: レスポンスのボディは「ストリーム(流体)」として扱われます。一度読み取ると空っぽになってしまうため、同じレスポンスに対して .json() を2回実行することはできません。
.then()とasync/await
非同期処理が終わった後に何をするかを書く方法は、.then()を使った方式とasync/awaitを使った方式の2つがあります。
1. then方式
「これが終わったら、次はこれをやってね」という予約票を次々に渡していくスタイルです。
- .then(): 非同期処理が完了した(Fulfille)時に、次にやってほしいことを指定する
- .chatch(): 非同期処理が失敗した(Rejected)時に、次にやってほしいことを指定する(また、その他のthrowされた例外も扱う)。
// 「fetchが終わったら(then)、jsonにして、終わったら(then)、表示して」
fetch('url')
.then(res => res.json())
.then(data => console.log(data))
.catch(error => {
console.error("通信に失敗しました:", error);
});
2. async/await方式
「終わるまでここで待つ」と指示して、完了まで待機するスタイルです。読みやすく、現在はこの書き方が主流です。
async(アシンク): 「この関数は非同期処理を含みますよ」という宣言で、関数をPromiseを返す特別な関数に変えます。
await(アウェイト): async 関数の中だけで使えるキーワードで、「Promiseの結果が出るまで、ここで一時停止して待つ」という指示です
// 「fetchが終わるのを待って(await)、jsonになるのを待って(await)、表示」
async function getData() {
try {
const res = await fetch('url');
const data = await res.json();
console.log(data);
} catch (error) {
console.error("通信に失敗しました:", error);
}
}
実例
1. GETリクエストの例
サーバーから情報を「取ってくる」とき(GET)の書き方です。
async function getUserData() {
try {
// 1. 通信開始(レスポンスヘッダーが届くまで待機)
const response = await fetch('https://jsonplaceholder.typicode.com/users/1');
// 2. 成功判定(ステータスが200番台かチェック)
if (!response.ok) {
throw new Error(`HTTPエラーです: ${response.status}`);
}
// 3. データの解析(中身が全部届くまで待機)
const data = await response.json();
console.log("取得したデータ:", data);
} catch (error) {
// 4. 失敗時の処理(ネット切れや上記のthrowをキャッチ)
console.error("失敗しました:", error.message);
}
}
getUserData();
2. POSTリクエストの例
サーバーに新しい情報を「登録する・送る」とき(POST)の書き方です。
async function createPost() {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST', // 1. 送信方法を指定
headers: {
'Content-Type': 'application/json' // 2. 「中身はJSONですよ」とHeadersで伝える
},
body: JSON.stringify({
title: 'こんにちは',
body: 'これはテスト投稿です',
userId: 1
}) // 3. 送りたいデータをJSON文字列にしてBodyに入れる
});
if (!response.ok) {
throw new Error('送信に失敗しました');
}
const result = await response.json();
console.log("送信成功!サーバーからの返事:", result);
} catch (error) {
console.error("エラー:", error);
}
}
createPost();