-
Notifications
You must be signed in to change notification settings - Fork 35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to get jsonschema for only one class ? #64
Comments
How about just picking out the classes you're interested in from |
@epiphone it's what I did actually.. |
Just in case you're still wondering about this, I managed to get it to work by making a new file that will hold my schema and doing something like this:
Creates a new class that extends my initial class but omits the _id property, you can also pass an empty array and I believe it still works. This provides basically the same class to the validationMetadatasToSchemas and allows me to get a result. |
@ThatOneAwkwardGuy I am not talking about heritence at all here but about being able to only generate schema for some given classes. You are off topic. But thanks to tried. |
I have the same problem, did you find any solutions by chance? @scorsi |
@DanoRysJan look at the end of my first message, I give a solution, what I'm actually doing. Far from being a great fix of course.
|
@scorsi Thank you. You helped me create this generic class.
The only problem I currently have is that the objects with the Nested decorator do not complete, they come out as Object. Documentation suggests requiring this.
But it's not working. |
Well, I already realized that it does work. Actually the only problem I have is when showing it in the documentation. These leave me with null error. Example:
|
Just stumbled across this issue, my case is that my schema names across project are not by any means unique, and there is few completely separate domains. Btw. sorry for spam / long samples. My solution is to recursivelly inline schema objects instead of using refs with custom import { Contructor } from 'type-fest'
// @ts-ignore
import { defaultMetadataStorage } from 'class-transformer/cjs/storage.js'
import { getMetadataStorage, ValidationTypes } from 'class-validator'
import { targetConstructorToSchema } from 'class-validator-jsonschema'
import { ISchemaConverters } from 'class-validator-jsonschema/build/defaultConverters'
import { IOptions } from 'class-validator-jsonschema/build/options'
import { ValidationMetadata } from 'class-validator/types/metadata/ValidationMetadata'
export const classToJsonSchema = (clz: Constructor<any>) => {
return targetConstructorToSchema(clz, options)
}
const additionalConverters: ISchemaConverters = {
[ValidationTypes.NESTED_VALIDATION]: plainNestedConverter,
}
const options: Partial<IOptions> = {
classTransformerMetadataStorage: defaultMetadataStorage,
classValidatorMetadataStorage: getMetadataStorage(),
additionalConverters,
}
/**
* Explicitly inline nested schemas instead of using refs
*
* @see https://github.com/epiphone/class-validator-jsonschema/blob/766c02dd0de188ebeb697f3296982997249bffc9/src/defaultConverters.ts#L25
*/
function plainNestedConverter(meta: ValidationMetadata, options: IOptions) {
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 targetToSchema(childType, options)
}
}
function getPropType(target: object, property: string) {
return Reflect.getMetadata('design:type', target, property)
}
function targetToSchema(type: any, options: IOptions): any | void {
if (typeof type === 'function') {
if (type.prototype === String.prototype || type.prototype === Symbol.prototype) {
return { type: 'string' }
} else if (type.prototype === Number.prototype) {
return { type: 'number' }
} else if (type.prototype === Boolean.prototype) {
return { type: 'boolean' }
}
return classToJsonSchema(type)
}
} So class class NestedOptions {
@IsInt()
@IsPositive()
@Type(() => Number)
int!: number
@IsBoolean()
@IsOptional()
@Type(() => Boolean)
bool?: boolean = false
}
class Options {
@IsString()
@Type(() => String)
str!: string
@IsArray()
@IsString({ each: true })
@Type(() => String)
arr!: string[]
@IsType(() => NestedOptions)
nested!: NestedOptions
} Produces huge but valid schema {
"properties": {
"str": {
"type": "string"
},
"arr": {
"items": {
"type": "string"
},
"type": "array"
},
"nested": {
"properties": {
"int": {
"exclusiveMinimum": true,
"minimum": 0,
"type": "integer"
},
"bool": {
"type": "boolean"
}
},
"type": "object",
"required": [
"int"
]
}
},
"type": "object",
"required": [
"str",
"arr",
"nested"
]
} // EDIT - solution with definitions object import { Constructor } from 'type-fest'
// @ts-ignore
import { defaultMetadataStorage } from 'class-transformer/cjs/storage.js'
import { getMetadataStorage, IS_NEGATIVE, IS_POSITIVE, ValidationTypes } from 'class-validator'
import { targetConstructorToSchema } from 'class-validator-jsonschema'
import { ISchemaConverters } from 'class-validator-jsonschema/build/defaultConverters'
import { IOptions } from 'class-validator-jsonschema/build/options'
import { ValidationMetadata } from 'class-validator/types/metadata/ValidationMetadata'
import { JSONSchema } from '../types/index.js'
export { JSONSchema as IsSchema } from 'class-validator-jsonschema'
/**
* Build json-schema from `class-validator` & `class-tranformer` metadata.
*
* @see https://github.com/epiphone/class-validator-jsonschema
*/
export function classToJsonSchema(clz: Constructor<any>): JSONSchema {
const options = { ...defaultOptions, definitions: {} }
const schema = targetConstructorToSchema(clz, options) as any
schema.definitions = options.definitions
return schema
}
function nestedClassToJsonSchema(clz: Constructor<any>, options: Partial<Options>): JSONSchema {
return targetConstructorToSchema(clz, options) as any
}
const additionalConverters: ISchemaConverters = {
/**
* Explicitly inline nested schemas instead of using refs
*
* @see https://github.com/epiphone/class-validator-jsonschema/blob/766c02dd0de188ebeb697f3296982997249bffc9/src/defaultConverters.ts#L25
*/
[ValidationTypes.NESTED_VALIDATION]: (meta: ValidationMetadata, options: 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)
const schema = targetToSchema(childType, options)
if (schema.$ref && !options.definitions[childType.name]) {
options.definitions[childType.name] = nestedClassToJsonSchema(childType, options)
}
return schema
}
},
}
type Options = IOptions & {
definitions: Record<string, JSONSchema>
}
const defaultOptions: Partial<Options> = {
classTransformerMetadataStorage: defaultMetadataStorage,
classValidatorMetadataStorage: getMetadataStorage(),
additionalConverters,
}
function getPropType(target: object, property: string) {
return Reflect.getMetadata('design:type', target, property)
}
function targetToSchema(type: any, options: IOptions): any | void {
if (typeof type === 'function') {
if (type.prototype === String.prototype || type.prototype === Symbol.prototype) {
return { type: 'string' }
} else if (type.prototype === Number.prototype) {
return { type: 'number' }
} else if (type.prototype === Boolean.prototype) {
return { type: 'boolean' }
}
return { $ref: options.refPointerPrefix + type.name }
}
} |
This works for me:
|
Hello,
In your exemple you give:
Unfortunatly I have too much classes using class-validator and I only want some. Is there a way to only get for given ones ?
Something like this:
Tried to create my own
MetadataStorage
with only the classes I want to be in but I don't find any exemples on how to achieve that. Did you have ?Actually I do:
Thanks,
The text was updated successfully, but these errors were encountered: