組み込み関数

JavaScriptのFetch API入門|非同期通信でデータをやり取りする

Fetch APIは、JavaScriptでHTTPリクエストを送信するためのモダンなインターフェースです。XMLHttpRequestの後継として設計され、PromiseベースのシンプルなAPIでサーバーとのデータ通信を行えます。REST APIとの連携で必須の知識です。

基本的な使い方

fetch()はURLを引数に取り、Promiseを返します。レスポンスはResponseオブジェクトで、.json().text()でデータを取得します。

JavaScript
// GETリクエスト(基本)
fetch("https://jsonplaceholder.typicode.com/users/1")
  .then(response => {
    console.log("ステータス:", response.status);
    return response.json();
  })
  .then(data => {
    console.log("名前:", data.name);
    console.log("メール:", data.email);
  })
  .catch(error => {
    console.error("エラー:", error.message);
  });

// async/awaitで書く場合
async function getUser(id) {
  try {
    const response = await fetch(
      `https://jsonplaceholder.typicode.com/users/${id}`
    );
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}`);
    }
    const user = await response.json();
    console.log(user.name);
  } catch (error) {
    console.error("取得失敗:", error.message);
  }
}
実行結果
ステータス: 200
名前: Leanne Graham
メール: Sincere@april.biz

fetch()はネットワークエラー時のみPromiseをrejectします。404や500などのHTTPエラーではrejectされないため、response.okのチェックが重要です。

POST・PUT・DELETEリクエスト

fetch()の第2引数にオプションを渡すことで、POST、PUT、DELETEなどのHTTPメソッドを指定できます。

JavaScript
// POSTリクエスト
async function createPost(title, body) {
  const response = await fetch(
    "https://jsonplaceholder.typicode.com/posts",
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json"
      },
      body: JSON.stringify({ title, body, userId: 1 })
    }
  );
  const data = await response.json();
  console.log("作成:", data);
}

// PUTリクエスト(更新)
async function updatePost(id, title) {
  const response = await fetch(
    `https://jsonplaceholder.typicode.com/posts/${id}`,
    {
      method: "PUT",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ id, title, body: "更新内容", userId: 1 })
    }
  );
  console.log("更新ステータス:", response.status);
}

// DELETEリクエスト
async function deletePost(id) {
  const response = await fetch(
    `https://jsonplaceholder.typicode.com/posts/${id}`,
    { method: "DELETE" }
  );
  console.log("削除ステータス:", response.status);
}
実行結果
作成: { title: "...", body: "...", userId: 1, id: 101 }
更新ステータス: 200
削除ステータス: 200

実践的な活用例

エラーハンドリング、タイムアウト、並列リクエストなど実務で必要なパターンを紹介します。

JavaScript
// 汎用的なfetchラッパー
async function apiRequest(url, options = {}) {
  const defaultOptions = {
    headers: { "Content-Type": "application/json" },
    ...options
  };

  const response = await fetch(url, defaultOptions);

  if (!response.ok) {
    throw new Error(`API Error: ${response.status} ${response.statusText}`);
  }

  return response.json();
}

// タイムアウト付きfetch
async function fetchWithTimeout(url, timeout = 5000) {
  const controller = new AbortController();
  const timeoutId = setTimeout(() => controller.abort(), timeout);

  try {
    const response = await fetch(url, { signal: controller.signal });
    return await response.json();
  } catch (error) {
    if (error.name === "AbortError") {
      throw new Error("リクエストがタイムアウトしました");
    }
    throw error;
  } finally {
    clearTimeout(timeoutId);
  }
}

// 複数のAPIを並列で呼び出し
async function fetchMultiple() {
  const urls = [
    "https://jsonplaceholder.typicode.com/users/1",
    "https://jsonplaceholder.typicode.com/users/2",
    "https://jsonplaceholder.typicode.com/users/3"
  ];

  const results = await Promise.all(
    urls.map(url => fetch(url).then(r => r.json()))
  );
  console.log(results.map(u => u.name));
}
実行結果
["Leanne Graham", "Ervin Howell", "Clementine Bauch"]
AbortControllerでリクエストをキャンセル

AbortControllerを使うと、進行中のfetchリクエストをキャンセルできます。ユーザーがページを離れた時やコンポーネントがアンマウントされた時のクリーンアップに必要です。

注意点

fetch()は404や500でもPromiseを解決します。必ずresponse.okまたはresponse.statusをチェックしてください。また、CORSポリシーにより、異なるオリジンへのリクエストはサーバー側の許可が必要です。機密情報を含むリクエストではcredentials: "include"の設定も検討してください。

まとめ

  • fetch()はPromiseベースのHTTPリクエスト関数
  • HTTPエラーではrejectされないためresponse.okのチェックが必須
  • POST/PUT/DELETEは第2引数のオプションで指定
  • AbortControllerでリクエストのキャンセルやタイムアウトを実装
  • Promise.all()で複数リクエストを並列実行できる