JSONとは何か
JSON(JavaScript Object Notation)は、人間にとって読み書きしやすく、機械にとっても解析・生成しやすい、軽量なテキストベースのデータ交換フォーマットです。JavaScriptの構文から派生していますが、JSONは言語非依存であり、現代のほぼすべてのプログラミング言語がJSONを解析・生成するためのライブラリを持っています。
JSONは2000年代初頭にDouglas Crockfordによって、Web上でのデータ交換においてXMLよりもシンプルな代替手段として提唱されました。今日では、REST API、設定ファイル、MongoDBのようなデータベースなど、あらゆる場面で使われる支配的なフォーマットとなっています。
JSON構文:完全ガイド
JSON値は以下のいずれかです:
- オブジェクト:
{ "key": value, ... }— キーと値のペアの順不同コレクション - 配列:
[ value, ... ]— 値の順序付きリスト - 文字列:
"hello world"— 必ずダブルクォートを使用 - 数値:
42,3.14,-7,1.5e10— 整数と浮動小数点の区別なし - 真偽値:
trueまたはfalse - Null:
null
{
"name": "田中アリス",
"age": 30,
"isActive": true,
"scores": [95, 87, 100],
"address": {
"city": "東京",
"postcode": "100-0001"
},
"notes": null
}
よくある構文ミス
| ミス | 誤り | 正しい書き方 |
|---|---|---|
| 末尾のカンマ | { "a": 1, } |
{ "a": 1 } |
| シングルクォート | { 'key': 'val' } |
{ "key": "val" } |
| クォートなしキー | { key: "val" } |
{ "key": "val" } |
| コメント | { // コメント } |
(サポートされていない) |
| Undefined | { "a": undefined } |
nullを使用またはキーを省略 |
JSONの歴史
- 2001年: Douglas Crockfordがステートレスなサーバー・ブラウザ間通信プロトコルとしてJSONを普及させ始める
- 2006年: IETFがRFC 4627(最初の公式JSON仕様)を公開
- 2013年: ECMA InternationalがJSONをECMA-404として正式標準化
- 2017年: RFC 8259が以前のすべてのRFCに取って代わり、決定版の標準となる
JSON以前は、XMLがAPI通信を支配していました。JSONの簡潔さとJavaScriptオブジェクトとの自然な親和性が、Web 2.0時代に爆発的な普及をもたらし、その傾向は加速し続けています。
JSONの活用場面
REST API
現代のほぼすべてのREST APIはJSONを返します。天気APIへのリクエストは次のようなレスポンスを返すでしょう:
{
"location": "東京",
"temperature": 22.4,
"unit": "celsius",
"conditions": ["曇り", "湿度高め"],
"forecast": [
{ "day": "月曜日", "high": 24, "low": 18 },
{ "day": "火曜日", "high": 21, "low": 16 }
]
}
設定ファイル
ESLint(.eslintrc.json)、TypeScript(tsconfig.json)、npm(package.json)などのツールはすべて設定にJSONを使用しています。
NoSQLデータベース
MongoDBはBSON(Binary JSON)形式でドキュメントを保存します。CouchDB、Firebase Firestore、DynamoDBはいずれもJSONライクなドキュメントモデルを採用しています。
ローカルストレージとCookie
ブラウザのlocalStorageは文字列しか保存できないため、開発者はオブジェクトを保存する前にJSON.stringify()し、取得時にJSON.parse()するのが一般的です。
ロギングとオブザーバビリティ
JSON形式の構造化ログは、Elasticsearch、Datadog、Lokiなどのツールでのログクエリを容易にします。
実践的なJSONパース
JavaScript / TypeScript
// 文字列をオブジェクトに変換
const data = JSON.parse('{"name":"田中","age":30}');
console.log(data.name); // "田中"
// オブジェクトを文字列に変換
const json = JSON.stringify({ name: "田中", age: 30 }, null, 2);
JSON.stringifyの省略可能な引数null, 2はインデント2スペースのpretty-printを有効にします。デバッグ時に非常に役立ちます。
Python
import json
# パース
data = json.loads('{"name": "田中", "age": 30}')
print(data["name"]) # 田中
# シリアライズ
text = json.dumps({"name": "田中", "age": 30}, indent=2, ensure_ascii=False)
Go
import (
"encoding/json"
"fmt"
)
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
func main() {
var p Person
json.Unmarshal([]byte(`{"name":"田中","age":30}`), &p)
fmt.Println(p.Name)
}
高度なトピック
JSON Schema
JSON Schemaは、JSONデータの構造を検証するためのボキャブラリです。必須フィールド、値の型、パターン、制約を定義できます:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"name": { "type": "string" },
"age": { "type": "integer", "minimum": 0 }
},
"required": ["name", "age"]
}
JSON Pointer(RFC 6901)
JSON PointerはJSONドキュメント内の特定の値を識別するための文字列構文を提供します:
/name→nameフィールド/scores/0→scores配列の最初の要素
JSON Patch(RFC 6902)
JSON PatchはJSONドキュメントに適用する一連の操作を表現するフォーマットを定義します。APIでの増分更新に役立ちます。
パフォーマンスに関する考慮事項
- サイズ: JSONはテキストベースであり冗長です。高スループットシステムでは、MessagePackやProtocol Buffersなどのバイナリ代替手段を検討してください。
- パース速度: 現代のJSONパーサー(simdjsonなど)は毎秒ギガバイト単位でパースできますが、ほとんどのWebアプリではJSONパースはボトルネックにはなりません。
- 深いネスト構造: 非常に深いネストは再帰パーサーでスタックオーバーフローエラーを引き起こす可能性があります。構造はできるだけフラットに保つことをお勧めします。
JSON vs XML vs YAML
| 特徴 | JSON | XML | YAML |
|---|---|---|---|
| 可読性 | 良い | 冗長 | 優秀 |
| コメント | ❌ | ✅ | ✅ |
| バイナリサポート | ❌(base64が必要) | ❌ | ❌ |
| スキーマ検証 | JSON Schema | XSD | ❌(限定的) |
| 最適な用途 | API、設定、ストレージ | ドキュメント、レガシー | 設定ファイル |
ベストプラクティス
- 入力時に検証する: 受け取ったJSONを盲目的に信頼しない。スキーマに対して検証するか、期待するフィールドを確認してください。
nullを意図的に使う: 「フィールドが存在しない」と「フィールドが明示的にnullである」を区別してください。- 深いネスト構造を避ける: フラットなデータの方が扱いやすい。関連オブジェクトの紐付けにはIDを使用してください。
- 一貫したキー命名: 規約(camelCase、snake_case)を選び、API全体で統一してください。
- 日付はISO 8601文字列として扱う: JSONには日付型がありません。相互運用性のために
"2025-04-09T00:00:00Z"形式を使用してください。 - 本番環境では圧縮、デバッグ時はpretty-print: APIレスポンスでは帯域幅削減のためコンパクトなJSONを使用し、ローカルではpretty-printしてください。
まとめ
JSONはWeb上でのデータ交換の共通言語となりました。それには十分な理由があります:シンプルで、読みやすく、どこでもサポートされています。その構文、制限、ベストプラクティスを理解することで、APIの構築、設定ファイルの作成、データパイプラインの処理など、あらゆる場面でより優れた開発者になれるでしょう。