MENU

【JavaScript】Fetch APIの使い方を解説|Webの基礎

JavaScriptでのFetch APIによるAjax通信の解説|Webの基礎
目次

はじめに

前回の記事では、非同期処理の基本としてPromise・async/awaitの書き方を解説しました。

今回は、その知識を使って実際にサーバーとデータをやり取りするFetch APIを解説します。ページ全体を再読み込みせずにサーバーと通信してデータを取得・送信する方法は、古くはAjax通信とも呼ばれ、現在のWebサイトのほとんどで使われている仕組みです。VBAで言えば、外部のWeb APIをHTTPリクエストで呼び出す処理に近いイメージです。前回の非同期処理の知識がそのまま活きてきますので、不安な方は先に前回の記事を確認しておくとスムーズです。

Fetch APIの基本(GETリクエスト)

fetch()は、指定したURLへHTTPリクエストを送る関数です。戻り値は前回解説したPromiseなので、.then()またはawaitで結果を受け取ります。

fetch("https://jsonplaceholder.typicode.com/users/1")
    .then((response) => {
        console.log(response.status); // 200
    });

本記事のサンプルでは、テスト用に公開されている無料のダミーAPI「JSONPlaceholder」を使っています。登録不要でそのままアクセスできるため、Fetch APIの動作確認に向いています。

fetch()が返すresponseには、通信そのものが成功したかどうかの情報(ステータスコードなど)が入っていますが、中身のデータ(JSON)はまだ入っていません。データを取り出すには、次に紹介するresponse.json()を使います。

レスポンスをJSONに変換する

response.json()は、レスポンスの中身をJavaScriptのオブジェクトに変換するメソッドです。このメソッド自体も非同期処理(Promise)になっています。

fetch("https://jsonplaceholder.typicode.com/users/1")
    .then((response) => response.json())
    .then((user) => {
        console.log(user.name); // "Leanne Graham"
        console.log(user.email); // "Sincere@april.biz"
    })
    .catch((error) => {
        console.error(error);
    });

.then()を2回つなげており、1回目でresponseを受け取ってresponse.json()を呼び出し、その結果(変換されたオブジェクト)を2回目の.then()で受け取っています。「通信の完了」と「JSONへの変換」という2段階の非同期処理が連続している、とイメージするとよいでしょう。

async/awaitで書く

前回解説したasync/awaitを使うと、Fetch APIの一連の流れをより読みやすく書けます。

async function getUser(id) {
    const response = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);
    const user = await response.json();
    return user;
}

async function main() {
    const user = await getUser(1);
    console.log(user.name); // "Leanne Graham"
}

main();

.then()を使わずに、通信結果を受け取る→JSONに変換する、という流れを上から順番に書けるようになりました。以降のサンプルは、基本的にこのasync/awaitの形で統一します。

エラー処理の注意点(response.okのチェック)

Fetch APIには、他の非同期処理と少し違う重要な注意点があります。存在しないユーザーIDでリクエストを送ってみましょう。

async function getUser(id) {
    const response = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);
    const user = await response.json();
    return user;
}

getUser(9999); // 存在しないID

サーバーが「404 Not Found」を返しても、このコードはエラーになりません。fetch()は、通信そのもの(インターネット接続やサーバーの応答)が成功していれば、ステータスコードが404や500であってもresolveしてしまうためです。rejectされるのは、サーバーに接続できなかった場合など、通信自体が失敗したときだけです。

そのため、HTTPのエラーを検知したい場合は、response.ok(ステータスコードが200番台かどうかを表すプロパティ)を自分でチェックし、必要であればthrowする必要があります。

async function getUser(id) {
    const response = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);

    if (!response.ok) {
        throw new Error(`ユーザーの取得に失敗しました(status: ${response.status})`);
    }

    return await response.json();
}

throwされたエラーは、前回解説したtry/catchで受け取れます。

async function main() {
    try {
        const user = await getUser(9999);
        console.log(user.name);
    } catch (error) {
        console.error(error.message); // "ユーザーの取得に失敗しました(status: 404)"
    }
}

「fetchはcatchされないから成功した」と思い込んでしまうミスが起きやすいポイントです。Fetch APIを使うときは、必ずresponse.okをチェックする習慣をつけましょう。

Fetch APIのリクエストからJSON変換までの流れを示すフロー図。fetchで通信、response.okでステータス確認、response.json()でデータ取得という3段階を表す

