Don't use refs for nested objects
Hi!
I have several database models defined using class-validator and I'd like to add validation inside the database itself by converting the existing models to JSONSchema. Some converters need to be changed (bsonType), but that's manageable by changing some converters.
One thing that I haven't figured out how to do is to store nested documents in this way. The default behavior of class-validator-jsonschema is to create a ref, but MongoDB doesn't support this.
Instead of creating refs I just need all the schemas to be nested. As far as I know there's currently no way to do this, but it feels like something that could be part of the config. Are there any plans for anything like this?
A workaround, you can do this with a custom converter:
const options: Partial<IOptions> = {
additionalConverters: {
[cv.ValidationTypes.NESTED_VALIDATION]: (meta, options) => {
if (typeof meta.target === `function`) {
const typeMeta = options.classTransformerMetadataStorage
? options.classTransformerMetadataStorage.findTypeMetadata(
meta.target,
meta.propertyName,
)
: null;
const childType = typeMeta
? typeMeta.typeFunction()
: getPropType(meta.target.prototype, meta.propertyName);
return targetConstructorToSchema(childType, options);
}
},
},
};
Noting that depending on your setup, you'll probably need to tweek your class decorators and options: https://github.com/epiphone/class-validator-jsonschema#validatenested-and-arrays.
I see, basically recursively populating nested fields by just running the conveter again for that sub type. Thank you!
I had boot issues with const childType part of the barock's snippet, but the edited one below works pretty decent for my use case of nesting a simple object:
classTransformerMetadataStorage: defaultMetadataStorage,
additionalConverters: {
[ValidationTypes.NESTED_VALIDATION]: (meta, options) => {
if (typeof meta.target === "function") {
const typeMeta = options.classTransformerMetadataStorage
? options.classTransformerMetadataStorage.findTypeMetadata(
meta.target,
meta.propertyName,
)
: null;
if (typeMeta) {
const childType = typeMeta.typeFunction()
return targetConstructorToSchema(childType, options)
}
}
return {}
}
}