JavaScript fetch APIの使い方|GET・POST・JSONを実際に送受信して確認する

fetch APIでGET・POST・JSONを送受信して確認する図

JavaScriptでデータを取得したいとき、fetch()の短いコードは見つかっても、「取得したJSONをどう画面に出すのか」「POSTしたデータをサーバー側でどう受け取るのか」で迷うことがあります。

この記事では、GETでお知らせのJSONを取得し、POSTでフォームの入力内容をPHPへ送るサンプルを作ります。送信先も手元に用意するため、外部サービスへの登録やAPIキーは不要です。

目標は、JSONの取得・送信と、返ってきた結果の画面表示ができることです。ChromeのNetworkタブで通信の中身を確認し、404・500・HTML誤返却も同じ教材で再現します。

この記事でできること
  • GETでJSONを取得し、必要な値を画面に表示する
  • POSTで入力内容をJSONとして送信し、PHPからの応答を受け取る
  • Networkタブで送信内容とレスポンスを見分ける
検証記録
記録項目現時点の状態
検証日2026年9月6日
OS・Chrome・PHPのバージョンWindows・Chrome系ブラウザー・PHP 8.5.8
前提localhostのPHPサーバー。同一オリジン・架空データ
使用ファイル正常系4ファイル+失敗系3ファイル
成功条件GET本文の画面表示、POSTの送信値とreceivedの一致
失敗例の確認結果404・500のHTTP判定、200+HTMLでのJSON解析失敗、復旧後の正常動作を確認
目次

fetchとは?GET・POST・JSONの役割

fetch()は、JavaScriptからHTTP通信を行うための関数です。ブラウザの画面全体を読み込み直さなくても、必要なデータだけを取得したり、入力内容を送信したりできます。

用語この記事での役割
GETお知らせデータを取得する通信方法
POST名前と作業名を送る通信方法
JSONキーと値を使ってデータを表すテキスト形式
リクエスト/レスポンスブラウザからの要求/サーバーからの応答

GETとPOSTは通信方法、JSONはデータ形式なので、同じ分類ではありません。今回の例ではGETの応答も、POSTの送信内容・応答もJSONにします。POSTしただけで保存されるわけではなく、保存するかどうかはサーバー側の処理で決まります。

このサンプルのPHPは、受け取った値を返すだけです。データベースへの登録やメール送信は行いません。

ブラウザとJavaScriptとPHPの間でリクエストとJSON応答が往復する流れ
始める前この記事を終えた後に確認すること
fetchのコードを写して動かすGET・POSTの違いとJSONの扱いを説明できる
画面に表示されたかだけを見るRequest・Payload・Status・Responseを照合できる
エラー文だけで判断する404・500・HTML誤返却の違いを同じ教材で確認できる

1.サンプルのファイルと実行環境を用意する

HTMLの要素やJavaScriptの変数・関数を読める方向けの手順です。PHPは受信用コードをそのまま用意し、まずJavaScript側の通信に注目します。

必要なもの準備する内容
ブラウザGoogle Chrome。本文の開発者ツール表記は英語名を併記
エディターUTF-8でHTML・JavaScript・PHPを保存できるもの
PHP実行環境PHP 8.1以上で動く構文を使用。サポート中のPHPを用意
作業フォルダー新しく作るfetch-basic。既存サイトのファイルは変更しない

ターミナルでphp -vを実行し、バージョンを確認します。コマンドが認識されない場合は、PHPの導入とPATHの設定を先に済ませてください。既存のファイル送信記事でも、PHPの実行環境を確認する手順を扱っています。

まず作業フォルダーに次の4ファイルを用意します。post.phpだけは、apiサブフォルダーへ保存します。

ファイル役割
index.html取得ボタン、入力フォーム、結果欄
sample.jsonGETで取得するお知らせ
app.jsGET・POSTと画面表示の処理
api/post.phpPOSTの入力を受け取りJSONで返す処理

2.ボタンと入力フォームを用意する

index.htmlに次のコードを保存します。上側はGETの結果、下側はPOSTの結果を表示する欄です。deferを付け、HTMLの読み取り後にapp.jsを実行します。

