Views: 2
AWS EC2 上で JSON Schema Draft 2020-12 + UN/CEFACT スキーマを検証する環境構築手順
2025-06-07
本記事では、UN/CEFACT によって公開されている JSON Schema 定義と XBRL GL インスタンスを使用して、Amazon EC2 上に JSON Schema Draft 2020-12 準拠の検証環境を構築する手順を紹介します。
1. 前提環境の構築
1.1. OS と Node.js のバージョン確認
Amazon Linux 2 では fs/promises
や ajv/dist/2020
の読み込みなどに問題があったため、Amazon Linux 2023 を使用しました。
$ uname -a
Linux ip-xxx.ap-northeast-1.compute.internal ...
$ cat /etc/os-release
NAME="Amazon Linux"
VERSION="2023"
Node.js は以下のとおりバージョン 18.20.8 を使用:
$ node -v
v18.20.8
1.2. 必要なモジュールのインストール
$ npm install ajv@8.17.1 ajv-formats@3.0.1
Note
|
開発初期段階では以下のように
ただし、 |
2. UN/CEFACT スキーマの取得
2.1. GitHub からの取得方法(推奨)
$ git clone https://github.com/uncefact/spec-JSONschema.git
$ cd spec-JSONschema/JSONschema2020-12/library/BuyShipPay/D23B/
2.2. curl で個別取得する場合
$ mkdir -p schemas/meta schemas/codelists
$ curl -L -o schemas/meta/metadata.json \
https://raw.githubusercontent.com/uncefact/spec-JSONschema/main/JSONschema2020-12/library/BuyShipPay/D23B/meta/metadata.json
$ curl -L -o schemas/UNECE-BasicComponents.json \
https://raw.githubusercontent.com/uncefact/spec-JSONschema/main/JSONschema2020-12/library/BuyShipPay/D23B/UNECE-BasicComponents.json
$ curl -L -o schemas/codelists/UnitCode.json \
https://raw.githubusercontent.com/uncefact/spec-JSONschema/main/JSONschema2020-12/library/BuyShipPay/D23B/codelists/UnitCode.json
2.3. Draft 2020-12 スキーマの取得
JSON Schema の $schema
URI に指定される:
https://json-schema.org/draft/2020-12/schema
このメタスキーマは curl で取得時にリダイレクトされるため、必ず -L
オプションを使用します。
$ curl -L -o schemas/draft2020-12.json https://json-schema.org/draft/2020-12/schema
-L
を省略すると HTML が保存されてしまい、AJV が "Unknown format"
というエラーでスキーマを処理できなくなります。
3. 検証スクリプト validate.js
以下は validate.js
の主要部分です。
const Ajv2020 = require("ajv/dist/2020");
const addFormats = require("ajv-formats");
const fs = require("fs/promises");
const ajv = new Ajv2020({ loadSchema, strict: false });
addFormats(ajv);
3.1. $ref
を解決する loadSchema 関数
async function loadSchema(uri) {
if (uri === "http://json-schema.org/draft/2020-12/schema") {
return JSON.parse(await fs.readFile("schemas/draft2020-12.json", "utf8"));
}
if (uri.endsWith("metadata.json")) {
return JSON.parse(await fs.readFile("schemas/meta/metadata.json", "utf8"));
}
if (uri.includes("UNECE-BasicComponents")) {
return JSON.parse(await fs.readFile("schemas/UNECE-BasicComponents.json", "utf8"));
}
if (uri.includes("UnitCode.json")) {
return JSON.parse(await fs.readFile("schemas/codelists/UnitCode.json", "utf8"));
}
throw new Error("Unresolved schema: " + uri);
}
3.2. スキーマとインスタンスの検証実行
const schema = await ajv.compileAsync(
JSON.parse(await fs.readFile("schemas/xbrl-gl-cor-schema.json"))
);
const data = JSON.parse(await fs.readFile("samples/xbrl-gl-instance.json"));
if (schema(data)) {
console.log("✅ Validation passed");
} else {
console.error("❌ Validation errors:", schema.errors);
}
4. metadata.json の役割と混乱
UN/CEFACT スキーマでは、"meta/metadata"
のように $ref
を通じてメタ情報を参照します。
誤ってファイル名を metadata.json
ではなく meta-data.json
として処理しようとすると、loadSchema()
で正しく読み込めずに検証に失敗します。
"unece:metadata": {
"$ref": "meta/metadata"
}
5. ディレクトリ構成例
project-root/
├── validate.js
├── schemas/
│ ├── draft2020-12.json
│ ├── meta/
│ │ └── metadata.json
│ ├── codelists/
│ │ └── UnitCode.json
│ ├── UNECE-BasicComponents.json
│ └── xbrl-gl-cor-schema.json
└── samples/
└── xbrl-gl-instance.json
6. format 検証の有効化
以下のように format
キーワードを使うと、ajv-formats
により自動的に検証されます。
{
"type": "string",
"format": "date-time"
}
7. まとめ
-
Amazon Linux 2023 + Node.js v18.20.8 は Draft 2020-12 に適した環境
-
ajv@8.17.1
とajv-formats@3.0.1
は Draft 2020-12 と format 検証に完全対応 -
GitHub の UN/CEFACT スキーマはローカル保存し
$ref
解決経路を明示する -
curl -L
を忘れずに使用し、誤って HTML を保存しないよう注意 -
meta-data.json
と誤記するとmetadata.json
の$ref
解決に失敗するため注意が必要
8. 参考リンク
-
UN/CEFACT JSON Schema:
https://github.com/uncefact/spec-JSONschema -
JSON Schema:
https://json-schema.org/ -
AJV GitHub:
https://github.com/ajv-validator/ajv
9. validate.js
const fs = require("fs").promises;
const path = require("path");
const Ajv2020 = require("ajv/dist/2020");
const addFormats = require("ajv-formats");
async function loadSchema(uri) {
const base = path.resolve(__dirname, "schemas");
// Draft 2020-12 メインスキーマ
if (uri === "http://json-schema.org/draft/2020-12/schema") {
const fullPath = path.join(base, "draft2020-12.json");
const schema = JSON.parse(await fs.readFile(fullPath, "utf8"));
delete schema["$id"];
return schema;
}
// 各 vocabulary メタスキーマ
const vocabularies = [
"core",
"applicator",
"unevaluated",
"validation",
"meta-data",
"format-annotation",
"content"
];
for (const name of vocabularies) {
if (uri === `http://json-schema.org/draft/2020-12/meta/${name}`) {
const fullPath = path.join(base, "meta", `${name}.json`);
const schema = JSON.parse(await fs.readFile(fullPath, "utf8"));
delete schema["$id"];
return schema;
}
}
// その他カスタムスキーマ
if (uri.includes("UNECE-BasicComponents.json")) {
const fullPath = path.join(
__dirname,
"../uncefact/spec-JSONschema/JSONschema2020-12/library/BuyShipPay/D23B/UNECE-BasicComponents.json"
);
return JSON.parse(await fs.readFile(fullPath, "utf8"));
}
if (uri.includes("codelists/")) {
const fileName = path.basename(uri);
const fullPath = path.join(
__dirname,
"../uncefact/spec-JSONschema/JSONschema2020-12/library/BuyShipPay/D23B/codelists",
fileName
);
return JSON.parse(await fs.readFile(fullPath, "utf8"));
}
throw new Error(`Unknown schema URI: ${uri}`);
}
const ajv = new Ajv2020({
loadSchema,
strict: false
});
addFormats(ajv);
(async () => {
try {
const schemaPath = path.join(__dirname, "schemas/xbrl-gl-cor-schema.json");
const instancePath = path.join(__dirname, "samples/xbrl-gl-instance.json");
const schema = JSON.parse(await fs.readFile(schemaPath, "utf8"));
const data = JSON.parse(await fs.readFile(instancePath, "utf8"));
const validate = await ajv.compileAsync(schema);
const valid = validate(data);
if (valid) {
console.log("✅ Validation successful: data is valid against the schema.");
} else {
console.error("❌ Validation errors:");
console.error(validate.errors);
}
} catch (err) {
console.error("💥 Runtime error:", err);
}
})();
コメントを残す