1. JSON読み込みで最初に押さえるポイント
JavaScriptでJSONを読み込むときは、読み込み元が「HTTPで取得するデータ」なのか「すでに手元にある文字列」なのかを先に分けます。外部APIやJSONファイルを読むならfetch()とresponse.json()、文字列をJavaScriptの値へ変換するならJSON.parse()を使います。
この記事では、fetch()、response.json()、JSON.parse()、HTML表示、エラー処理、ローカル開発時の注意点までを、実務で迷わない順番で整理します。
1.1 JSONはJavaScriptオブジェクトそのものではない
結論:JSONはテキスト形式のデータであり、JavaScriptのオブジェクトリテラルと似ていますが同じものではありません。
JSONではキーと文字列をダブルクォーテーションで囲み、末尾カンマやコメントは使えません。次のJSONは正しい形式です。
{
"name": "Taro",
"age": 30,
"skills": ["JavaScript", "HTML", "CSS"],
"active": true
}
一方、次のような書き方はJavaScriptのオブジェクトとしては使える場合がありますが、JSONとしては不正です。
{
name: "Taro",
age: 30,
}
JSONを読み込む処理でエラーが出る場合、通信よりも先に「JSONとして正しい構文か」を確認すると原因を切り分けやすくなります。
1.2 読み込み方法は2種類に分けて考える
結論:URLから取るならfetch()、文字列を変換するならJSON.parse()です。
よく使う方法は次の2つです。
| やりたいこと | 使うAPI | 代表例 |
|---|---|---|
| APIやJSONファイルをHTTPで取得する | fetch()とresponse.json() | /api/users、./data.json |
| JSON文字列をJavaScriptの値へ変換する | JSON.parse() | "{\"name\":\"Taro\"}" |
fetch()は通信を行うため非同期処理になります。JSON.parse()は手元にある文字列を解析する同期処理です。この違いを混同すると、Promiseの扱いやエラー処理でつまずきます。
2. fetchでJSONファイルやAPIを読み込む
fetch()はブラウザ標準のAPIで、指定したURLへリクエストを送り、Responseオブジェクトを返します。JSON本文をJavaScriptの値として取り出すには、返ってきたResponseに対してresponse.json()を呼び出します。

