現代のWeb開発において、JSON (JavaScript Object Notation) を扱わない日は一日たりとも存在しません。APIレスポンス、設定ファイル、ログデータ、NoSQL...。あらゆる場所にJSONは存在します。しかし、あなたは本当にJSONを「正しく」使いこなせていると言い切れるでしょうか?
「ただのテキストデータだろう」と高を括っていると、本番環境で予期せぬパースエラーや、セキュリティホール、あるいはパフォーマンスのボトルネックを引き起こす原因になります。この記事では、教科書的な定義だけでなく、シニアエンジニアが現場で実践している「堅牢で扱いやすいJSON設計」のノウハウを、失敗事例を交えて徹底的に解説します。明日からのコード品質を一段階引き上げる準備はいいですか?
なぜXMLは敗れ、JSONが覇権を握ったのか
歴史を振り返ると、かつてデータ交換の王者はXMLでした。しかし、XMLは「冗長」で「解析が重い」という致命的な課題を抱えていました。タグの開始と終了でデータを囲む必要があり、ファイルサイズが肥大化しやすかったのです。
現在の開発現場において、JSONが選ばれる理由は明確です。
- 圧倒的な可読性: 人間が見て直感的に構造を理解できる。
- 言語非依存: JavaScriptだけでなく、Python, Go, Javaなど全ての主要言語に標準ライブラリが存在する。
- 軽量: 無駄なメタデータが少なく、ネットワーク帯域を圧迫しない。
JSON構文:プロが意識する「厳格なルール」
JSONは「JavaScriptのオブジェクト」に似ていますが、完全に別物です。ここを混同するとエラーの温床になります。特に以下のルールは絶対です。
1. キーは必ずダブルクォーテーションで囲む
JavaScriptでは { name: "Taro" } と書けますが、JSONでは Syntax Error です。必ず { "name": "Taro" } と記述しなければなりません。シングルクォーテーション ' も使用不可です。
2. 末尾のカンマ(Trailing Comma)は禁止
配列やオブジェクトの最後の要素の後にカンマを残すことは、モダンなJavaScriptでは許容されていますが、JSON仕様では厳密に禁止されています。古いブラウザや一部の厳格なパーサー(JavaのJacksonなど)は、これで即座にクラッシュします。
利用可能なデータ型と「使えない」型
JSONで扱えるのは以下の6つだけです。
- 文字列 (String)
- 数値 (Number): 整数・浮動小数点の区別なし
- 真偽値 (Boolean):
true/false(小文字のみ) - 配列 (Array)
- オブジェクト (Object)
- null
ここで重要なのは「何が使えないか」を知っておくことです。undefined、関数、Symbol、そして何より日付 (Date) はJSONで直接表現できません。
JavaScriptでの実装と「隠れた機能」
基本の JSON.parse() と JSON.stringify() は誰もが使いますが、第2引数、第3引数まで使いこなしているエンジニアは意外と少ないものです。
デバッグ効率を上げる JSON.stringify の整形
ログ出力や設定ファイルの保存時、一行に圧縮されたJSONは読みづらいですよね。第3引数にスペースの数を渡すことで、綺麗に整形(Pretty Print)できます。
const user = {
id: 101,
name: "Suzuki",
roles: ["admin", "editor"]
};
// 第3引数に '2' を指定すると、インデント2つで整形される
const prettyJson = JSON.stringify(user, null, 2);
console.log(prettyJson);
/* 出力:
{
"id": 101,
"name": "Suzuki",
"roles": [
"admin",
"editor"
]
}
*/
安全なパース処理(例外ハンドリング)
外部APIからのレスポンスや、ローカルストレージの値をパースする際、JSON.parse() を裸で使うのは自殺行為です。不正な文字列が渡されると即座にアプリがクラッシュします。
// ❌ 危険なコード
const data = JSON.parse(apiResponse);
// ✅ 推奨されるラッパー関数の例
function safeParse(jsonString, fallbackValue) {
try {
return JSON.parse(jsonString);
} catch (error) {
console.error("JSON Parse Error:", error);
return fallbackValue; // デフォルト値を返すことでアプリの停止を防ぐ
}
}
シニアが注意する3つの「落とし穴」
実務レベルでJSONを扱う際、以下の問題に直面することが必ずあります。これらを知っているかどうかが、ジュニアとシニアの分水嶺です。
1. Date型喪失問題
JSONには日付型がありません。JSON.stringify() すると、Dateオブジェクトは ISO 8601 形式の文字列(例: "2023-10-27T10:00:00.000Z")に変換されます。これを受け取って parse しても、それはただの「文字列」です。
new Date(dateString) を通してDateオブジェクトに復元する必要があります。あるいは、日付サフィックス(例: createdAt_date)をキー名につけて、ミドルウェアで自動変換する設計を採用する場合もあります。
2. BigIntと精度の壁
近年のJavaScriptには巨大な整数を扱う BigInt がありますが、JSONはこれをサポートしていません。無理やりstringifyするとエラーになります。また、APIから巨大な数値(64bit整数など)が送られてきた場合、JavaScriptの Number 型の精度限界(2^53 - 1)を超え、勝手に丸められてしまうリスクがあります。
解決策: Twitter APIのように、巨大なIDは数値ではなく文字列(String)として送受信するのが鉄則です。
3. コメントが書けないジレンマ
標準のJSONにはコメントが書けません。これが設定ファイルとして使う際の最大の弱点です。「なぜこの設定値なのか」を残せないからです。VS Codeの設定ファイルなどが採用している「JSON with Comments (JSONC)」や「JSON5」の使用を検討するか、コメント専用のキー(例: "_comment": "この値は...")を含めるなどの工夫が必要です。
ベストプラクティスとエコシステム
最後に、堅牢なシステムを構築するためのツールと設計思想を紹介します。
JSON Schemaによるバリデーション
APIドキュメントと実装が乖離することは日常茶飯事です。これを防ぐために「JSON Schema」を導入しましょう。期待されるデータ構造を定義し、自動テストでバリデーションを行うことで、クライアントとサーバー間の契約を守ることができます。
| 項目 | 説明 | ツール例 |
|---|---|---|
| 型定義 | データの型や必須項目を厳密に定義 | TypeScript, QuickType |
| バリデーション | ランタイムでのデータ検証 | Ajv, Zod |
| フォーマッター | コードスタイルの統一 | Prettier |
特にTypeScript環境では、Zodのようなライブラリを使って、ランタイムのバリデーションと静的な型定義を一本化するのがトレンドです。
セキュリティ対策:JSON HijackingとXSS
信頼できないソースからのJSONを扱う際、eval() を使うのは論外です。また、HTMLの中にJSONを埋め込む場合(SSR時の初期状態データなど)、</script> という文字列が含まれているとXSS攻撃の足がかりになります。必ず適切なエスケープ処理を行うライブラリやフレームワークの機能を使用してください。
まとめ:JSONを制する者はデータを制す
JSONはシンプルがゆえに奥が深く、その扱い方一つでアプリケーションの品質が大きく変わります。型のない柔軟さに甘えることなく、スキーマ定義やエラーハンドリングを徹底することで、初めて「堅牢なシステム」と呼べるものが出来上がります。
今日紹介したテクニックを、ぜひ次のプルリクエストに取り入れてみてください。あなたのコードに対する信頼度が、確実に上がるはずです。
Post a Comment