JSON.parse が「危険」になりやすい理由
まず前提として、JSON.parse は「JSON 形式の文字列を、JavaScript の値(オブジェクトや配列など)に変換する関数」です。
const json = '{"id":1,"name":"山田"}';
const obj = JSON.parse(json);
console.log(obj.id); // 1
console.log(obj.name); // "山田"
JavaScriptここまではとても便利ですが、問題は「壊れた JSON が来たとき」です。JSON.parse は、パースに失敗すると 例外を投げて処理を止めてしまう という性質があります。
const badJson = '{id:1,"name":"山田"}'; // JSON として不正(id にダブルクォートがない)
const obj = JSON.parse(badJson); // ここで例外が発生して処理が止まる
JavaScript業務コードでこれをそのまま使うと、
画面が真っ白になる
API 処理が 500 エラーで落ちる
バッチ処理が途中で止まる
といった「一発アウト」の事故につながります。
だからこそ、「安全な JSON parse」をユーティリティとして用意しておく価値が大きいのです。
基本形:try/catch で例外を握りつぶさない「安全ラッパー」
安全な JSON parse の第一歩は、「JSON.parse を直接呼ばず、必ず try/catch で包む」ことです。
いちばんシンプルな safeJsonParse
function safeJsonParse(text) {
try {
return {
ok: true,
value: JSON.parse(text),
};
} catch (error) {
return {
ok: false,
error,
};
}
}
JavaScript使い方はこうです。
const good = safeJsonParse('{"id":1,"name":"山田"}');
const bad = safeJsonParse('{id:1,"name":"山田"}');
if (good.ok) {
console.log("成功:", good.value);
} else {
console.log("失敗:", good.error);
}
if (bad.ok) {
console.log("成功:", bad.value);
} else {
console.log("失敗:", bad.error.message);
}
JavaScript重要なのは、「例外を外に飛ばさず、結果を“成功か失敗か”の形で返している」ことです。
これにより、呼び出し側は「落ちるかもしれない関数」ではなく、「結果を見て分岐すればよい関数」として扱えます。
デフォルト値を返すバージョン
「失敗したときはエラー情報はいらないから、代わりにデフォルト値を返してほしい」という場面も多いです。
その場合は、次のようなユーティリティが便利です。
function safeJsonParseOr(text, defaultValue) {
try {
return JSON.parse(text);
} catch {
return defaultValue;
}
}
JavaScript使い方の例です。
const json1 = '{"theme":"dark"}';
const json2 = '壊れたJSON';
const settings1 = safeJsonParseOr(json1, {});
const settings2 = safeJsonParseOr(json2, { theme: "light" });
console.log(settings1); // { theme: "dark" }
console.log(settings2); // { theme: "light" } (失敗したのでデフォルト)
JavaScriptここでのポイントは、「呼び出し側が try/catch を書かなくてよくなる」ことです。
「壊れていたらこの値にしておいて」という意図を、関数の引数で表現できます。
型を意識した「期待する形かどうか」のチェック
JSON.parse が成功しても、「中身が期待した形とは限らない」という問題があります。
例えば、次のようなケースです。
const json = '"これは文字列です"'; // JSON としては正しい
const result = JSON.parse(json);
console.log(result); // "これは文字列です"
JavaScriptもしあなたが「オブジェクトが来るはず」と思っていたら、ここで result.id を読もうとしてエラーになります。
つまり、「パースに成功したか」と「中身の構造が正しいか」は別問題です。
そこで、「パース成功+型チェック」をセットにしたユーティリティを考えます。
例:オブジェクトであることを期待する safeJsonObjectParse
function safeJsonObjectParse(text) {
try {
const value = JSON.parse(text);
if (value === null || typeof value !== "object" || Array.isArray(value)) {
return { ok: false, error: new Error("オブジェクトではありません") };
}
return { ok: true, value };
} catch (error) {
return { ok: false, error };
}
}
JavaScript使い方の例です。
const json1 = '{"id":1,"name":"山田"}';
const json2 = '"ただの文字列"';
const r1 = safeJsonObjectParse(json1);
const r2 = safeJsonObjectParse(json2);
console.log(r1.ok, r1.value); // true, { id: 1, name: "山田" }
console.log(r2.ok, r2.error.message); // false, "オブジェクトではありません"
JavaScriptここでは、「JSON として正しいか」に加えて、「オブジェクトであるかどうか」もチェックしています。
業務では、「ここでは必ずオブジェクトが来るはず」「ここでは配列が来るはず」といった前提が多いので、
こうした「型付きの safe parse」はかなり役に立ちます。
実務でよくあるパターン別の使い方
ローカルストレージからの読み込み
localStorage には文字列しか保存できないので、オブジェクトを保存するときは JSON にします。
localStorage.setItem("settings", JSON.stringify({ theme: "dark" }));
JavaScript読み込むときに、壊れた値や空文字が入っていると JSON.parse が落ちます。
そこで、安全な読み込み関数を用意します。
function loadSettings() {
const text = localStorage.getItem("settings");
if (text == null) {
return { theme: "light" }; // 初期値
}
return safeJsonParseOr(text, { theme: "light" });
}
const settings = loadSettings();
console.log(settings.theme);
JavaScriptこれで、「保存されている JSON が壊れていても、アプリ全体が落ちることはない」状態になります。
API レスポンスの一部が JSON 文字列になっている場合
API が「中のフィールドだけ JSON 文字列」という形で返してくることがあります。
// 例: data.meta が JSON 文字列
const data = {
id: 1,
meta: '{"tags":["a","b"],"published":true}',
};
JavaScriptこのときも、直接 JSON.parse せず、安全なラッパーを通します。
const metaResult = safeJsonParse(data.meta);
if (!metaResult.ok) {
console.error("meta の JSON が壊れています", metaResult.error);
} else {
console.log("タグ:", metaResult.value.tags);
}
JavaScript「壊れていたらログを出してスキップする」「壊れていたらデフォルト値にする」など、
プロジェクトの方針に合わせて振る舞いを決められます。
どこまで「安全」にするかを決める視点
安全な JSON parse を設計するとき、次のような軸で考えると整理しやすくなります。
例外を外に出さないか(常に戻り値で表現するか)
失敗時にエラー情報を返すか、デフォルト値だけ返すか
中身の型(オブジェクト・配列・特定の構造)までチェックするか
例えば、「バッチ処理で壊れた JSON があったら、そのレコードだけスキップしてログに残したい」なら、{ ok: boolean, value?, error? } 形式が向いています。
一方、「設定ファイルが壊れていたら即座に初期値にフォールバックしたい」なら、safeJsonParseOr(text, defaultValue) のような形が使いやすいです。
小さな練習で感覚をつかむ
次のような文字列を用意して、自分で safeJsonParse と safeJsonParseOr を実装して試してみてください。
const samples = [
'{"id":1,"name":"山田"}',
'["a","b","c"]',
'"ただの文字列"',
'{id:1,"name":"山田"}', // 不正
'壊れたJSON',
'',
' ',
];
JavaScriptそれぞれに対して、「成功か失敗か」「失敗時にどう扱うか(ログ?デフォルト?無視?)」を決めていくと、
あなたのプロジェクトにとってちょうどいい「安全な JSON parse ユーティリティ」の形が見えてきます。

