JSON と YAML:使い分けと相互変換時の落とし穴

約6分

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 のほうが機械が解析しやすい

主な違い

項目JSONYAML
コメント不可# で可
末尾カンマ不可該当なし
文字列の引用必須多くの場合不要
改行\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 true
  • off → 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 変換ツールが使えます。