<!doctype html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>fetch GET・POSTサンプル</title>
  <script src="./app.js" defer></script>
</head>
<body>
  <h1>fetch GET・POSTサンプル</h1>
  <h2>GET:お知らせを取得</h2>
  <button id="get-button" type="button">お知らせを取得</button>
  <pre id="get-result" aria-live="polite">未取得</pre>

  <h2>POST:入力内容を送信</h2>
  <form id="post-form">
    <p><label>名前(架空)
      <input name="name" value="サンプル太郎" required maxlength="50">
    </label></p>
    <p><label>作業名
      <input name="task" value="fetchの練習" required maxlength="100">
    </label></p>
    <button type="submit">JSONを送信</button>
  </form>
  <pre id="post-result" aria-live="polite">未送信</pre>
</body>
</html>

装飾を省いて、ボタン・入力欄・通信後の表示に絞っています。フォームは準備だけ済ませ、先にGETを動かします。

3.GETでJSONを取得して画面に表示する

1.取得するJSONを保存する

sample.jsonに次の内容を保存します。文字列とキーは半角のダブルクォーテーションで囲み、最後の項目の後にカンマを付けないようにします。

{
  "title": "サンプルのお知らせ",
  "message": "GETでJSONを取得できました。"
}

2.取得処理をapp.jsに保存する

app.jsに次のコードを保存します。取得ボタンを押したときにsample.jsonを読み取り、titlemessageを画面に出す処理です。

const getButton = document.querySelector("#get-button");
const getResult = document.querySelector("#get-result");

getButton.addEventListener("click", async () => {
  getButton.disabled = true;
  getResult.textContent = "取得中...";
  try {
    const response = await fetch("./sample.json", { cache: "no-store" });
    if (!response.ok) {
      throw new Error("HTTPエラー: " + response.status);
    }
    const data = await response.json();
    getResult.textContent = data.title + "\n" + data.message;
  } catch (error) {
    getResult.textContent = "取得失敗: " + error.message;
  } finally {
    getButton.disabled = false;
  }
});

fetch()の通信方法は、指定を省略するとGETになります。cache: "no-store"は、練習中にJSONを書き換えたとき、保存済みの応答を使わずに取得するための指定です。実務で常に必要な設定ではありません。

await fetch(...)で受け取るのは本文そのものではなく、ステータスなどを持つResponseです。その本文をawait response.json()で読み取り、JavaScriptの値として扱います。awaitはこの非同期処理の続きを待つもので、ブラウザ全体を停止させるものではありません。

仕様の詳細はMDNのFetch APIの使い方と、Response.json()を参照してください。

3.ローカルサーバーを起動して取得する

ターミナルでfetch-basicフォルダーへ移動し、php -S localhost:8000を実行します。ターミナルは起動したままにして、Chromeでhttp://localhost:8000/を開きます。

注意

index.htmlをダブルクリックしてfile://で開かず、上記のHTTPアドレスを使ってください。PHPの組み込みサーバーは開発用です。公開サーバーとして使わず、終了するときはターミナルでCtrl+Cを押します。PHP公式の説明も確認してください。

PHPのローカルサーバーをlocalhostの8000番ポートで起動した確認記録

「お知らせを取得」を押します。想定する表示は「サンプルのお知らせ」と「GETでJSONを取得できました。」の2行です。

GETで取得したJSONのお知らせをページに表示した結果

4.NetworkタブでGETの応答を確認する

ChromeでF12を押すか、メニューの「その他のツール」から「デベロッパーツール」を開きます。「ネットワーク(Network)」を選び、録画が有効な状態で「お知らせを取得」をもう一度押します。

一覧のsample.jsonを選び、「ヘッダー(Headers)」でRequest MethodがGET、Status Codeが200であることを確認します。見つからない場合は、フィルターの「Fetch/XHR」を選ぶか、絞り込み文字を消してください。

Networkタブでsample.jsonへのGETリクエストとステータス200を確認する画面

「レスポンス(Response)」へ切り替え、sample.jsonに保存した2つのキーと値を確認します。画面には必要な値だけを表示していますが、通信の応答ではJSON本文を確認できます。