POSTリクエストでデータを送信する

ここまではデータを取得するGETリクエストでしたが、fetch()の第2引数にオプションを渡すことで、データを送信する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: title,
            body: body,
            userId: 1,
        }),
    });

    if (!response.ok) {
        throw new Error(`投稿に失敗しました(status: ${response.status})`);
    }

    return await response.json();
}
  • method:送信方法を指定します(省略時はGET)。
  • headers:送信するデータの形式をサーバーに伝えます。JSON形式で送る場合は"Content-Type": "application/json"を指定します。
  • body:送信するデータ本体です。JavaScriptのオブジェクトをそのまま送ることはできないため、JSON.stringify()で文字列に変換してから渡します。

実務サンプル(ユーザー検索フォーム)

前回の実務サンプルで作った「ローディング表示→結果表示」の流れを、今回は実際のFetch APIに置き換えて動かしてみます。ユーザーIDを入力して検索すると、該当ユーザーの情報を取得して表示するイメージです。

async function searchUser(userId) {
    showLoading(true);

    try {
        const response = await fetch(`https://jsonplaceholder.typicode.com/users/${userId}`);

        if (!response.ok) {
            throw new Error(`ユーザーが見つかりませんでした(status: ${response.status})`);
        }

        const user = await response.json();
        showResult(`${user.name}(${user.email})`);
    } catch (error) {
        showResult(`エラー:${error.message}`);
    } finally {
        showLoading(false);
    }
}

searchUser(1);

前回はsetTimeoutで通信を再現した疑似関数でしたが、今回は実際のfetch()に置き換わっただけで、showLoading・try/catch/finally・showResultという全体の骨組みはまったく同じです。非同期処理の書き方さえ身につけていれば、通信先が疑似APIでも本物のAPIでも同じ形でコードを書ける、ということが実感できるサンプルになっています。

ユーザーID検索フォームで「処理中...」のローディング表示から、取得したユーザー名とメールアドレスの表示に切り替わる様子を示すモックアップ

よくある質問・エラー対処

Q. fetchが404エラーでもcatchされないのはなぜですか?

→ fetch()は、通信そのもの(サーバーへの接続)が失敗したときだけrejectします。404や500のようなHTTPエラーは「通信自体は成功した」とみなされるため、catchでは捕まえられません。response.okを自分でチェックし、必要ならthrowしてください。


Q. GET・POST以外のメソッドも使えますか?

→ methodに"PUT"(更新)や"DELETE"(削除)などを指定することもできます。基本的な書き方はPOSTと同様で、必要に応じてheaders・bodyを組み合わせます。


Q. 「CORS」というエラーが出て通信できません。

→ CORS(Cross-Origin Resource Sharing)は、ブラウザが異なるドメインへの通信を制限するセキュリティの仕組みです。アクセス先のサーバー側がCORSを許可していないと発生します。本記事で使っているJSONPlaceholderのようなテスト用APIはCORSが許可されていますが、自分で用意したAPIでこのエラーが出た場合は、サーバー側でCORSの設定を確認する必要があります。

おわりに(まとめ)

まとめ

Fetch APIは、前回解説した非同期処理の書き方の上に成り立っている仕組みです。基本の型を覚えてしまえば、様々なAPIとの通信に応用できます。

  • ✅ `fetch()`はサーバーへリクエストを送り、Promiseを返す関数
  • ✅ レスポンスの中身を取り出すには`response.json()`でJSONに変換する(これも非同期処理)
  • ✅ `fetch()`はHTTPエラー(404・500等)ではrejectしないため、`response.ok`を自分でチェックする
  • ✅ POSTリクエストは`method`・`headers`・`body`(`JSON.stringify()`で変換)を指定して送る
  • ✅ async/awaitで書けば、疑似的な非同期処理も本物のAPI通信も同じ形のコードで扱える

次回は、今回何度も登場した`JSON.stringify()`など、JSONの扱い方についてさらに詳しく解説します。

次回は、JSONの扱い方について解説予定です。

この記事が、少しでも誰かのお役に立てれば幸いです。

関連記事

当サイトの記事で使用したVBAなどのサンプルをDLできます

この記事のサンプルはありません!

ダウンロードページへは下のカードをクリックすればジャンプできます。
よろしければご利用ください!


【CSS】テキスト関連プロパティについて基本解説|Webの基礎


よかったらシェアしてね!
  • URLをコピーしました!
目次