0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

JSON の整形・エスケープ・読み込みを分けて検証する小さな Node.js テスト

0
Posted at

目的と前提

JSON を整形した後に「読みやすくなった」だけで処理を終えると、文字列の先頭ゼロや null と欠落値の違いを見落とします。この記事では、ファイルを読む・文字列として包む・空白を減らす操作を、小さな Node.js の検証コードで分けます。

開示:QoTool の運営側からの投稿で、自社ツールへのリンクを含みます。文章とコードは AI を利用して作成し、掲載する検証項目は Node.js で実行して確認しました。サンプルは架空のデータです。ツールを使わなくても、以下のコードだけで確認できます。

1. ファイル名ではなくルートの型を確認する

英語の質問なら how do you open a json file に当たる作業です。まず元ファイルを残し、コピーをテキストとして開きます。QoTool の画面では Open file から読み込めます。表示上の入力上限は 5 MB、大きいデータはプレビュー範囲が制限されるため、画面に見える件数だけで全件数を判断しません。

JSON のルートはオブジェクトとは限りません。配列、文字列、数値、真偽値、null も有効です。また、拡張子が .json でも、実体が一行一件の JSONL のことがあります。複数行に独立したオブジェクトが並ぶ入力は、単一の JSON.parse では処理できません。

2. 変換後の値を比較するテスト

次を check-json.cjs として保存し、node check-json.cjs で実行します。追加パッケージは不要です。成功時は最後に PASS が表示されます。

const assert = require('node:assert/strict');

const value = {
  id: '0007',
  message: 'two words',
  empty: '',
  absent: null,
  flags: [true, false]
};
const pretty = JSON.stringify(value, null, 2);
const compact = JSON.stringify(JSON.parse(pretty));

assert.deepEqual(JSON.parse(compact), value);
assert.equal(JSON.parse(compact).id, '0007');
assert.equal(JSON.parse(compact).message, 'two words');
assert.equal(Object.hasOwn(JSON.parse(compact), 'absent'), true);
assert.equal(Object.hasOwn(JSON.parse(compact), 'missing'), false);

const quotedText = JSON.stringify(pretty);
assert.equal(typeof JSON.parse(quotedText), 'string');
assert.equal(JSON.parse(quotedText), pretty);

assert.throws(() => JSON.parse('{"a":1,}'));
assert.throws(() => JSON.parse('{"a":1}' + String.fromCharCode(10) + '{"a":2}'));
console.log('PASS');

重要なのは、整形後の文字列そのものを比較する場合と、パース後の値を比較する場合を区別することです。インデントは変わってよい一方、id の先頭ゼロや message の内部の空白は変えてはいけません。

3. エスケープは別の操作

ログや設定値に JSON の本文を文字列として格納するなら、escape json に相当する操作を行います。上の quotedText は、pretty の本文を一つの JSON 文字列として包んだ結果です。これを一度パースしても、オブジェクトではなく文字列が得られます。

二重に包まれた入力を扱う場合は、一度戻した時点で型を確認します。常に二度 JSON.parse する処理にすると、正当な文字列まで JSON として解釈しようとします。画面上のバックスラッシュだけを一括削除する方法も、引用符や改行を壊す原因になります。

4. 圧縮の意味を限定する

json minify は、JSON の構造上不要な空白を減らす作業です。文字列の中の空白を削除する作業ではありません。上のテストでは two words が同じ値で残ることを確認しています。

この JavaScript の例を任意のデータにそのまま適用する際には、数値精度にも注意します。Number.MAX_SAFE_INTEGER を超える整数は JSON.parse の段階で丸められる場合があります。ID を文字列として扱う仕様なら、最初から文字列として保持します。数値であることが必須の仕様なら、桁を保持するパーサーを使い、出力先まで正確な数字列を確認します。

5. このテストが保証しないこと

このサンプルは JSON で表現できる値だけを対象にしています。Date、Map、undefined、循環参照などの JavaScript オブジェクトを損失なく保存するテストではありません。JSON Schema による業務ルールの検証も別途必要です。

実際の連携では、空配列、空文字、null、欠落フィールド、引用符と改行を含む文字列、大きな整数のサンプルを追加すると、見た目では気づきにくい変化を検出できます。修復、整形、エスケープを別々の工程として記録しておくと、どこで値が変わったかを調べやすくなります。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?