GETのResponseにtitleとmessageが含まれていることを確認する画面

Networkは開いている間の通信を記録します。ボタンを押した後に開いて何も出ない場合は、開いた状態で再実行してください。操作項目はChrome DevTools公式のNetworkリファレンスでも確認できます。

5.POSTで入力内容をJSONとして送信する

1.受信用のPHPを保存する

次のコードをapi/post.phpへUTF-8(BOMなし)で保存します。送信方法・形式・入力内容を確認し、受け取った名前と作業名をJSONで返します。PHPの開始タグより前に文字や空白を置かないでください。

<?php
declare(strict_types=1);

header('Content-Type: application/json; charset=UTF-8');

function reply(int $status, array $data): never {
    http_response_code($status);
    echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR);
    exit;
}

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    header('Allow: POST');
    reply(405, ['message' => 'POSTで送信してください。']);
}

$contentType = $_SERVER['CONTENT_TYPE'] ?? '';
$mediaType = strtolower(trim(explode(';', $contentType)[0]));
if ($mediaType !== 'application/json') {
    reply(415, ['message' => 'JSON形式で送信してください。']);
}

$rawBody = file_get_contents('php://input');
if ($rawBody === false) {
    reply(500, ['message' => '本文を読み取れませんでした。']);
}

try {
    $data = json_decode($rawBody, true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
    reply(400, ['message' => 'JSONの形式が正しくありません。']);
}

if (!is_array($data)
    || !is_string($data['name'] ?? null)
    || !is_string($data['task'] ?? null)
    || trim($data['name']) === ''
    || trim($data['task']) === '') {
    reply(400, ['message' => '名前と作業名を文字列で指定してください。']);
}

reply(200, [
    'message' => '入力内容を受信しました。',
    'method' => $_SERVER['REQUEST_METHOD'],
    'contentType' => $contentType,
    'received' => [
        'name' => trim($data['name']),
        'task' => trim($data['task'])
    ]
]);

JSON形式のリクエスト本文は、通常のフォーム送信のように$_POSTから取り出すのではなく、php://inputで読み取ります。json_decode(..., true, ...)でPHPの連想配列へ変換しています。詳しくはphp://inputjson_decode()の公式説明を参照してください。

このPHPの役割は通信の練習用です。本番の入力受付には、用途に応じた文字数・データ量の制限、認証・認可などを追加する必要があります。個人情報や実在する業務データは入力しないでください。

2.送信処理をapp.jsの末尾へ追加する

先ほどのGET処理は残したままapp.jsの末尾へ次を追加します。フォーム送信時のページ遷移をevent.preventDefault()で止め、代わりにfetch()で送信します。

const postForm = document.querySelector("#post-form");
const postResult = document.querySelector("#post-result");
const postButton = postForm.querySelector('button[type="submit"]');

postForm.addEventListener("submit", async (event) => {
  event.preventDefault();
  const payload = {
    name: postForm.elements.namedItem("name").value.trim(),
    task: postForm.elements.namedItem("task").value.trim()
  };

  postButton.disabled = true;
  postResult.textContent = "送信中...";
  try {
    const response = await fetch("./api/post.php", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(payload)
    });
    if (!response.ok) {
      throw new Error("HTTPエラー: " + response.status);
    }
    const data = await response.json();
    postResult.textContent = JSON.stringify(data, null, 2);
  } catch (error) {
    postResult.textContent = "送信失敗: " + error.message;
  } finally {
    postButton.disabled = false;
  }
});
指定役割
method: “POST”POSTで送信する
Content-Type: application/json送る本文がJSONであることを伝える
body: JSON.stringify(payload)JavaScriptのオブジェクトをJSON文字列にして本文に入れる

Content-Typeを指定するだけではデータはJSONになりません。本文の変換はJSON.stringify()、形式を伝えるのはContent-Typeと分けて考えると、どちらの設定が不足しているかを判断できます。

画面表示にはtextContentを使っています。受け取った文字をHTMLとして解釈しないため、このサンプルでinnerHTMLへ置き換える必要はありません。

3.入力内容を送信する

