class-validator-jsonschema
Converts class-validator decorator metadata into OpenAPI-compatible JSON Schema, with a converter table and a JSONSchema decorator for manual overrides.
Repository Health
Technical Analysis
class-validator-jsonschema takes the decorator metadata produced by class-validator (@IsString, @MaxLength, @IsEnum, and the rest) and converts it into OpenAPI-compatible JSON Schema definitions, so a project’s runtime validation classes can double as the source of truth for its API schema documentation. Rather than requiring a second, hand-maintained schema definition, it walks class-validator’s internal MetadataStorage and groups each class’s property metadata into a schema object, resolving inherited properties and nested @ValidateNested classes along the way.
Because the mapping from validator to JSON Schema keyword is inherently opinionated in places, the library exposes two escape hatches rather than forcing a single fixed conversion: an additionalConverters option that can add or override individual validator-to-schema mappings, and a @JSONSchema decorator that merges (or, in function form, fully rewrites) arbitrary schema keywords onto a class or property. It also integrates with class-transformer’s @Type and @Expose/@Exclude decorators so array/generic property types and renamed or hidden fields resolve correctly instead of falling back to Object.
What You Get
- A
validationMetadatasToSchemas()function that reads class-validator’s global metadata storage and returns a map of class-name to JSON SchemaSchemaObject - A data-driven converter table covering the full set of class-validator decorators (string/number/date formats, length/range constraints, enums, custom validators, nested objects, arrays), overridable per-validator-type via
additionalConverters - A
@JSONSchemadecorator for merging (or fully replacing, via a function form) arbitrary schema keywords onto a class or property — descriptions, examples,deprecated, customformats - Optional integration with class-transformer’s metadata storage so
@Type()-annotated nested arrays/generics and@Expose/@Exclude-decorated properties resolve to the correct schema shape - Automatic resolution of inherited validation decorators across class hierarchies, with child-class metadata taking precedence over parent metadata
Common Use Cases
- Generating OpenAPI/Swagger component schemas from existing class-validator DTOs in an Express, NestJS, or routing-controllers API without hand-writing a parallel schema
- Keeping request-body validation and published API documentation in sync by deriving both from the same decorated class
- Adding descriptions, examples, and custom formats to generated schemas via the
@JSONSchemadecorator for richer Swagger UI output - Documenting nested and array DTOs (
@ValidateNested({ each: true })collections) where the referenced schema needs to appear as a proper$refrather than resolving toArrayorObject
Under The Hood
Architecture
The library is a single-purpose functional transform split across four small modules with no internal layering beyond that: src/index.ts orchestrates the conversion — it pulls ValidationMetadata[] out of class-validator’s MetadataStorage, groups entries by class name with lodash.groupby, resolves inherited metadata by walking the prototype chain (getInheritedMetadatas), converts each property’s metadata array through the converter table (applyConverters), and finally layers in any @JSONSchema decorator content (applyDecorators); src/defaultConverters.ts holds a data-driven converter map keyed by class-validator’s ValidationTypes constants; src/decorators.ts stores @JSONSchema payloads via reflect-metadata’s Reflect.defineMetadata/getMetadata keyed on a private Symbol; src/options.ts centralizes the config object and defaults. State flows through explicit function arguments and an immutable options object rather than any container or shared mutable state, but the converters pattern-match directly on class-validator’s internal ValidationMetadata shape (imported via a submodule path, class-validator/types/metadata/ValidationMetadata), so an internal shape change in class-validator would ripple through every converter function at once.
Tech Stack
Written in TypeScript (ES6 target, CommonJS modules, decorator and metadata emit enabled) and built with tsc against a dedicated release tsconfig. Runtime dependencies are deliberately minimal: lodash.groupby and lodash.merge for grouping and merging schema fragments, openapi3-ts for SchemaObject/ReferenceObject typings, reflect-metadata for decorator metadata storage, and tslib for helper injection. class-validator and class-transformer are peer dependencies rather than bundled runtime deps, since the library operates on metadata those packages already produce. Tests run under Jest with ts-jest; formatting is enforced with Prettier (single quotes, no semicolons) and linting with tslint (not yet migrated to ESLint); CI runs on GitHub Actions against Node 22, executing build, format check, lint, and test in sequence.
Code Quality
Ten Jest test files (roughly 1,300 lines) exercise the library against class-validator’s real MetadataStorage rather than mocks, covering decorators, the full default-converter table, inherited properties across class hierarchies, class-transformer integration, @Expose/@Exclude handling, custom validation constraints, and global options. tsconfig.json enables strictNullChecks, noImplicitAny, and noUnused* checks, though not the full strict flag. Error handling is intentionally permissive rather than defensive: converters return undefined for unrecognized metadata shapes instead of throwing, consistent with the README’s stated best-effort design goal rather than being an oversight. Naming is consistent and single-responsibility throughout; there is no code-coverage reporting configured in CI.
What Makes It Unique
Its differentiator is a dual extensibility model rather than a single fixed mapping: a data-driven converter table keyed by class-validator’s own validator-type constants, selectively overridable per-type via additionalConverters, paired with a separate @JSONSchema decorator (with a function form for full manual control) that composes on top of the generated schema via a deep merge instead of replacing it outright. It also resolves @ValidateNested children through class-transformer’s @Type() metadata specifically to work around TypeScript’s inability to reflect generic array/collection element types at runtime — a narrow, well-documented interoperability fix rather than a generic pattern, but one that solves a real recurring gap between the two libraries.