JSON と YAML:使い分けと相互変換時の落とし穴
JSON は API、YAML は設定ファイルでよく使われますが、用途で使い分けるべき形式です。本記事では両者の違いと、相互変換時の罠を整理します。
同じデータの両方の表現
{
"name": "Alice",
"age": 30,
"skills": ["JavaScript", "Python"],
"address": {
"city": "Tokyo",
"zip": "100-0001"
}
} name: Alice
age: 30
skills:
- JavaScript
- Python
address:
city: Tokyo
zip: '100-0001' YAML のほうがインデントベースで人間が書きやすい。JSON のほうが機械が解析しやすい。
主な違い
| 項目 | JSON | YAML |
|---|---|---|
| コメント | 不可 | # で可 |
| 末尾カンマ | 不可 | 該当なし |
| 文字列の引用 | 必須 | 多くの場合不要 |
| 改行 | \n | 改行を保持 |
| アンカー | なし | & * で参照可能 |
| 複数文書 | 1 ファイル 1 文書 | --- で区切り可能 |
| 型推論 | 厳密 | 緩い(Norway 問題など) |
JSON の特徴
シンプルで一意:
- データ型は string、number、boolean、null、array、object のみ
- コメントが書けない
- 末尾カンマ不可
- パースが速い
API のレスポンスに最適。Web 標準(ECMA-404)。
YAML の特徴
人間が読み書きしやすい:
- コメントが書ける
- 文字列の引用が省略可能
- インデントで階層を表現
- 複数の文書を 1 ファイルに(
---区切り) - アンカーで参照を表現できる
設定ファイル(CI/CD、Kubernetes、Docker Compose など)でよく使われる。
YAML 1.2 と 1.1 の違い
YAML 1.1 には有名な落とし穴:
country: NO
isOpen: yes
disabled: off NO→ boolean false(Norway の国コードのつもりが…)yes→ boolean trueoff→ boolean false
これを「Norway 問題」と呼ぶ。YAML 1.2 で修正されたが、Docker Compose や GitHub Actions など 1.1 互換のツールが多い。
安全策:boolean 風の文字列はクォートする:
country: 'NO'
isOpen: 'yes' コメントの問題
YAML はコメントが書けるが、JSON は書けない:
# 開発環境用設定
host: localhost
port: 3000 # デフォルトポート YAML から JSON に変換するとコメントが失われる。逆方向への変換でコメントを復活させることはできない。
日付の扱い
YAML 1.1/1.2 は日付型をネイティブサポート:
created: 2024-01-15
modified: 2024-01-15T10:30:00Z これらは Date オブジェクトとしてパースされる。JSON にはこれがない(文字列で表現するしかない)。
{
"created": "2024-01-15",
"modified": "2024-01-15T10:30:00Z"
} YAML → JSON 変換で日付がどう扱われるかは実装依存。文字列として残すパーサーが多い。
数値の精度
YAML 1.1 は数値を「特別扱い」する:
phone: 09012345678 # 数値?文字列?
postal: 0123456 # 8 進数?
hex: 0xFF # 16 進数 これらは数値としてパースされ、先頭の 0 が消えたり、桁あふれしたりする。電話番号や郵便番号は引用が必須:
phone: '09012345678'
postal: '0123456' キーの順序
JSON:オブジェクトのキー順序は仕様上は保証されないが、多くの実装で挿入順を維持。 YAML:マッピングのキー順序は保持される(パーサーに依存)。
「順序が重要な辞書」を扱うなら YAML が安全。
重複キー
両方とも仕様上は禁止だが、実装の挙動が違う:
{
"key": "first",
"key": "second"
} key: first
key: second - JSON:パーサーによっては「後勝ち」、エラー、警告
- YAML 1.2:エラーが推奨
整形ツールが「重複キーは無効化」する場合があるので注意。
アンカーと参照
YAML の独自機能:
defaults: &defaults
timeout: 30
retries: 3
prod:
<<: *defaults
host: prod.example.com
dev:
<<: *defaults
host: dev.example.com &defaults で定義、*defaults で参照、<<: でマージ。設定ファイルの DRY に便利。
JSON にはこれがない。
ファイルサイズ
同じデータでも:
- JSON:引用符・カンマで肥大化
- YAML:インデントが多いと逆に大きくなることも
API では gzip 圧縮が前提なので、生のサイズ差はあまり気にしない。
ストリーミング
JSON:JSONL(JSON Lines)形式で 1 行 1 文書のストリーミングが可能。
{"id": 1, "name": "a"}
{"id": 2, "name": "b"} YAML:複数文書(--- 区切り)でストリーミング可能。だがパーサーによる。
セキュリティ
YAML の !!python/object などのタグは任意のオブジェクトをデシリアライズできるため、信頼できないデータの読み込みは危険:
!!python/object/apply:os.system
- 'rm -rf /' PyYAML のデフォルト yaml.load() は危険(yaml.safe_load() を使う)。Ruby の Psych も同様。
JSON にはこの問題がない(プリミティブ型のみ)。
どちらを選ぶべきか
| 用途 | 推奨 | 理由 |
|---|---|---|
| API リクエスト/レスポンス | JSON | 速度、互換性 |
| ログ | JSON | パース速度 |
| 設定ファイル | YAML | 可読性、コメント |
| CI/CD パイプライン | YAML | デファクト |
| 機械間通信 | JSON | 標準化 |
| 人間が編集する | YAML | 書きやすい |
「設定は YAML、データは JSON」が経験則。
TOML という第三の選択肢
最近は TOML(Tom’s Obvious Minimal Language)も人気:
name = "Alice"
age = 30
[address]
city = "Tokyo"
zip = "100-0001" - INI ファイル風
- YAML より曖昧さが少ない
- Cargo (Rust)、Hugo、pyproject.toml で標準
YAML の「Norway 問題」を避けたい設定ファイル用に増えてきた。
まとめ
- JSON:API、機械間通信、シンプル
- YAML:設定ファイル、人間が編集、コメント可
- YAML 1.1 の Norway 問題に注意(boolean 風文字列はクォート)
- YAML → JSON でコメントは失われる
- 信頼できない YAML は安全モードでパース
JSON ↔ YAML の相互変換には、本サイトの JSON to YAML 変換ツールが使えます。