ファイルを保存したらページを再読み込みします。名前は「サンプル太郎」、作業名は「fetchの練習」のまま「JSONを送信」を押してください。

想定する応答は、messageが「入力内容を受信しました。」、methodPOSTreceivedの中に入力した名前・作業名が入ったJSONです。これは受信内容の確認であり、データの保存完了を意味しません。

フォームの入力内容をPOSTしPHPから返されたJSONを表示した結果

6.Networkで送信内容と受信結果を照合する

Networkを開いたまま、もう一度「JSONを送信」を押します。一覧のpost.phpを選び、「Headers」でRequest MethodがPOST、Status Codeが200、Request HeadersのContent-Typeがapplication/jsonであることを確認します。

POSTリクエストの送信方法とJSONのContent-Typeを確認する画面

続いて「ペイロード(Payload)」を開き、Request Payloadのnametaskを確認します。ここに表示されるのはブラウザが送った内容です。

POSTのRequest Payloadに架空の名前と作業名が入っている画面

「Response」に切り替え、received内の値と照合します。こちらはサーバーが返した内容です。作業名を「JSON送信の確認」に変えて再送し、PayloadとResponseの両方が変わることも確認してください。

入力を変更して再送しPHPの応答にも変更後の作業名が返ることを確認する画面
確認する場所このサンプルで確かめること
Headersどこへ、どの方法で送り、どのステータスが返ったか
Payload名前と作業名がJSONとして送られているか
ResponsePHPのreceivedに入力した値が返っているか

ここまで一致すれば、ボタンを押した結果だけでなく、ブラウザから送った内容とPHPから返った内容をたどれます。実際のAPIへ応用するときも、この3か所が確認の出発点になります。

7.取得先を変えて404・500・HTML誤返却を再現する

正常に取得・送信できた状態を基準に、GETの取得先だけを一つずつ変更します。POSTの処理は変更しません。各ケースで、画面表示とNetworkのStatus・Responseを記録します。

変更するのはapp.jsのGET処理にあるfetch("./sample.json", { cache: "no-store" })のURL部分です。変更のたびに保存し、ページを再読み込みしてから「お知らせを取得」を押します。

fetchで404・500・200とHTML応答を見分ける確認順

失敗例1:学習用PHPから404を返して確認する

PHP 8.4以降の組み込みWebサーバーでは、存在しないパスに対して親フォルダーのindex.htmlが返り、404を再現できない場合があります。環境差を避けるため、api/error-404.phpを作成して学習用の404応答を返します。

<?php
http_response_code(404);
header('Content-Type: application/json; charset=UTF-8');
echo json_encode(['message' => '学習用の404エラーです。'], JSON_UNESCAPED_UNICODE);

GET処理のURLを./api/error-404.phpへ変更し、ページを再読み込みして「お知らせを取得」を押します。Networkでerror-404.phpを選び、ステータスを確認します。

検証では取得失敗: HTTPエラー: 404と表示されました。response.okが偽になり、コード中のthrowで例外を発生させます。JSONを読み取る処理には進みません。404本文の形式はサーバーによって異なるため、実際に返った内容を記録してください。

学習用PHPへのアクセスが404になったことをNetworkタブで確認する画面

失敗例2:PHPから500を返して判定する

api/error-500.phpを新しく作り、次のコードを保存します。実際のサーバーを壊すのではなく、学習用の応答として500を返します。

<?php
http_response_code(500);
header('Content-Type: application/json; charset=UTF-8');
echo json_encode(['message' => '学習用の500エラーです。'], JSON_UNESCAPED_UNICODE);

GET処理のURLを./api/error-500.phpへ変更して再実行します。検証では取得失敗: HTTPエラー: 500と表示されました。NetworkのResponseではJSON本文を確認できますが、この最小コードはthrowした時点で止まるため、その本文のメッセージは画面には出しません。

学習用PHPへのアクセスが500になったことをNetworkタブで確認する画面

失敗例3:200でもHTMLが返るとJSON解析に失敗する

api/return-html.phpを新しく作り、次のコードを保存します。HTTP通信は成功していても、本文の形式が想定と違う状態を作ります。

<?php
http_response_code(200);
header('Content-Type: text/html; charset=UTF-8');
echo '<h1>JSONではなくHTMLの応答です</h1>';

