Knowledge
JSONの整形・バリデーション完全ガイド:壊れたJSONを素早く修正する方法
JSONの構文エラーが起きる原因とエラーメッセージの読み方、ブラウザ・Node.js・各言語でのパースエラー対処法、よくある間違いパターンと修正方法を体系的に解説します。
1. JSONとは何か
JSON(JavaScript Object Notation)は、データを人間にも機械にも読みやすいテキスト形式で表現するための仕様です。 2001年にDouglas Crockfordが提唱し、現在はRFC 8259として標準化されています。 REST APIのレスポンス、設定ファイル(package.json、tsconfig.jsonなど)、ログデータなど、 Web開発のあらゆる場面で使われています。
JSONが広く使われる理由は、そのシンプルさにあります。 データ型はオブジェクト・配列・文字列・数値・真偽値・nullの6種類のみです。 XMLと比べてタグによる冗長さがなく、ほぼすべてのプログラミング言語で標準のパーサーが用意されています。
一方で、JSONの構文は非常に厳格です。末尾カンマ・コメント・シングルクォートはすべて無効であり、 人間が手書きする際にミスが起きやすい形式でもあります。 APIレスポンスやログの確認でJSONを扱う機会が多いエンジニアにとって、 素早く整形・バリデーションできるツールは日常的な作業を大きく効率化します。
2. JSONパースエラーが起きる原因
JSONパースエラーは、大きく分けて以下の原因で発生します。 それぞれの原因と典型的な間違いを把握しておくと、エラーを見たときに素早く修正できます。
- 末尾カンマ(Trailing Comma): JavaScriptのオブジェクトや配列では末尾カンマが許可されていますが、 JSONでは仕様違反です。
{ "name": "Alice", "age": 30, }の最後のカンマはエラーになります。 コードからJSONを生成する際にJavaScriptの感覚で書いてしまうと起きやすいミスです。 - シングルクォート: JSONのキーと文字列値は必ずダブルクォートで囲む必要があります。
{ 'name': 'Alice' }はJavaScriptでは有効ですが、JSONでは無効です。 - コメントの混入: JSONはコメントをサポートしていません。 設定ファイルを手書きする際に
// これは設定ですのようなコメントを入れると、 標準のJSONパーサーはエラーを返します。 コメントを使いたい場合は、JSON5やJSONCといった拡張形式か、 専用の設定ファイル形式(TOML、YAMLなど)を検討してください。 - エスケープされていない特殊文字: 文字列内にダブルクォート、バックスラッシュ、改行文字などを含める場合は バックスラッシュでエスケープが必要です。 例えば改行は
\n、タブは\t、 ダブルクォートは\"と書きます。 Windowsのファイルパスに含まれる\をそのまま書くとエラーになります。 - 数値の形式:
NaN・Infinity・先頭ゼロの数値(007)はJSONでは無効です。 JavaScriptでは有効な値でも、JSONとしては不正になる場合があります。 - 文字コードの問題: RFC 8259ではJSONはUTF-8での記述が推奨されています。 UTF-16やShift_JISで保存されたJSONをUTF-8のパーサーに渡すと、 日本語を含むデータで文字化けやパースエラーが発生します。
3. エラーメッセージの読み方
JSONパースエラーのメッセージはブラウザやランタイムによって形式が異なります。 メッセージの読み方を知っておくと、どこに問題があるかを素早く特定できます。
Chrome / V8(Node.jsを含む)の場合、エラーメッセージはSyntaxError: Unexpected token '}', ... is not valid JSONのような形式で、問題のある文字と文字列中の絶対位置(position)が表示されます。 この位置番号は文字列の先頭を0としたインデックスです。 長いJSONでは位置番号だけでは場所を特定しにくいため、整形ツールを使うと行・列番号に変換できます。
Firefox / SafariのパーサーはSyntaxError: JSON.parse: unexpected character at line 3 column 15のように行番号と列番号を直接表示します。 このメッセージは人間にとって読みやすく、問題箇所の特定が容易です。
Pythonでは json.JSONDecodeError: Expecting ',' delimiter: line 5 column 3のように、何を期待していたのか(delimiter・value・propertyなど)と行・列番号が表示されます。
いずれの場合も、エラーメッセージが指す位置は「問題が検出された場所」であり、 「問題の根本原因」とは異なることがあります。 例えば閉じ括弧の不足は、その括弧が必要な位置ではなく、 ファイル末尾や次のトークンの位置でエラーとして検出されることがあります。 エラー位置の少し手前を注意深く確認することが重要です。
4. よくある間違いパターンと修正方法
実務でよく遭遇するJSONの間違いパターンと、その修正方法を紹介します。
- APIレスポンスに余分な文字が混入している: PHPのAPIで多く見られるケースです。レスポンスの先頭に
}や改行・スペース・BOM(Byte Order Mark)が混入していると、 クライアント側のJSONパーサーがエラーを返します。 ネットワークタブでレスポンスの生データを確認し、 JSONの開始文字{または[より前に余分な文字がないか確認します。 - JavaScriptオブジェクトをそのままJSONとして使っている:
JSON.stringify()を通さずにオブジェクトをテキストとして送信すると、[object Object]という文字列になってしまいます。 APIに送信する前に必ずJSON.stringify(data)を使い、Content-Type: application/jsonヘッダーを設定します。 - 数値が文字列になっている: フォームデータや環境変数経由でJSONを構築すると、 本来数値であるべき値が文字列
"42"になっていることがあります。 スキーマバリデーション(Zodなど)を使うか、JSONを整形して型を目視確認します。 - 深くネストされたJSONの読み方: API仕様と実際のレスポンスが一致しているかの確認に、整形ツールが役立ちます。 インデントを4スペースにすると階層構造が明確になります。
5. 整形・バリデーションツールの使い方
JSONを扱う際の整形・バリデーション手段はいくつかあります。 状況に応じて使い分けましょう。
- オンラインツール: すぐに使いたい場合はブラウザから使えるツールが便利です。 このサイトの JSON Formatter では、 JSONを貼り付けると即座に整形・バリデーションを行い、 構文エラーがある場合は行番号・列番号を表示します。 インデント幅(2スペース・4スペース)も切り替えられます。
- コマンドライン(jq):
jqはJSONを扱うための強力なコマンドラインツールです。echo '{"name":"Alice"}' | jq .で整形出力できます。 フィルタ機能を使えば特定のキーの抽出や変換もできるため、 ログ解析やAPIデバッグで重宝します。 - エディタの拡張機能: VS CodeにはJSON整形機能が標準で内蔵されています。
Format Document(Mac:⇧⌘F、Windows:Shift+Alt+F)で ファイル全体を整形できます。 ファイル保存時に自動整形されるようeditor.formatOnSaveを設定しておくと便利です。 - Node.js でのバリデーション: スクリプトでJSONファイルを検証したい場合は
JSON.parse(fs.readFileSync('data.json', 'utf-8'))を try-catchで囲むだけで実現できます。 型安全なバリデーションにはZodのz.string().json()や スキーマ定義を使うと、構文だけでなく型や必須フィールドの検証も行えます。
6. 実務で使えるTips
- JSON5・JSONC を使う: 設定ファイルにコメントを書きたい場合は、JSON5(
.json5)や JSONC(JSON with Comments、.jsonc)を検討します。 VS Codeのsettings.jsonやtsconfig.jsonはJSONCです。 アプリのランタイムでは専用のパーサーライブラリが必要になります。 - 大きなJSONは分割して確認: 数MBを超えるJSONをブラウザで開くと動作が重くなります。
jqや Python のjson.toolモジュール (python3 -m json.tool data.json)をコマンドラインで使うと、 大きなファイルでも快適に整形・確認できます。 - JSON Schemaでドキュメントと検証を兼ねる: JSON Schemaを定義しておくと、APIのリクエスト・レスポンスの形式をドキュメントとして 共有しながら、自動バリデーションにも使えます。 AJVやZodなど主要な言語でJSON Schemaをサポートするライブラリが揃っています。
- ログ出力時の注意:
JSON.stringify(obj, null, 2)の第3引数はインデント幅です。 開発時のデバッグ出力には便利ですが、本番ログではファイルサイズが増えるためJSON.stringify(obj)(第3引数なし)を使いましょう。