Skip to content

Generate JSON-Schemas from typescript classes annotated with decorators

License

Notifications You must be signed in to change notification settings

Kage0x3B/ts-decorator-json-schema-generator

Repository files navigation

ts-decorator-json-schema-generator

Generate JSON-Schemas from typescript classes annotated with decorators.

Installation

pnpm add ts-decorator-json-schema-generator reflect-metadata or npm install ts-decorator-json-schema-generator reflect-metadata

As this library uses reflections, the reflect-metadata library is required and has to be imported before anything else. And include these options in your tsconfig.json:

"experimentalDecorators": true,
"emitDecoratorMetadata": true

Usage

import 'reflect-metadata';

import { generateJsonSchema } from 'ts-decorator-json-schema-generator';
import { MySchema } from './MySchema';

console.log(generateJsonSchema(MySchema));
import {
    DependentRequired, JsonSchema, MaxLength, Min, MinLength, Optional, Pattern, Required
} from 'ts-decorator-json-schema-generator';

// This decorator and it's options are optional and
// only a handy shortcut to add some general info to your schema
@JsonSchema({
    id: 'https://example.com/my-schema.schema.json',
    title: 'Example Schema',
    description: 'An example schema for showcasing some features of the ts-decorator-json-schema-generator library'
})
export class MySchema {
    // Primitive types are automatically extracted from the typescript type
    @Required()
    @Min(0)
    public myRequiredNumber!: number;

    @Required()
    @MinLength(4)
    @MaxLength(16)
    @Pattern(/^[a-zA-Z_]+$/)
    public username!: string;

    @Optional()
    public streetAddress?: string;

    @Optional()
    @DependentRequired('streetAddress')
    public extendedAddress?: string;
}

Important: Every property has to have at least one decorator (just add Required or Optional everywhere) or it won't be possible to extract the typescript type and include the property in the schema.

Other features

  • Almost all current json schema validation types are implemented as decorators (currently missing most of the core structure types like "if"/"then" and more)
  • You can set the type to another schema typescript class to include a subschema.
  • Explicitly set the property type with @Type which accepts a type name or another schema class -> @Type("integer") or @Type(OtherSchema).
  • @Enum accepts typescript enums and automatically sets the correct accepted values and property type.

Decorator reference

JSON schema keyword Decorator Description
Common schema decorators
$id, title, description, $schema @JsonSchema({ id?: string; title?: string; description?: string }) Used on a class to mark it as a json schema class. Pass the options object to set metadata on the json schema
$comment
type @Type(typeNameOrSchemaClass: string | ClassConstructor) Explicitly set the type of this property to either a subschema class or a type name (one of string, number, integer, boolean, object, array, null)
enum @Enum(enumClass: Enum, valueType?: 'string' | 'number' | 'integer') Use a TypeScript enum class to set enum values on this property. The decorator tries to guess if your enum contains string or number types to set the type on the schema of the property, but this can be explicitly set with valueType
const The const keyword is used to restrict a value to a single value.
dependentRequired @DependentRequired(...requiredProperties: string[]) List all other property keys, which this property depends on.
dependentSchemas
default @Default(value: any) Set a default value for a property. This might be used by documentation generators.
examples @Examples(examples: any[]) Provide a list of example values for this property. This might be used by documentation generators.
readOnly @ReadOnly() Mark a property as read-only.
writeOnly @WriteOnly() Mark a property as write-only.
deprecated @Deprecated() Mark a property as deprecated.
$ref See subschemas
Composition decorators
allOf @AllOf(...schemaOrClasses: ClassConstructor | JSONSchema7)
anyOf @AnyOf(...schemaOrClasses: ClassConstructor | JSONSchema7)
oneOf @OneOf(...schemaOrClasses: ClassConstructor | JSONSchema7)
not @Not(schemaOrClass: ClassConstructor | JSONSchema7)
String decorators
minLength @MaxLength(maxLength: number) Set the max length of this string.
maxLength @MinLength(minLength: number) Set the min length of this string.
pattern @Pattern(pattern: RegExp | string) Require the string to match the given RegExp pattern.
format @Format(format: string) Json schemas have a list of inbuilt string formats for strings containing dates, email addresses and more.
contentEncoding @ContentEncoding(contentEncoding: string) Specify the encoding of the content of this string. Examples include base16, base32, base32hex base64.
contentMediaType @ContentMediaType(mimeType: string) Specify the mimetype of the content of this string.
contentSchema @ContentSchema(schemaClass: ClassConstructor) Specify the json schema, which the content of this string should adhere to.
Number decorators
minimum @Min(min: number) Set the min value of the number.
maximum @Max(max: number) Set the max value of the number.
minimum and maximum @Range(min: number, max: number) Shortcut for setting both @Min and @Max.
exclusiveMin @ExclusiveMin(exclusiveMin: number) Set the exclusive min value of the number.
exclusiveMax @ExclusiveMax(exclusiveMax: number) Set the exclusive max value of the number.
multipleOf @MultipleOf(value: number) Require to the number to be a multiple of value.
Object decorators
required (on the parent object) @Required() Mark this property as required
(doesn't set anything) @Optional() Mark this property as optional (no used in json schema, decorator exists for parity with @Required() decorator)
minProperties @MinProperties(minAmount: number) Require a min amount of properties on this object
maxProperties @MaxProperties(maxAmount: number) Restrict the max amount of properties on this object
additionalProperties
patternProperties
propertyNames
Array decorators
items @Items(type: string | ClassConstructor) Specify the type for each array item by passing a json schema type or a class
contains @Items(type: string | ClassConstructor) Specify the type for each array item by passing a json schema type or a class
minItems @MinItems(minAmount: number) Require a min amount of items in this array
maxItems @MaxItems(maxAmount: number) Restrict the max amount of items in this array
uniqueItems @UniqueItems() Require each array item to be unique
Conditional decorators
if/then/else

Subschemas

When your schema classes have properties, which are also schema classes, there are different ways to place the subschemas of these classes into the final json schema.

The generateJsonSchema(sourceClass: ClassConstructor, options?: SchemaGeneratorOptions) method accepts an options object, where you can set includeSubschemas to the following values:

Value Description
full Basically "copy-pastes" the full class json-schema into the property type
anonymously Like full, but removes the $id field to resolve problems with having json-schemas with the same $id defined multiple times in a file
reference Inserts a $ref to the json-schema $id, which then has to be resolved by the system loading the json-schemas.
($id: string | undefined) => SubschemaIncludeType Decide for each subschema, how to insert it.

Comparison to similar libraries

Similar libraries are ts-json-schema-generator, which uses JSDoc comments for information on how to build the json schema instead of decorators and requires the source .ts files to be present. There is also ts-json-schema-decorator, which uses decorators and inspired this library, but I decided to write a completely new library instead of forking this project, as the code looked very hard to maintain. Furthermore, it used an unusual approach when it comes to generating the json schema, as the decorators "magically" generated the schema when a class with the correct decorator was loaded, and appended the generated schema to the class prototype.