2.1 最小構成のコード
結論:await fetch(url)でレスポンスを受け取り、await response.json()でJSON本文を解析します。
async function loadUser() {
const response = await fetch("/api/user.json");
const user = await response.json();
console.log(user.name);
}
loadUser();
このコードでは、fetch()がHTTPレスポンスを取得し、response.json()がレスポンス本文をJSONとして読み取ります。response.json()も非同期処理なので、awaitを付ける必要があります。
2.2 HTTPエラーは自動で例外にならない
結論:fetch()は404や500のレスポンスだけではcatchへ移りません。response.okを自分で確認します。
初心者がよく誤解する点として、fetch()はサーバーからHTTPレスポンスを受け取れた場合、ステータスが404でも500でも通常は解決済みのPromiseになります。ネットワーク障害、CORSエラー、リクエストの中断などでは例外になりますが、HTTPステータスの判定は別です。
async function loadJson(url) {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
return response.json();
}
このようにしておくと、存在しないURLやサーバーエラーを正常データとして処理してしまう事故を防げます。
2.3 Content-Typeも確認すると安全
結論:APIがHTMLのエラーページを返すこともあるため、必要に応じてContent-Typeを確認します。
response.json()はレスポンス本文をJSONとして解析します。サーバー側の設定ミスでHTMLやプレーンテキストが返ってくると、SyntaxErrorが発生します。
async function loadJson(url) {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
const contentType = response.headers.get("content-type");
if (!contentType?.includes("application/json")) {
throw new Error("Response is not JSON");
}
return response.json();
}
すべてのAPIが厳密にapplication/jsonを返すとは限りませんが、自分で管理しているAPIや業務システムでは確認しておくと不具合の発見が早くなります。
3. JSON.parseで文字列をオブジェクトに変換する
JSON.parse()は、JSON形式の文字列をJavaScriptの値へ変換するメソッドです。HTTP通信は行いません。localStorageに保存した文字列、フォームから受け取ったJSON文字列、サーバーから別の形式で受け取った文字列などを解析するときに使います。
3.1 JSON.parseの基本
結論:JSON.parse()に渡す文字列は、正しいJSONでなければなりません。
const jsonText = '{"name":"Taro","age":30}';
const user = JSON.parse(jsonText);
console.log(user.name);
console.log(user.age);
jsonTextは文字列です。JSON.parse(jsonText)を実行した後のuserはJavaScriptのオブジェクトになります。
3.2 SyntaxErrorをtry…catchで扱う
結論:ユーザー入力や外部データを解析する場合は、try...catchで構文エラーに備えます。
function parseJsonSafely(jsonText) {
try {
return {
ok: true,
data: JSON.parse(jsonText)
};
} catch (error) {
return {
ok: false,
message: "JSONの形式が正しくありません"
};
}
}
const result = parseJsonSafely('{"name":"Taro"}');
if (result.ok) {
console.log(result.data.name);
} else {
console.error(result.message);
}
JSON.parse()は構文エラーがあるとSyntaxErrorを投げます。アプリ全体が止まらないよう、入力値や外部データを扱う箇所では失敗時の表示やログを用意します。
3.3 JSON.stringifyとの違い
結論:JSON.parse()は文字列から値へ、JSON.stringify()は値から文字列へ変換します。
| メソッド | 変換方向 | 主な用途 |
|---|---|---|
JSON.parse() | JSON文字列からJavaScriptの値 | 読み込み、復元、解析 |
JSON.stringify() | JavaScriptの値からJSON文字列 | 保存、送信、ログ出力 |
たとえばlocalStorageは文字列しか保存できないため、保存時はJSON.stringify()、読み込み時はJSON.parse()を使います。
const settings = {
theme: "dark",
pageSize: 20
};
localStorage.setItem("settings", JSON.stringify(settings));
const savedText = localStorage.getItem("settings");
const savedSettings = JSON.parse(savedText);
console.log(savedSettings.theme);
4. 取得したJSONをHTMLに表示する
JSONを読み込めても、画面に表示する段階で安全性やDOM操作を誤ると問題が起きます。特に外部データをそのままinnerHTMLへ入れる方法は、内容によっては危険です。
4.1 textContentで安全に表示する
結論:単純なテキスト表示にはtextContentを使います。
次のJSONをAPIから取得するとします。
{
"name": "Taro",
"role": "Frontend Developer"
}
HTML側には表示先を用意します。
<div id="profile"></div>
JavaScriptでは、取得した値をtextContentで代入します。
async function renderProfile() {
const response = await fetch("/api/profile.json");
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
const profile = await response.json();
const container = document.querySelector("#profile");
container.textContent = `${profile.name} / ${profile.role}`;
}
renderProfile().catch((error) => {
console.error(error);
});
textContentは文字列をHTMLとして解釈しないため、外部データを表示する基本手段として扱いやすいです。
4.2 リスト表示はcreateElementで組み立てる
結論:配列データを表示するときは、要素を作って追加すると安全で保守しやすくなります。
[
{ "id": 1, "name": "HTML" },
{ "id": 2, "name": "CSS" },
{ "id": 3, "name": "JavaScript" }
]
<ul id="skill-list"></ul>
async function renderSkills() {
const response = await fetch("/api/skills.json");
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
const skills = await response.json();
const list = document.querySelector("#skill-list");
list.replaceChildren();
for (const skill of skills) {
const item = document.createElement("li");
item.textContent = skill.name;
list.append(item);
}
}
renderSkills().catch(console.error);
replaceChildren()で既存の表示を消してから追加すると、再読み込み時に同じ項目が重複する問題を避けられます。
4.3 innerHTMLを使う場合の注意
結論:信頼できないJSONデータをinnerHTMLへ直接入れてはいけません。
次のようなコードは、外部データにHTMLやスクリプトが混ざったときに危険です。
container.innerHTML = data.description;
APIの値が完全に自分の管理下にあり、サーバー側で安全なHTMLだけを許可している場合を除き、表示にはtextContentやDOM生成を使うほうが安全です。
5. ローカルJSONファイルを読むときの注意点
手元のdata.jsonをブラウザで読み込もうとして失敗する場合、コードではなく実行環境が原因のことがあります。
5.1 file://ではfetchが失敗することがある
結論:HTMLファイルを直接開くのではなく、ローカルサーバー経由で確認します。
ブラウザでindex.htmlをダブルクリックして開くと、URLがfile://で始まります。この状態では、ブラウザのセキュリティ制限によりfetch("./data.json")が期待どおり動かないことがあります。
開発時は、プロジェクトのフォルダをHTTPサーバーで配信して確認します。
npx serve .
または、Pythonが使える環境なら次のように起動できます。
python -m http.server 8000
その後、ブラウザでhttp://localhost:8000のようなURLを開きます。
5.2 パスの基準を確認する
結論:fetch("./data.json")の基準は、実行中のHTMLページのURLです。
たとえば次の構成だとします。
project/
index.html
data/
users.json
index.htmlから読み込む場合は、次のように書きます。
fetch("./data/users.json");
JavaScriptファイルの場所ではなく、ブラウザで表示しているページのURLを基準に考えると、パスの間違いを減らせます。ただし、ビルドツールやフレームワークを使う場合は、そのツールの公開ディレクトリ規則も確認してください。
6. よくあるエラーと対処法
JSON読み込みの不具合は、通信、HTTPステータス、JSON構文、CORS、DOM表示のどこで起きているかを分けると解決しやすくなります。
6.1 Unexpected tokenの原因
結論:Unexpected tokenは、JSONではない文字列をJSONとして解析したときによく出ます。
たとえば、APIがログインページのHTMLを返しているのにresponse.json()を呼ぶと、HTMLの先頭文字で構文エラーになることがあります。
async function debugJson(url) {
const response = await fetch(url);
const text = await response.text();
console.log(text.slice(0, 200));
return JSON.parse(text);
}
原因調査では、一時的にresponse.text()で本文の先頭を確認すると、HTMLエラー、空レスポンス、余計な文字列混入などを見つけやすくなります。確認後は、通常のresponse.json()を使う形へ戻します。
6.2 CORSエラーの原因
結論:CORSはブラウザ側の制限で、基本的にはサーバー側のレスポンスヘッダー設定が必要です。
別ドメインのAPIをブラウザから読む場合、APIサーバーが許可していないオリジンからのアクセスはブロックされます。フロントエンド側のJavaScriptだけで任意に解除することはできません。
開発時の対処は次のどれかです。
| 状況 | 対処 |
|---|---|
| 自分でAPIを管理している | サーバー側で許可するオリジンを設定する |
| 外部APIを使っている | 公式の利用方法、APIキー、許可ドメインを確認する |
| 開発環境だけで失敗する | 開発サーバーのプロキシ設定を使う |
CORSエラーを避けるためにブラウザの安全機能を無効化して確認する方法は、通常の開発手順としては推奨できません。
6.3 response.json is not a functionの原因
結論:response.json()はfetch()が返すResponseオブジェクトのメソッドです。
次のように、すでにJSON化された値に対してjson()を呼ぶと失敗します。
const response = await fetch("/api/user.json");
const data = await response.json();
data.json(); // 誤り
response.json()を呼ぶのはレスポンス本文を読み取る一度だけです。読み取った後のdataは通常のオブジェクトや配列として扱います。
6.4 body stream already readの原因
結論:レスポンス本文は原則として一度だけ読み取れます。
次のコードは、同じレスポンス本文をtext()とjson()で二重に読もうとしているため失敗します。
const response = await fetch("/api/user.json");
const text = await response.text();
const data = await response.json(); // 誤り
調査で本文を文字列として確認したい場合は、textをJSON.parse()へ渡します。
const response = await fetch("/api/user.json");
const text = await response.text();
const data = JSON.parse(text);
通常の処理では、await response.json()だけを使えば十分です。
7. 実務向けの読み込み関数を作る
同じエラー処理を何度も書くと抜け漏れが出ます。小さな共通関数にまとめておくと、画面側のコードが読みやすくなります。
7.1 再利用できるloadJson関数
結論:HTTPステータス、Content-Type、JSON解析をまとめて扱います。
async function loadJson(url, options = {}) {
const response = await fetch(url, options);
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
const contentType = response.headers.get("content-type");
if (contentType && !contentType.includes("application/json")) {
throw new Error(`Expected JSON but received: ${contentType}`);
}
return response.json();
}
使う側はシンプルになります。
async function main() {
try {
const users = await loadJson("/api/users.json");
console.log(users);
} catch (error) {
console.error("JSONの読み込みに失敗しました", error);
}
}
main();
Content-TypeがないAPIも存在するため、上の例ではヘッダーがある場合だけ検査しています。自分で管理するAPIなら、常にapplication/jsonを返すように統一すると保守しやすくなります。
7.2 タイムアウトや中断を扱う
結論:AbortControllerを使うと、長すぎるリクエストを中断できます。
async function loadJsonWithTimeout(url, timeoutMs = 5000) {
const controller = new AbortController();
const timeoutId = setTimeout(() => {
controller.abort();
}, timeoutMs);
try {
return await loadJson(url, {
signal: controller.signal
});
} finally {
clearTimeout(timeoutId);
}
}
通信が遅いときに画面が待ち続けると、ユーザーには何が起きているか分かりません。タイムアウト、再試行、エラーメッセージを設計しておくと、実運用で扱いやすくなります。
7.3 POSTでJSONを送信する場合
結論:送信時はJSON.stringify()で本文を作り、Content-Typeを指定します。
JSONの読み込みだけでなく、APIへJSONを送る場面もよくあります。
async function createUser(user) {
const response = await fetch("/api/users", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(user)
});
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
return response.json();
}
createUser({
name: "Taro",
role: "Frontend Developer"
}).catch(console.error);
送信時はJSON.stringify()、受信時はresponse.json()という対応で覚えると整理しやすくなります。
8. 公式情報で確認したい項目
JavaScriptのAPIはブラウザや実行環境によって対応状況が異なる場合があります。挙動を確認するときは、英語の公式リファレンスを最小限参照すると正確です。
8.1 fetchとResponse.json
結論:fetch()はHTTPリクエストを行い、response.json()はレスポンス本文をJSONとして読み取ります。
仕様やブラウザ対応を確認したい場合は、次のリファレンスが役立ちます。
8.2 JSON.parse
結論:JSON.parse()はJSON文字列をJavaScriptの値へ変換します。
例外の種類や第2引数のreviverを確認したい場合は、次のリファレンスを参照します。
通常の記事やアプリ開発では、まず本文で紹介した基本形、HTTPエラー処理、try...catchを押さえれば十分です。
9. まとめ
JavaScriptでJSONを読み込む基本は、URLから取得する場合はfetch()とresponse.json()、文字列を解析する場合はJSON.parse()です。実務では、response.okでHTTPエラーを確認し、必要に応じてContent-Typeを検査し、画面表示ではtextContentやDOM生成を使うと安全に扱えます。
JSON読み込みで詰まったときは、通信できているか、HTTPステータスは成功か、返ってきた本文は本当にJSONか、表示処理でHTMLとして解釈していないかを順番に確認してください。この順番で切り分けると、Unexpected token、CORS、response.json is not a functionのようなエラーにも対応しやすくなります。
10. FAQ
10.1 JavaScriptでJSONを読み込む一番基本の方法は何ですか?
結論:APIやJSONファイルを読むならfetch()で取得し、response.json()でJavaScriptの値へ変換する方法が基本です。
10.2 JSON.parseとresponse.jsonの違いは何ですか?
結論:JSON.parse()は手元のJSON文字列を解析し、response.json()はfetch()で得たレスポンス本文をJSONとして非同期に読み取ります。
10.3 fetchで404なのにcatchされないのはなぜですか?
結論:fetch()はHTTPレスポンスを受け取れた場合、404や500だけでは例外にしないため、response.okを自分で確認する必要があります。
10.4 ローカルのdata.jsonを読み込めない原因は何ですか?
結論:file://でHTMLを直接開いている場合、ブラウザの制限で失敗することがあるため、ローカルサーバー経由で確認します。
10.5 取得したJSONをHTMLに表示するときの注意点は何ですか?
結論:外部データをinnerHTMLへ直接入れると危険な場合があるため、単純な文字表示にはtextContent、リスト表示にはcreateElement()を使うのが安全です。
