javascript - ajv - Zajistěte, aby struktura daného objektu odpovídala struktuře vlastního typu
Používám ajv s TypeScriptem a mám vlastní typ MyCustomType. Při vytváření validačního schématu chci zajistit, aby konkrétní vlastnost byla typu MyCustomType. Ajv by tedy měl ověřit jeho strukturu a rozhodnout, zda by to mohlo být parsováno na daný typ.
Začal jsem s následujícím ukázkovým kódem (a vytvořil jsem pro testovací účely příklad v Codesandboxu)
import { AType } from "./AType"; // custom type
import { AnInterface } from "./AnInterface"; // custom interface
import Ajv from "ajv";
type MyComplexType = AType | AnInterface; // create a more complex type from the given imports
const ajvInstance = new Ajv();
const schema = {
type: "object",
properties: {
myComplexType: { type: "string" } // value structure must match structure of MyComplexType
},
required: ["myComplexType"],
additionalProperties: false
};
const validate = ajvInstance.compile(schema);
const data = {
myComplexType: {}
};
const isValid = validate(data);
if (isValid) {
console.info("everything is fine");
} else {
validate.errors?.forEach((error) => console.error(error.message));
}
V současné době nevím, jak vytvořit validační schéma pro vlastnost myComplexType. Našel jsem několik diskusí
- Přidejte vlastnost instanceof pro objekty typu
- Vytváření vlastního typu
- Zadejte klíčová slova
ale nemyslím si, že by to pomohlo, protože
typeofprostě vrací"object"instanceofnebude fungovat pro typy
Takže musím vytvořit vlastní klíčové slovo (jak je popsáno zde) a napsat si vlastní validační logiku (prozkoumat strukturu objektu) nebo existují nějaké věci, které mohu už použít? Jak bych měl nakonfigurovat myComplexType?
Odpověď č. 1
Zploštil jsem vaši strukturu, abych mohl odpovědět jedním segmentem kódu. Toto je TypeScript a úspěšně běží na NODE JS s použitím Ajv.
Klíčem je použití JSONSchemaType z Ajv pro propojení mezi Ajv a TypeScriptem. Pokud se definice TYPE a AJV neshodují, TypeScript si stěžuje. To je skvělé, zejména pokud má váš editor zabudovaný real-time kontrolor TypeScriptu (VS Code, VIM, ...).
Všimněte si, že schéma MyComplexTypeSchema je definováno pomocí dříve definovaných schémat. Nemusí to být jedno obrovské vnořené schéma. Mějte schéma pro každý TYPE a INTERFACE a budujte svou knihovnu od základů tak, aby podporovala jak TypeScript, tak Ajv.
'use strict'
import Ajv, {JSONSchemaType} from "ajv"
const ajvInstance = new Ajv();
type AType = "x" | "y";
const ATypeSchema : JSONSchemaType<AType> = {
type:"string",
enum:["x","y"]
}
interface AnInterface {
prop: string;
}
const AnInterfaceSchema : JSONSchemaType<AnInterface> = {
type:"object",
properties:{
prop:{type:"string"}
},
required:["prop"]
}
type MyComplexType = AType | AnInterface;
const MyComplexTypeSchema : JSONSchemaType<MyComplexType> = {
oneOf:[ ATypeSchema,AnInterfaceSchema ]
}
const schema = {
type: "object",
properties: {
myComplexType: MyComplexTypeSchema
},
required: ["myComplexType"],
additionalProperties: false
};
const validate = ajvInstance.compile(schema);
const data1 = {
myComplexType: {
prop:"a string"
}
};
var isValid = validate(data1);
if (isValid) {
console.info("everything is fine in data1");
} else {
validate.errors?.forEach((error) => console.error(error.message));
}
const data2 = {
myComplexType: "x"
};
var isValid = validate(data2);
if (isValid) {
console.info("everything is fine in data2");
} else {
validate.errors?.forEach((error) => console.error(error.message));
}
const bad1 = {
myComplexType: {}
};
var isValid = validate(bad1);
if (isValid) {
console.info("everything is fine in bad1");
} else {
validate.errors?.forEach((error) => console.error("bad1: "+error.message));
}
const bad2 = {
myComplexType: "z"
};
var isValid = validate(bad2);
if (isValid) {
console.info("everything is fine in bad2");
} else {
validate.errors?.forEach((error) => console.error("bad2: "+error.message));
}
Nechal jsem váš kód "const schema"" beze změny, ale pravděpodobně by měl být něco podobného níže, aby to bylo konzistentní s ostatní strukturou Type/Schema.
type TopType = {
myComplexType : MyComplexType
}
const TopTypeSchema : JSONSchemaType<TopType> = {
type: "object",
properties: {
myComplexType: MyComplexTypeSchema
},
required: ["myComplexType"],
additionalProperties: false
};
const validate2 = ajvInstance.compile(TopTypeSchema);
// TypeScript will not let us build a BAD value if the type is defined
const data1:TopType = {
myComplexType: {
prop:"a string"
}
};
Odpověď č. 2
Nemyslím si, že s touto knihovnou můžete vytvořit vlastní typ, možná si pletete javascriptové typy s typescriptovými typy. Takže pravděpodobně máte 2 možnosti: 1) místo používání typů použijete třídy a pro ověření instance vaší třídy použijete instanceof, např.
class MyClass {}
const instanceofDef = require("ajv-keywords/dist/definitions/instanceof")
instanceofDef.CONSTRUCTORS.MyClass = MyClass
ajv.validate({instanceof: "MyClass"}, new MyClass())
nebo 2) vytvoříte vnořený schéma takto
const schema = {
type: "object",
properties: {
myComplexType: {
type: "object",
properties: {
myProperty: { type: "string" },
myFunction: { type: "function" },
...
}
}
},
required: ["myComplexType"],
additionalProperties: false
};
const validate = ajvInstance.compile(schema);
const data = {
myComplexType: {
myProperty: "Hello World",
myFunction: function(){}
}
};
const isValid = validate(data);