GET処理のURLを./api/return-html.phpへ変更して再実行します。Networkでは200、Content-Typeはtext/html、ResponseにはHTMLがあることを確認します。

検証ではresponse.okの判定を通過した後、response.json()で解析に失敗してcatchへ進みました。エラーの詳しい文言はブラウザのバージョンによって異なります。200だからJSONも正しい、とは判断できません。

HTTPステータスは200でもResponse本文がHTMLになっていることを確認する画面

取得先を元に戻して正常動作を確認する

GET処理のURLを./sample.jsonへ戻し、保存・ページ再読み込み・ボタン実行の順に進めます。お知らせの2行が再び表示されることを確認してください。POSTの送信も再確認し、失敗例用の変更を残さずに終えます。

8.期待した動作と実測結果を比較する

2026年9月6日に各ケースを実行し、画面表示とNetworkの結果を照合しました。PHP 8.5.8では存在しないmissing.jsonが200+HTMLになるため、404だけは学習用のerror-404.phpで再現しています。

ケース期待する動作実測結果
正常GET200・お知らせ2行を表示200・表示一致を確認
正常POST200・入力値とreceivedが一致200・送受信値の一致を確認
404HTTP判定で停止・404を表示404・HTTPエラー表示を確認
500HTTP判定で停止・500を表示500・HTTPエラー表示を確認
200+HTMLHTTP判定通過後、JSON解析で失敗200・HTML本文・JSON解析失敗を確認
復旧後GET・POSTの正常動作に戻るGET・POSTの正常動作を再確認

うまくいかないときは、URL・形式・ステータスを確認する

症状最初に確認する点
ボタンを押しても通信が出ないapp.jsの保存場所、読み込みエラー、Consoleのエラー
404になるsample.jsonとapi/post.phpの名前・配置、サーバーを起動したフォルダー
PHPのコードが表示・ダウンロードされるPHPを実行しない静的サーバーで開いていないか。PHPサーバーのURLへ戻る
405になるpost.phpをアドレス欄から直接開いていないか。フォームからPOSTする
400/415になるJSONの形式、空欄、リクエストのContent-Type
CORS関連のエラーページとAPIのスキーム・ホスト・ポートが一致しているか

今回は同じhttp://localhost:8000/内で通信する構成です。片方だけ127.0.0.1に変えたり別ポートを使ったりせず、まず本文どおりのURLへ戻します。別オリジンのAPIではサーバー側のCORS設定が必要になる場合があり、mode: "no-cors"を付けても読めるJSONを取得する解決にはなりません。

404・500の詳しい処理は既存記事へ

このサンプルはresponse.okが偽なら例外を投げ、画面へステータスを表示する最小限の構成です。okが真になる範囲は200〜299で、404や500はfetch()だけでは自動的に例外になりません。MDNのResponse.okも参照してください。

エラー本文の取り出しや通信失敗との区別は、次の記事でまとめています。この記事で違いを再現した後、実務向けのエラー処理へ進むときに参照してください。

また、response.json()はJSON以外の本文や空の本文では解析に失敗します。今回と異なり204など本文のない成功応答を返すAPIでは、常にjson()を呼ぶ実装にはできません。HTMLが返っている場合は、次の記事でURLとResponseの確認手順を説明しています。

まとめ

fetchでJSONを扱うときは、GETで取得する処理と、POSTで送信する処理を分けると整理しやすくなります。404・500と、200でもJSONではない応答は、失敗する段階が異なります。POSTでは送るオブジェクトをJSON文字列に変換し、PHP側で読み取って応答を返します。

画面の表示だけで判断せず、NetworkのHeaders・Payload・Responseも確認してください。ファイルを送る場合は今回のJSON本文とは別にFormDataを使います。準備の章で紹介したファイル送信記事が次の手順になります。

参考リンク

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

この記事を書いた人

ちゃあむのアバター ちゃあむ エンジニア

Web開発やSaaS(ServiceNow、Salesforce)、業務システムに携わる、猫と食べることが大好きなインドア系ITエンジニアです。

コメント

コメントする


目次