- 技術 💻
JSONとは|JSONファイルの書き方・開き方とエラー例を実物で解説
結論
JSONとは、データを「文字」で表すための決まった書き方です。API のやり取りや設定ファイルに使われ、JSONファイルはその文字を保存したものです。
この記事でわかること
- 6つの型とオブジェクト・配列の書き方の早見表
- Python・JavaScript・jqで読み書きした実物
- 書き間違い12例のエラー原文と直し方
JSON は、プログラムの中のデータを文字の並びに書き出し、別のプログラムがそれを読み込んで元のデータに戻すための「共通の書き方」です。言語が違っても同じ形で受け渡せます。
flowchart TD
A[プログラムのデータ<br>Python の dict・JS のオブジェクト] -->|書き出す<br>dumps・stringify| J[JSON テキスト<br>決まった書き方の文字]
J -->|保存する| F[JSON ファイル<br>拡張子 .json]
J -->|送る| W[API のリクエスト<br>とレスポンス]
F -->|読み込む<br>load・parse| B[別のプログラムのデータ<br>言語が違っても同じ形]
W -->|読み込む| B
急いでいる人向けに、よく調べられることの答えを先にまとめます。
| 知りたいこと | 答え | 詳しい節 |
|---|---|---|
| JSON とは | データを文字で表す書き方 | JSONとは |
| 読み方 | ジェイソン | JSONとは |
| 書き方 | {"キー": 値} と [値, 値] |
書き方の決まり |
| 使える型 | 文字列・数値・真偽値・null・オブジェクト・配列 | 6つの型 |
| JSON ファイルとは | JSON を保存した拡張子 .json のテキスト | JSONファイルとは |
| 開き方 | メモ帳・VS Code・ブラウザ | 開き方・編集の仕方 |
| コメントは書ける? | 書けない(エラーになる) | よくある書き間違い |
| JavaScript との違い | キーは必ず " で囲む・関数は書けない |
JavaScriptとの違い |
| 1行1件の形式 | JSON Lines(.jsonl) | JSON Lines |
確認環境:Ubuntu 24.04.4 LTS。同じ JSON ファイルを Python 3.11.15 の json モジュール、Node.js v22.22.2 の JSON.parse・JSON.stringify、jq 1.7 で読み書きし、書き間違い12例のエラーを3つの道具で出しました。API のやり取りは Python の http.server で作った手元のサーバーに curl 8.5.0 と Node.js の fetch で送り、ブラウザでの表示は Chromium 141.0.7390.37 で、JSON Schema の検証は Python の jsonschema 4.26.0 で確かめました。仕様は RFC 8259・ECMA-404・json.org、型の対応と既定の動きは Python と MDN のドキュメント、エディタの機能は VS Code の公式ドキュメント(2026年10月21日更新)と Firefox のドキュメント、JSON Schema と JSON Lines はそれぞれの公式サイトで確かめました(確認日 2026年10月23日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「JSONとは|JSONファイルの書き方・開き方とエラー例を実物で解説」
JSONとは(意味・読み方・使われる場面)
この節では、JSON という言葉の意味と読み方、どんな場面で使われているのかが分かります。
JSON(JavaScript Object Notation)は、データを人にも機械にも読みやすい文字で表すための書き方(データ形式)です。 json.org の日本語ページでは「軽量のデータ交換フォーマット」と説明され、JavaScript の書き方の一部を元に作られたものの、特定の言語には依存しないとされています。読み方は「ジェイソン」です。
名前に JavaScript と入っていますが、Python・Java・PHP・Go など、ほとんどの言語が JSON を読み書きする仕組みを持っています。「言語が違うプログラムどうしで、データを同じ形で受け渡すための共通語」と考えると分かりやすくなります。
| 規格 | 発行 | 内容 |
|---|---|---|
| RFC 8259 | IETF・2017年12月 | インターネットの標準(STD 90)。RFC 7159 を置きかえた |
| ECMA-404 第2版 | Ecma International・2017年12月 | JSON の文法(The JSON data interchange syntax) |
| ISO/IEC 21778 | ISO・IEC | ECMA-404 のページに番号が載っている国際規格 |
身近なところでは、次の場面で毎日のように使われています。
1Web API のやり取り
天気・地図・決済などのサービスに問い合わせると、結果が JSON で返ってくる。送るデータも JSON で書くことが多い。
2画面とサーバーの通信
ブラウザの JavaScript が fetch でサーバーからデータを受け取り、画面を書きかえる。
3設定ファイル
package.json(Node.js)、VS Code の settings.json、tsconfig.json など。
4データの保存・書き出し
アプリのデータのバックアップ、ゲームのセーブデータ、サービスからのデータの書き出し。
5ログ
1行に1件の JSON を書く形式(JSON Lines)で、あとから検索・集計しやすくする。
JSONの書き方の決まり(オブジェクト・配列・6つの型)
この節では、JSON の書き方の決まりを、1つのサンプルと早見表で確かめられます。
JSON は「オブジェクト { }」と「配列 [ ]」の2つの入れ物に、6種類の値を入れて組み立てます。 この記事では、次の user.json を例に使います。
{
"id": 101,
"name": "佐藤 花子",
"email": "hanako@example.com",
"active": true,
"score": 92.5,
"tags": ["admin", "editor"],
"address": {
"pref": "東京都",
"zip": "100-0001"
},
"manager": null
}
| 入れ物 | 書き方 | 意味 | 例 |
|---|---|---|---|
| オブジェクト | { "キー": 値, ... } |
名前と値の組の集まり | {"pref": "東京都"} |
| 配列 | [ 値, 値, ... ] |
順番のある値の並び | ["admin", "editor"] |
| 型 | 書き方 | 例 | Python では | JavaScript では |
|---|---|---|---|---|
| 文字列(string) | " で囲む |
"佐藤 花子" |
str | string |
| 数値(number) | そのまま書く。整数も小数も同じ型 | 101・92.5 |
int・float | number |
| 真偽値(boolean) | 小文字の true・false |
true |
bool | boolean |
| null | 小文字の null(値が無い) |
null |
None | null |
| オブジェクト | { } |
{"zip": "100-0001"} |
dict | object |
| 配列 | [ ] |
["admin"] |
list | Array |
RFC 8259 では、値は「オブジェクト・配列・数値・文字列」か、false・null・true のどれかと決められています。真偽値の2つを1つの型として数えると、6つの型になります。オブジェクトの中にオブジェクトや配列を入れる(入れ子にする)こともできます。上の例の address がそれです。
書くときの細かい決まりです。
| 決まり | 正しい例 | 誤りの例 |
|---|---|---|
キーは必ず "(ダブルクォート)で囲む |
{"name": "花子"} |
{name: "花子"} |
文字列も " で囲む。' は使えない |
"花子" |
'花子' |
| 最後の要素の後ろにカンマを付けない | [1, 2] |
[1, 2,] |
| コメントは書けない | ― | // メモ |
true・false・null は小文字 |
true |
True |
| 数値の先頭に 0 を付けない | 12 |
012 |
NaN・Infinity は書けない |
null などで表す |
NaN |
| 空白・改行は記号の前後に自由に入れてよい | 整形しても1行でも同じ意味 | ― |
文字列の中で特別な文字を書くときは、\ を前に付けます(エスケープ)。RFC 8259 では "・\・制御文字(U+0000〜U+001F)は必ずエスケープすると決められています。
| 書きたい文字 | JSON での書き方 |
|---|---|
| 改行 | \n |
| タブ | \t |
| ダブルクォート | \" |
| バックスラッシュ(円記号) | \\ |
| 任意の文字(UTF-16 の番号) | \u3042(あ) |
Python で書き出すと、次のとおりエスケープされました。
{"msg": "1行目\n2行目", "quote": "He said \"hi\"", "path": "C:\\Users\\rjc", "tab": "A\tB", "emoji": "😀"}
JSONとJavaScriptのオブジェクトの違い
この節では、見た目がよく似た JavaScript のオブジェクトと JSON が、どこで違うのかが分かります。
JavaScript のオブジェクトはプログラムの中の「データそのもの」、JSON はそれを書き出した「文字」です。 JSON は JavaScript の書き方を元にしていますが、MDN は「JavaScript ならば JSON であるというわけではない」と説明しています。
キーと文字列の囲み
{name: 'single'} のように、キーの囲みを省け、' も使える" で囲むJSON.parse に {a: 1} を渡すと SyntaxError になった
書ける値
関数と undefined は消え、NaN は null、Date は文字列になった
末尾のカンマ・コメント
次の節で、3つの道具のエラー原文を確かめる
Node.js で、JSON に無いものを含むオブジェクトを JSON.stringify で JSON にしました。
const obj = {
name: 'single', // シングルクォートも書ける(JS の書き方)
when: new Date("2026-10-23T09:00:00+09:00"),
hello() { return "hi"; },
nothing: undefined,
big: 10n ** 2n === 100n,
nan: NaN,
inf: Infinity,
};
console.log(JSON.stringify(obj));
try { JSON.stringify({ n: 10n }); } catch (e) { console.log(e.name + ": " + e.message); }
{"name":"single","when":"2026-10-23T00:00:00.000Z","big":true,"nan":null,"inf":null}
TypeError: Do not know how to serialize a BigInt
関数 hello と undefined の nothing は黙って消え、NaN・Infinity は null に、日付は UTC の文字列になりました。 BigInt はそのままでは JSON にできずエラーです。戻したときに元と同じにならない値があるので、JSON にする前に「送りたいデータが6つの型で表せるか」を確かめます。
JSONファイルとは(拡張子・中身・文字コード)
この節では、JSON ファイルの正体と、保存するときの決まりが分かります。
JSON ファイルは、JSON の文字をそのまま保存したテキストファイルで、拡張子は .json です。 画像やアプリのような特別な形式ではなく、メモ帳でも中身を読めます。RFC 8259 では、ネットワークで使うときの種類(メディアタイプ)を application/json、拡張子を .json と決めています。
user.json を file コマンドと od(中身を16進数で見るコマンド)で調べました。
$ file user.json
user.json: JSON text data
$ wc -c user.json
228 user.json
$ od -A d -t x1z -N 48 user.json
0000000 7b 0a 20 20 22 69 64 22 3a 20 31 30 31 2c 0a 20 >{. "id": 101,. <
0000016 20 22 6e 61 6d 65 22 3a 20 22 e4 bd 90 e8 97 a4 > "name": "......<
0000032 20 e8 8a b1 e5 ad 90 22 2c 0a 20 20 22 65 6d 61 > ......",. "ema<
先頭は {(7b)から始まる、ただの文字の並びです。 「佐藤」は e4 bd 90 e8 97 a4 の6バイトで、UTF-8 という文字コードで保存されています。
| 項目 | 決まり(RFC 8259) | 守らないと |
|---|---|---|
| 文字コード | 閉じた環境の外とやり取りする JSON は UTF-8 | 日本語が文字化けする |
| BOM(先頭の目印 EF BB BF) | ネットワークで送る JSON の先頭に付けてはいけない | Python と Node.js はエラーにした(次の節) |
| 同じキー | オブジェクトのキーは重ならないようにする(SHOULD) | どれが使われるかは道具しだい |
| 大きな整数 | -(2の53乗-1)〜2の53乗-1 の範囲なら、どこでも同じ値で読める | 範囲の外は値が変わることがある |
最後の2つは、実際に道具によって結果が変わりました。{"id": 9007199254740993, "dup": 1, "dup": 2} を読み込んだ結果です。
Python 3.11 : {'id': 9007199254740993, 'dup': 2, 'price': 0.1}
Node.js 22 : { id: 9007199254740992, dup: 2, price: 0.1 }
jq 1.7 : {"id":9007199254740993,"dup":2,"price":0.1}
Node.js では ...993 が ...992 に変わりました。 JavaScript の数値は2の53乗を超える整数を正しく持てないためです。注文番号やツイートの ID のように大きな整数を送るときは、"9007199254740993" のように文字列にするのが一般的です。同じキー dup は、3つとも後の 2 を使いました。
JSONファイルの開き方・編集の仕方
この節では、パソコン・ブラウザ・コマンドで JSON ファイルを開いて、見やすく整形する方法が分かります。
JSON ファイルはテキストなので、文字を表示できるアプリならどれでも開けます。 目的ごとに使い分けると楽になります。
| 目的 | 道具 | 操作 |
|---|---|---|
| 中身をちょっと見る | Windows のメモ帳・Mac のテキストエディット | ファイルを右クリック→プログラムから開く |
| 見やすく読む | ブラウザ(Chrome・Edge・Firefox) | ファイルをブラウザの画面へドラッグ |
| 編集する | VS Code などのコードエディタ | 色分け・誤りの表示・整形ができる |
| コマンドで整形・抜き出し | jq・python3 -m json.tool |
jq . user.json |
| プログラムで扱う | Python・JavaScript など | 次の節 |
ダブルクリックで開けないときは、拡張子 .json にアプリが結び付いていないだけです。右クリックの「プログラムから開く」でテキストエディタを選びます。
ブラウザで開く
Chromium 141 で1行に詰めた JSON ファイルを開くと、文字がそのまま表示され、画面の左上に Pretty-print というチェックボックスが出ました。チェックを入れると、改行と空白2つの字下げが付いて読みやすくなりました。ページの種類(document.contentType)は application/json でした。
Firefox には JSON ビューアーが組み込まれています。Firefox のドキュメントでは、application/json で配信されたファイルや URL を色分けして表示し、検索欄での絞り込み、生の JSON の表示と整形、(ネットワークから開いたときは)リクエストとレスポンスのヘッダーの表示ができると説明されています。
VS Code で開いて編集する
VS Code は JSON を色分けし、誤りに波線を引きます。公式ドキュメントでは、ドキュメントの整形(Format Document)のショートカットは次のとおりです。
| OS | 整形のショートカット |
|---|---|
| Windows | Shift+Alt+F |
| Mac | ⇧⌥F |
| Linux | Ctrl+Shift+I |
VS Code の settings.json・tasks.json・launch.json は「JSON with Comments(jsonc)」という別のモードで、// と /* */ のコメントが書けます。 末尾のカンマも受け付けますが、使わないよう警告が出ると公式ドキュメントに書かれています。これは VS Code の設定ファイル用の書き方で、ふつうの JSON ではコメントはエラーになります。
コマンドで整形する(jq・Python)
1行に詰めた JSON と、整形した JSON の大きさを比べました。
$ jq -c . user.json > user.min.json # 1行に詰める
$ python3 -m json.tool --no-ensure-ascii user.min.json > user.pretty.json # 整形する
$ wc -c user.min.json user.pretty.json
179 user.min.json
276 user.pretty.json
python3 -m json.tool は、何も付けないと日本語を \u4f50\u85e4 のように書きかえました。 日本語のまま整形したいときは --no-ensure-ascii を付けます。Python のドキュメントでは、3.14 からは python -m json でも同じことができ、python -m json.tool も引き続き使えるとされています。
$ python3 -m json.tool user.min.json | head -3
{
"id": 101,
"name": "\u4f50\u85e4 \u82b1\u5b50",
整形ツールは、JSON の誤りを見つける道具にもなります。末尾にカンマのあるファイルを渡すと、場所を示して終了コード 1 で止まりました。
$ python3 -m json.tool bad/01_trailing.json
Expecting property name enclosed in double quotes: line 1 column 17 (char 16)
JSONを読み書きする(Python・JavaScript・jq)
この節では、同じ user.json を3つの道具で読み込み、値を取り出し、書きかえて保存した実物を確かめられます。
どの言語でも「JSON テキスト → 言語のデータ(読み込み)」と「言語のデータ → JSON テキスト(書き出し)」の2つの操作があります。
| 操作 | Python | JavaScript | jq |
|---|---|---|---|
| 文字列から読む | json.loads(s) |
JSON.parse(s) |
echo '…' | jq . |
| ファイルから読む | json.load(f) |
JSON.parse(await readFile(p, "utf8")) |
jq . file.json |
| 文字列へ書き出す | json.dumps(obj) |
JSON.stringify(obj) |
jq -c . |
| 整形して書き出す | json.dumps(obj, indent=2) |
JSON.stringify(obj, null, 2) |
jq . |
| 値を取り出す | user["address"]["pref"] |
user.address.pref |
jq '.address.pref' |
Python(json モジュール)
import json
with open("user.json", encoding="utf-8") as f:
user = json.load(f) # JSON → Python の dict
print(type(user).__name__, user["name"], user["address"]["pref"])
for k, v in user.items():
print(f"{k:8} {type(v).__name__}")
user["tags"].append("viewer") # 書きかえて
user["active"] = False
with open("user_out.json", "w", encoding="utf-8") as f:
json.dump(user, f, ensure_ascii=False, indent=2) # Python → JSON ファイル
print(json.dumps({"name": "花子"})) # 既定は \u エスケープ
print(json.dumps({"name": "花子"}, ensure_ascii=False)) # 日本語のまま
dict 佐藤 花子 東京都
id int
name str
email str
active bool
score float
tags list
address dict
manager NoneType
{"name": "\u82b1\u5b50"}
{"name": "花子"}
JSON の true は Python の True、null は None になりました。 保存した user_out.json では、"active": false に変わり、tags に "viewer" が加わっていました。Python のドキュメントでは、ensure_ascii は既定で True で、ASCII 以外の文字をすべてエスケープすると説明されています。日本語のまま保存したいときは ensure_ascii=False を付けます。書き方のレシピは、関連記事「Python JSON 読み書き|コピペレシピと実行結果・3.14対応」で扱っています。
JavaScript(JSON.parse・JSON.stringify)
import { readFile, writeFile } from "node:fs/promises";
const text = await readFile("user.json", "utf8");
const user = JSON.parse(text); // JSON テキスト → オブジェクト
console.log(typeof user, user.name, user.tags.length, user.manager);
user.score += 1;
await writeFile("user_out2.json", JSON.stringify(user, null, 2) + "\n");
console.log(JSON.stringify({ id: 1, name: "花子" })); // 1行(最小)
object 佐藤 花子 2 null
{"id":1,"name":"花子"}
JSON.stringify は、日本語をエスケープせずにそのまま書き出しました。2つ目の引数で書き出す項目を選び、3つ目の引数で字下げの数を決めます。JSON.parse のエラーの原因と整形の方法は、関連記事「JSON.parseとJSON.stringifyの使い方|エラー原因と整形」で扱っています。
jq(コマンドで読む・書きかえる)
jq は、JSON を取り出したり形を変えたりするコマンドです。公式サイトでは「軽量で柔軟なコマンドラインの JSON プロセッサ」と説明され、2026年10月23日時点の最新は 1.8.2(2026年6月20日)です。手元では Ubuntu 24.04 の apt の 1.7 を使いました。
$ jq '.name' user.json
"佐藤 花子"
$ jq -r '.name' user.json # -r で " を外す
佐藤 花子
$ jq '.tags[0]' user.json # 配列の0番目
"admin"
$ jq '.address.pref' user.json # 入れ子をたどる
"東京都"
$ jq -c '{id, name, pref: .address.pref}' user.json # 形を変える
{"id":101,"name":"佐藤 花子","pref":"東京都"}
$ jq '.tags | length' user.json
2
$ jq '.missing' user.json # 無いキーは null
null
$ jq '.active = false | .tags += ["viewer"]' user.json > user_jq.json # 書きかえて保存
$ jq -c . user_jq.json
{"id":101,"name":"佐藤 花子","email":"hanako@example.com","active":false,"score":92.5,"tags":["admin","editor","viewer"],"address":{"pref":"東京都","zip":"100-0001"},"manager":null}
. で全体、.キー でオブジェクトの値、[番号] で配列の要素を指します。 番号は0から数えます。条件で絞る・集計するなどの書き方は、関連記事「jqの使い方|逆引き40例と実務レシピを全部実行結果つきで解説」で扱っています。
よくある書き間違いとエラー原文(末尾のカンマ・シングルクォート・コメント)
この節では、JSON を手で書いたときにつまずきやすい12の書き間違いと、Python・Node.js・jq が出したエラー原文、直し方が分かります。
12個のファイルを作り、同じものを3つの道具で読み込みました。
== Python 3.11(json.load)
01_trailing.json: JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 17 (char 16)
02_single.json: JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)
03_comment.json: JSONDecodeError: Expecting ',' delimiter: line 2 column 10 (char 11)
04_nokey.json: JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)
05_nocomma.json: JSONDecodeError: Expecting ',' delimiter: line 2 column 2 (char 9)
06_zero.json: JSONDecodeError: Expecting ',' delimiter: line 1 column 8 (char 7)
07_true.json: JSONDecodeError: Expecting value: line 1 column 8 (char 7)
08_empty.json: JSONDecodeError: Expecting value: line 1 column 1 (char 0)
09_bom.json: JSONDecodeError: Unexpected UTF-8 BOM (decode using utf-8-sig): line 1 column 1 (char 0)
10_fullwidth.json: JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)
11_nan.json: OK {'n': nan}
12_ctrl.json: JSONDecodeError: Invalid control character at: line 1 column 10 (char 9)
== Node.js 22(JSON.parse)
01_trailing.json: SyntaxError: Expected double-quoted property name in JSON at position 16 (line 1 column 17)
02_single.json: SyntaxError: Expected property name or '}' in JSON at position 1 (line 1 column 2)
03_comment.json: SyntaxError: Expected ',' or '}' after property value in JSON at position 11 (line 2 column 10)
04_nokey.json: SyntaxError: Expected property name or '}' in JSON at position 1 (line 1 column 2)
05_nocomma.json: SyntaxError: Expected ',' or '}' after property value in JSON at position 9 (line 2 column 2)
06_zero.json: SyntaxError: Unexpected number in JSON at position 7 (line 1 column 8)
07_true.json: SyntaxError: Unexpected token 'T', "{"ok": True}" is not valid JSON
08_empty.json: SyntaxError: Unexpected end of JSON input
09_bom.json: SyntaxError: Unexpected token '', "{"a": 1}" is not valid JSON
10_fullwidth.json: SyntaxError: Expected property name or '}' in JSON at position 1 (line 1 column 2)
11_nan.json: SyntaxError: Unexpected token 'N', "{"n": NaN}" is not valid JSON
12_ctrl.json: SyntaxError: Bad control character in string literal in JSON at position 9 (line 1 column 10)
== jq 1.7
01_trailing.json: jq: parse error: Expected another key-value pair at line 1, column 17
02_single.json: jq: parse error: Invalid numeric literal at line 1, column 5
03_comment.json: jq: parse error: Invalid numeric literal at line 2, column 12
04_nokey.json: jq: parse error: Invalid numeric literal at line 1, column 3
05_nocomma.json: jq: parse error: Expected separator between values at line 2, column 4
06_zero.json: {"n":12}
07_true.json: jq: parse error: Invalid numeric literal at line 1, column 12
08_empty.json: (何も出力しない)
09_bom.json: {"a":1}
10_fullwidth.json: jq: parse error: Invalid numeric literal at line 1, column 9
11_nan.json: {"n":null}
12_ctrl.json: jq: parse error: Invalid string: control characters from U+0000 through U+001F must be escaped at line 2, column 7
| 書き間違い | ファイルの中身 | 直し方 |
|---|---|---|
| 01 末尾のカンマ | {"a": 1, "b": 2,} |
最後の要素の後ろのカンマを消す |
| 02 シングルクォート | {'a': 1} |
' を " に置きかえる |
| 03 コメント | "a": 1 // コメント |
コメントを消す。説明は別のキーかドキュメントに書く |
| 04 キーを囲んでいない | {a: 1} |
{"a": 1} にする |
| 05 カンマの付け忘れ | "a": 1 改行 "b": 2 |
要素の間に , を入れる |
| 06 先頭が0の数値 | {"n": 012} |
12。0 で始まる番号は文字列 "012" にする |
| 07 大文字の True | {"ok": True} |
小文字の true |
| 08 空のファイル | (0バイト) | 中身が届いているか、読む前に確かめる |
| 09 先頭に BOM | EF BB BF {"a": 1} |
BOM なしの UTF-8 で保存し直す |
| 10 全角の引用符 | {“a”: 1} |
半角の " にする(文書からのコピーで起きやすい) |
| 11 NaN | {"n": NaN} |
null にするか、文字列にする |
| 12 文字列の中の改行 | "改行 改行 入り" |
\n と書く |
エラー文の「line 行 column 列」や「position 位置」は、読み込みが止まった場所です。 原因はその場所か、その少し前にあります。たとえば末尾のカンマ(01)は、カンマの次の } の位置(17列目)で止まっています。
3つの道具の結果を見比べると、道具によって受け付ける範囲が少し違うことが分かります。
| ファイル | Python 3.11 | Node.js 22 | jq 1.7 | 規格(RFC 8259)では |
|---|---|---|---|---|
| 06 先頭が0 | エラー | エラー | 12 として読んだ |
誤り |
| 09 BOM | エラー | エラー | 読んだ | 送る側が付けてはいけない |
| 11 NaN | nan として読んだ |
エラー | null にした |
誤り |
| 08 空 | エラー | エラー | 何も出さず終了 | 誤り |
ある道具で読めても、ほかの道具では読めないことがあります。 自分で書く JSON は、規格どおりに書いておくのが安全です。Python のドキュメントにも、RFC は NaN と無限大を認めていないが、json モジュールは既定でそれらを受け付けて書き出すと書かれています。書き出すときに止めたい場合は json.dumps(obj, allow_nan=False) で、手元では ValueError: Out of range float values are not JSON compliant が出ました。
BOM 付きのファイルを Python で読むときは、エラー文のとおり encoding="utf-8-sig" を指定すると {'a': 1} として読めました。Python の JSONDecodeError のうち Expecting value が出る原因の切り分けは、関連記事「JSONDecodeError: Expecting valueの直し方」で扱っています。
- 1キーと文字列はすべて半角の " で囲んだ' や全角の引用符が混じっていない
- 2最後の要素の後ろにカンマが無い行を消したあと、1つ前の行に残りやすい
- 3コメントを書いていない// や /* */ はふつうの JSON ではエラー
- 4true・false・null が小文字Python の True・None をそのまま書いていない
- 5BOM なしの UTF-8 で保存したエディタの保存形式で選べる
- 6保存したら整形ツールに通したjq . や python3 -m json.tool がエラーを出さない
APIでのJSONのやり取り(curlで送受信)
この節では、API が JSON をどう送り、どう返すのかを、手元のサーバーと curl で実際に確かめられます。
API で JSON を送るときは、本文(ボディ)に JSON の文字を入れ、ヘッダーの Content-Type: application/json で「中身は JSON です」と伝えます。 受け取る側はこのヘッダーを見て、本文を JSON として読み込みます。
flowchart TD
C[クライアント<br>curl・ブラウザ・アプリ] -->|POST 本文に JSON<br>Content-Type application/json| S[サーバー<br>JSON を読み込む]
S -->|正しい JSON| OK[201 Created<br>登録したデータの JSON]
S -->|書き間違い 400<br>種類が違う 415| NG[エラー内容の JSON]
Python の標準ライブラリだけで、ユーザーを取得・登録する小さな API を作りました。
import json
from http.server import BaseHTTPRequestHandler, HTTPServer
USERS = {101: {"id": 101, "name": "佐藤 花子", "active": True}}
class Handler(BaseHTTPRequestHandler):
def send_json(self, status, body):
data = json.dumps(body, ensure_ascii=False).encode("utf-8")
self.send_response(status)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(data)))
self.end_headers()
self.wfile.write(data)
def do_GET(self):
uid = int(self.path.rsplit("/", 1)[-1])
if uid in USERS:
self.send_json(200, USERS[uid])
else:
self.send_json(404, {"error": "not found"})
def do_POST(self):
if self.headers.get("Content-Type", "").split(";")[0] != "application/json":
return self.send_json(415, {"error": "Content-Type must be application/json"})
raw = self.rfile.read(int(self.headers.get("Content-Length", 0)))
try:
body = json.loads(raw)
except json.JSONDecodeError as e:
return self.send_json(400, {"error": "invalid JSON", "detail": str(e)})
new_id = max(USERS) + 1
USERS[new_id] = {"id": new_id, **body}
self.send_json(201, USERS[new_id])
HTTPServer(("127.0.0.1", 38201), Handler).serve_forever()
受け取る(GET)
$ curl -i http://127.0.0.1:38201/api/users/101
HTTP/1.0 200 OK
Server: BaseHTTP/0.6 Python/3.11.15
Date: Fri, 23 Oct 2026 08:41:58 GMT
Content-Type: application/json
Content-Length: 52
{"id": 101, "name": "佐藤 花子", "active": true}
送る(POST)
$ curl -i -X POST http://127.0.0.1:38201/api/users \
-H 'Content-Type: application/json' \
-d '{"name": "鈴木 一郎", "active": false}'
HTTP/1.0 201 Created
Content-Type: application/json
Content-Length: 53
{"id": 102, "name": "鈴木 一郎", "active": false}
手元の curl 8.5.0 には --json があり、ヘッダーを自分で書かずに送れます。-v で送ったヘッダーを見ると、Content-Type と Accept の2つが自動で付いていました。Content-Length: 25 は、「高橋 次郎」(UTF-8 で13バイト)を含む本文のバイト数です。
$ curl -v --json '{"name": "高橋 次郎"}' http://127.0.0.1:38201/api/users
> POST /api/users HTTP/1.1
> Host: 127.0.0.1:38201
> User-Agent: curl/8.5.0
> Content-Type: application/json
> Accept: application/json
> Content-Length: 25
>
< HTTP/1.0 201 Created
{"id": 104, "name": "高橋 次郎"}
間違えたとき(400・415)
$ curl -X POST http://127.0.0.1:38201/api/users -H 'Content-Type: application/json' -d "{'name': 'x'}"
{"error": "invalid JSON", "detail": "Expecting property name enclosed in double quotes: line 1 column 2 (char 1)"}
$ curl -X POST http://127.0.0.1:38201/api/users -d '{"name": "x"}'
{"error": "Content-Type must be application/json"}
2つ目は JSON の中身は正しいのに、415 になりました。 curl の -d は、ヘッダーを付けないと Content-Type: application/x-www-form-urlencoded(フォームの形式)で送るためです。API に JSON を送って 400 や 415 が返ったら、本文の書き方とヘッダーの両方を確かめます。curl のオプションの使い方は、関連記事「curlコマンドの使い方|よく使うオプションとAPIの確認方法」で扱っています。
JavaScript の fetch で送受信する
const res = await fetch("http://127.0.0.1:38201/api/users", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name: "田中 美咲", active: true }), // オブジェクト → JSON
});
console.log(res.status, res.headers.get("content-type"));
const data = await res.json(); // JSON → オブジェクト
console.log(data, typeof data.id);
201 application/json
{ id: 105, name: '田中 美咲', active: true } number
送るときは JSON.stringify で文字にし、受け取ったら res.json() でオブジェクトに戻します。 サーバーが JSON ではなく HTML のエラーページを返すと、res.json() は次のエラーになりました(Node.js 22 の Response に HTML の文字を渡して確かめたもの)。
SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON
JSON Schemaで中身を検証する
この節では、JSON の「形」は正しくても「中身」が期待と違うときに、JSON Schema で見つける方法が分かります。
JSON Schema は、「このキーは必須」「この値は整数」「0〜100の範囲」といった JSON の決まりを、JSON で書いておくための仕様です。 公式サイトでは、2026年10月23日時点の最新版は 2020-12 です。
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "ユーザー",
"type": "object",
"required": ["id", "name", "email"],
"properties": {
"id": { "type": "integer", "minimum": 1 },
"name": { "type": "string", "minLength": 1 },
"email": { "type": "string", "pattern": "^[^@]+@[^@]+$" },
"active": { "type": "boolean" },
"score": { "type": "number", "minimum": 0, "maximum": 100 },
"tags": { "type": "array", "items": { "type": "string" } }
},
"additionalProperties": true
}
Python の jsonschema 4.26.0 で、正しいデータ(user.json)と、書き方は正しいが中身が違うデータを検証しました。
import json, sys
from jsonschema import Draft202012Validator
schema = json.load(open("user.schema.json", encoding="utf-8"))
v = Draft202012Validator(schema)
for path in sys.argv[1:]:
data = json.load(open(path, encoding="utf-8"))
errors = sorted(v.iter_errors(data), key=lambda e: list(e.path))
print(f"{path}: {'OK' if not errors else f'{len(errors)} 件のエラー'}")
for e in errors:
print(f" {'/'.join(map(str, e.path)) or '(全体)'}: {e.message}")
$ echo '{"id": "101", "name": "", "score": 120, "tags": ["admin", 1]}' > user_bad.json
$ python validate.py user.json user_bad.json
user.json: OK
user_bad.json: 5 件のエラー
(全体): 'email' is a required property
id: '101' is not of type 'integer'
name: '' should be non-empty
score: 120 is greater than the maximum of 100
tags/1: 1 is not of type 'string'
user_bad.json は JSON としては正しく読み込めますが、決まりに合わない点が5つ見つかりました。 API の入り口でこの検証をしておくと、おかしなデータを保存する前に止められます。
| よく使うキーワード | 意味 |
|---|---|
type |
型(object・array・string・number・integer・boolean・null) |
required |
必ずあるべきキーの一覧 |
properties |
キーごとの決まり |
minimum・maximum |
数値の下限・上限 |
minLength・pattern |
文字列の長さ・正規表現 |
items |
配列の要素の決まり |
enum |
決まった値のどれか |
additionalProperties |
書いていないキーを許すか |
VS Code では、JSON ファイルに $schema キーを書くか、設定の json.schemas でファイル名とスキーマを結び付けると、入力中に誤りを表示し、候補を出します。公式ドキュメントでは、$schema キーを書く方法は VS Code 独自のもので、JSON の中身が変わるため受け取る側が想定していないことがある、と注意されています。
JSON Lines(.jsonl)とは
この節では、ログや大量のデータでよく使う JSON Lines の形と、ふつうの JSON との違いが分かります。
JSON Lines は、1行に1つの JSON を書き、改行で区切る形式です。 公式サイトでは、UTF-8 で BOM を付けない、各行が正しい JSON の値、行の終わりは \n、拡張子は .jsonl が使える、とされています。メディアタイプは application/jsonl が提案されていますが、まだ正式には決まっていません。
ふつうの JSON(配列)
ファイル全体で1つの値。[{...}, {...}]
全部を読み終えないと使えない
追記するには最後の ] の前に入れ直す
JSON Lines(.jsonl)
1行に1件。行ごとに独立した JSON
1行ずつ読んで処理できる
ファイルの末尾に1行足すだけで追記できる
アクセスログを JSON Lines で書き、Python と jq で読みました。
{"time": "2026-10-23T09:00:01+09:00", "path": "/", "status": 200, "ms": 12}
{"time": "2026-10-23T09:00:02+09:00", "path": "/api/users", "status": 201, "ms": 48}
{"time": "2026-10-23T09:00:03+09:00", "path": "/api/users/999", "status": 404, "ms": 5}
{"time": "2026-10-23T09:00:04+09:00", "path": "/login", "status": 500, "ms": 230}
import json
with open("access.jsonl", encoding="utf-8") as f:
rows = [json.loads(line) for line in f if line.strip()] # 1行ずつ読む
print(len(rows), "行", [r["status"] for r in rows])
print("4xx/5xx:", [r["path"] for r in rows if r["status"] >= 400])
try:
json.load(open("access.jsonl", encoding="utf-8")) # 全体を1つの JSON として読むと…
except json.JSONDecodeError as e:
print("JSONDecodeError:", e)
4 行 [200, 201, 404, 500]
4xx/5xx: ['/api/users/999', '/login']
JSONDecodeError: Extra data: line 2 column 1 (char 76)
$ jq -c 'select(.status >= 400) | {path, status}' access.jsonl
{"path":"/api/users/999","status":404}
{"path":"/login","status":500}
$ jq -s 'map(.ms) | add / length' access.jsonl # -s で配列にまとめて平均
73.75
JSON Lines のファイルを json.load で丸ごと読むと、2行目で Extra data のエラーになりました。 1行ずつ json.loads で読むのが正しい読み方です。jq は1行ずつ処理し、-s を付けると全体を1つの配列にまとめます。
JSONとCSV・XML・YAMLの違い
この節では、よく比べられるデータ形式と JSON の違いが、早見表で分かります。
JSON は入れ子のデータを短く書け、ほとんどの言語が標準で読めるので、API のやり取りでよく選ばれます。 表の形だけなら CSV、人が手で書く設定なら YAML、文書の構造や属性を細かく表すなら XML が選ばれることがあります。
| 形式 | 見た目 | 入れ子 | コメント | よく使う場面 |
|---|---|---|---|---|
| JSON | {"name": "花子"} |
できる | 書けない | API・設定・データの受け渡し |
| CSV | name,pref の行 |
できない(表だけ) | 決まりが無い | 表のデータの受け渡し |
| XML | <name>花子</name> |
できる | <!-- --> |
文書・業務システムのデータ・RSS |
| YAML | name: 花子 |
字下げでできる | # |
設定ファイル(CI・Kubernetes など) |
同じデータを5つの形式で書いて読み込んだ比較と、選び方の判断表は、関連記事「CSV・JSON・XML・YAML・TOMLの違いと使い分け|同じデータで比較」で扱っています。
よくある質問
Q. JSON とは簡単に言うと何ですか?
A. データを文字で表すための決まった書き方です。{"name": "花子", "age": 20} のように、名前と値の組を { } で、並びを [ ] で書きます。言語が違うプログラムの間でデータを受け渡すときによく使われます。
Q. JSON の読み方は? A. 「ジェイソン」と読みます。JavaScript Object Notation の頭文字です。
Q. JSON ファイルとは何ですか?どうやって開きますか? A. JSON の文字を保存した、拡張子 .json のテキストファイルです。メモ帳・テキストエディット・VS Code で開け、ブラウザに読み込むと整形して表示できます(Chromium 141 では Pretty-print のチェックボックスが出ました)。
Q. JSON にコメントは書けますか?
A. 書けません。// を入れると、Python・Node.js・jq のどれもエラーになりました。VS Code の settings.json などは JSON with Comments という別のモードなので、コメントが書けます。
Q. JSON の末尾にカンマを付けるとどうなりますか?
A. エラーになります。Python では Expecting property name enclosed in double quotes、Node.js では Expected double-quoted property name in JSON と出ました。最後の要素の後ろのカンマを消します。
Q. JSON でシングルクォートは使えますか?
A. 使えません。キーも文字列も "(ダブルクォート)で囲みます。{'a': 1} は3つの道具すべてでエラーになりました。
Q. JSON で使えるデータ型は? A. 文字列・数値・真偽値(true・false)・null・オブジェクト・配列の6つです。日付は文字列で、関数は書けません。
Q. JSON と JavaScript のオブジェクトの違いは?
A. JSON はデータを書き出した文字で、キーと文字列を必ず " で囲み、関数・undefined・コメント・末尾のカンマは書けません。JSON.stringify で JavaScript のオブジェクトを JSON にすると、関数と undefined は消えました。
Q. JSON の配列とは?
A. [ と ] で囲んだ、順番のある値の並びです。["admin", "editor"] のように書き、0番目から数えます。jq では .tags[0] で最初の要素を取り出せます。
Q. 日本語が \u82b1 のようになるのはなぜですか?
A. Python の json.dumps と python3 -m json.tool は、既定で ASCII 以外の文字をエスケープするためです。ensure_ascii=False か --no-ensure-ascii を付けると日本語のまま出ました。
Q. JSON Lines(jsonl)とは? A. 1行に1つの JSON を書く形式です。ログのように1件ずつ追記するデータに向き、1行ずつ読んで処理できます。
Q. JSON Schema とは? A. JSON の中身の決まり(必須のキー・型・範囲)を JSON で書くための仕様で、2026年10月23日時点の最新版は 2020-12 です。決まりに合わないデータを、保存する前に見つけられます。
Q. JSON と XML の違いは?
A. どちらも入れ子のデータを表せます。JSON は {"name": "花子"} のように短く書け、XML は <name>花子</name> のようにタグで囲み、属性やコメントも書けます。
まとめ
- JSON は、データを文字で表す決まった書き方(読み方はジェイソン)。RFC 8259 と ECMA-404 で決められ、言語をまたいでデータを受け渡すのに使う。
- 入れ物はオブジェクト
{ }と配列[ ]、値は文字列・数値・真偽値・null・オブジェクト・配列の6つ。キーと文字列は必ず"で囲む。 - JSON ファイルは拡張子 .json の UTF-8 のテキスト。メモ帳・VS Code・ブラウザで開け、jq や
python3 -m json.toolで整形と誤りの確認ができる。 - 末尾のカンマ・シングルクォート・コメントなど12の書き間違いは、Python・Node.js・jq で異なるエラー文になり、道具によっては読めてしまうものもあった。規格どおりに書くのが安全。
- API では本文に JSON、ヘッダーに
Content-Type: application/json。ヘッダーが無いと 415、書き間違いは 400 になった。 - 中身の決まりは JSON Schema(2020-12)で検証し、ログのように1件ずつ増えるデータは JSON Lines で書く。
参考・出典
確認日はいずれも 2026年10月23日です。
- IETF「RFC 8259: The JavaScript Object Notation (JSON) Data Interchange Format」:https://www.rfc-editor.org/rfc/rfc8259
- Ecma International「ECMA-404 The JSON data interchange syntax」:https://ecma-international.org/publications-and-standards/standards/ecma-404/
- json.org「JSON の紹介」:https://www.json.org/json-ja.html
- MDN Web Docs「JSON」:https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/JSON
- Python ドキュメント「json --- JSON エンコーダおよびデコーダ」:https://docs.python.org/3/library/json.html
- jq 公式サイト:https://jqlang.org/
- Visual Studio Code「JSON editing in Visual Studio Code」:https://code.visualstudio.com/docs/languages/json
- Firefox Source Docs「JSON viewer」:https://firefox-source-docs.mozilla.org/devtools-user/json_viewer/index.html
- JSON Schema「Specification」:https://json-schema.org/specification
- JSON Lines:https://jsonlines.org/
- @IT「JSON(ジェイソン)」:https://atmarkit.itmedia.co.jp/ait/articles/1602/29/news046.html
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「JSONとは|JSONファイルの書き方・開き方とエラー例を実物で解説」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。