Model

The classes can be used as a model in your application. Ts.ED use this models to convert JSON objects to theirs class equivalents.

The classes models can be used in the following cases:

  • Serialization and deserialisation of data (Converters),
  • Data validation with AJV,
  • Generating documentation with Swagger.

To create a model, Ts.ED provides decorators who will store and generate a standard JsonSchema model.

Example

The example below uses decorators to describe a property of the class and store metadata such as the description of the field.

import {
  Default,
  Enum,
  Format,
  Maximum,
  MaxLength,
  Minimum,
  MinLength,
  Pattern,
  Required
} from "@tsed/common";

enum Categories {
  CAT1 = "cat1",
  CAT2 = "cat2"
}

export class MyModel {
  _id: string;

  @Required()
  unique: string;

  @MinLength(3)
  @MaxLength(50)
  indexed: string;

  @Minimum(0)
  @Maximum(100)
  @Default(0)
  rate: Number = 0;

  @Enum(Categories)
    // or @Enum("type1", "type2")
  category: Categories;

  @Pattern(/[a-z]/)
  pattern: String;

  @Format("date-time")
  @Default(Date.now)
  dateCreation: Date = new Date();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

TIP

The Model will generate a JsonSchema which can be used by module supporting JsonSchema spec

WARNING

The schema generated by Ts.ED list only properties decorated by at least one decorator. In the previous example, the _id won't be displayed in the JsonSchema. It's very important to understand that TypeScript only generates metadata on properties with at least of theses decorators:

    Our model is now described, we can use it inside a as input type parameter for our methods. Ts.ED will use the model to convert the raw data to an instance of your model.

    import {BodyParams, Controller, Post} from "@tsed/common";
    import {MyModel} from "../models/MyModel";
    
    @Controller("/")
    export class PersonsCtrl {
    
      @Post("/")
      save(@BodyParams() model: MyModel): MyModel {
        console.log(model instanceof MyModel); // true
        return model; // will be serialized according to your annotation on MyModel class.
      }
    
      // OR
    
      @Post("/")
      save(@BodyParams("person") model: MyModel): MyModel {
        console.log(model instanceof MyModel); // true
        return model; // will be serialized according to your annotation on Person class.
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20

    Collections

    Declaring property that use a collection is a bit different than declaring a simple property. TypeScript store only the Array/Set/Map type when your declare the type of your property. The type used by the collection is lost.

    To tell Ts.ED (and other third party which use JsonSchema) that a property use a collection with a specific type, you must use decorator as following:

    import {PropertyType} from "@tsed/common";
    import {Role} from "./Role";
    import {Security} from "./Security";
    
    class User {
      @PropertyType(Role)
      roles: Role[];
    
      @PropertyType(String)
      securities: Map<string, Security>;
    
      @PropertyType(String)
      scopes: Set<string>;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

    Use JsonSchema

    In some cases, it may be useful to retrieve the JSON Schema from a Model for use with another library.

    Here is an example of use with the AJV library:

    import {JsonSchemesService, OverrideService, ValidationService} from "@tsed/common";
    import * as Ajv from "ajv";
    import {ErrorObject} from "ajv";
    import {BadRequest} from "ts-httpexceptions";
    
    @OverrideService(ValidationService)
    export class AjvService extends ValidationService {
      constructor(private jsonSchemaService: JsonSchemesService) {
        super();
      }
    
      public validate(obj: any, targetType: any, baseType?: any): void {
        const schema = this.jsonSchemaService.getSchemaDefinition(targetType);
    
        if (schema) {
          const ajv = new Ajv();
          const valid = ajv.validate(schema, obj);
    
          if (!valid) {
            throw(this.buildErrors(ajv.errors!));
          }
        }
      }
    
      private buildErrors(errors: ErrorObject[]) {
    
        const message = errors.map(error => {
          return `{{name}}${error.dataPath} ${error.message} (${error.keyword})`;
        }).join("\n");
    
        return new BadRequest(message);
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33

    Decorators