Tanpa additionalProperties, pengesahan skema tidak mengesahkan apa-apa
Inti pati: Pengesahan yang lulus tidak bermakna data bersih. Pydantic secara lalai mengabaikan medan asing, Zod mengalihkannya, Ajv membiarkannya — parameter halusinasi dan kunci tersilap lolos tanpa bunyi. Artikel ini menunjukkan tiga bentuk penerimaan senyap dan memberikan resipi lengkap: menutup objek, mengawal paksaan jenis, menggenggam setiap peringkat bersarang.

Kesimpulan: secara lalai, pengesah mengabaikan medan yang tidak diisytiharkan dan bukannya menolaknya. Tanpa additionalProperties: false, kelulusan hanya membuktikan medan yang diisytiharkan tidak bermasalah.
Perilaku paling berbahaya bagi pengesah bukanlah membuang ralat, tetapi mendiamkan diri. Kunci tersilap atau parameter yang direka oleh model lolos pengesahan tanpa bunyi dan meletup dalam logik perniagaan.
Satu: pengesahan yang "lulus"
{
"type": "object",
"properties": {
"order_id": { "type": "string" },
"amount": { "type": "number" }
},
"required": ["order_id", "amount"]
}
Hantar {"order_id": "A1", "amount": 50, "reasn_code": "damaged"} — kunci ketiga tersilap ejaan. Dengan konfigurasi lalai Ajv, hasilnya lulus. Medan tambahan tidak ditolak mahupun ditanda.
Dalam spesifikasi JSON Schema, nilai lalai additionalProperties ialah true: medan yang tidak diisytiharkan dibenarkan.
Dua: tiga bentuk senyap
| Runtime | Tingkah laku lalai | Akibat |
|---|---|---|
| Ajv (JS) | biar lulus | data kotor sampai ke logik |
Zod z.object |
alih keluar | medan hilang, objek menjadi pendek |
| Pydantic v2 | abaikan (extra="ignore") |
sama, tanpa jejak dalam log |
Pembuangan lebih licik daripada kelulusan. Kedua-dua pustaka gagal secara senyap dengan cara yang sama, secara lalai.
Tiga: panggilan alat LLM membesarkan masalah
Argumen dijana oleh model: ia mereka nama medan dan menghantar "3" sebagai nombor. Platform mentakrifkan parameter sebagai JSON Schema tetapi secara lalai tidak memaksa skema ditutup — mod strict perlu diaktifkan secara jelas, dan kekangan tatabahasa hanya meliputi output terus model.
{
"order_id": 4411,
"refund_amount_usd": 50,
"reason_code": "damaged",
"urgent": "yes"
}
Dengan objek tertutup, reason_code dan urgent ditolak dan ralat menunjuk ke laluan /reason_code.
Empat: cara menutup
Ajv: tambah additionalProperties: false pada nod objek.
import Ajv from "ajv";
const ajv = new Ajv({ allErrors: true });
const schema = {
type: "object",
properties: { order_id: { type: "string" }, amount: { type: "number" } },
required: ["order_id", "amount"],
additionalProperties: false,
};
const validate = ajv.compile(schema);
validate({ order_id: "A1", amount: 50, reasn_code: "x" }); // false
Zod: ganti z.object dengan z.strictObject atau rantaikan .strict(). Pydantic: konfigurasikan ConfigDict(extra="forbid").
Peraturan sama: penutupan dilakukan peringkat demi peringkat. Setiap objek bersarang perlu additionalProperties: false sendiri.
Lima: polisi paksaan jenis
Mod lax Pydantic menukar "5" kepada 5. Tiga polisi: ketat (tolak jenis salah), terkawal (hanya penukaran jelas bersempadan), bebas (data dalaman sahaja). Untuk input tidak dipercayai, pilih 1 atau 2 dan tulis dalam ujian.
Enam: senarai semak bersarang
| Titik | Tindakan |
|---|---|
| Objek akar | additionalProperties: false |
| Setiap objek bersarang | sama |
| Elemen tatasusunan | tutup objek dalam items |
| Enum dan julat | tambah enum, minimum/maximum |
| Skema janaan | lengkapkan secara manual |
Tujuh: selepas penolakan
allErrors: true melaporkan semua medan sekali gus; verbose: true memberikan laluan. Masalah sintaks disaring oleh penghurai sebelum pengesahan skema.
Soalan Lazim
Terlalu ketat?
Bergantung pada kontrak. Untuk input sendiri, tutup; untuk data pihak ketiga yang boleh diluaskan, tutup teras sahaja danasingkan kawasan sambungan.
Strip Zod bukannya lebih selamat?
Tidak: ia melindungi hilir dengan mengorbankan pemanggil. Ralat perlu muncul awal dan jelas.
Mod strict platform menggantikan pengesahan setempat?
Tidak. Skema sendiri mungkin terbuka dan tatabahasa mungkin tidak meliputi argumen alat.
Selepas menutup, data lama gagal beramai-ramai?
Itulah yang patut didedahkan. Senaraikan dengan allErrors, tambah medan tidak berbahaya, betulkan yang berbahaya.
Penyelesaian satu baris?
Tiada, tetapi langkah minimum: pastikan setiap type: "object" diikuti additionalProperties: false.