DTO --- DTO (Data Transfer Object) Validation picks up where [Rules](/rule/README.md) left off. Data can get complicated with multiple rules for each property. Writing rules for this is exhaustive, so DTOs and the `Validate` decorator provide an alternative. Additionally, `ScrubIn` and `ScrubOut` decorators conveniently eliminate properties coming in and properties going out. [Property Validation](#validation) [Data Scrubbing](#scrubbing) ## Property Validation Currently there is no formal definition of a "DTO", but a collection of validation metadata on class properties. The `Validate` decorator takes a validation object with rules for validation. Keep in mind that **property validation only applies to data coming in**. ```typescript export class User { @Validate({ ... validation rules }) public someProperty: string; } ``` The following rules can be used in the validation object. **Options** | Rule | Description | Possible Values | Example | |-----------|-------------------------------------------------------------------------------------------------|---------------------------------------|----------------------------| | required | Set to true if this property is required on this DTO. Fails if the property is undefined. | true, false | true | | type | Ensures the value received is of this type. Fails the value is not the given type. | 'string', 'number', 'object', 'array' | 'string' | | minLength | Ensures the string value length is at least this. | 0 to Infinity | 10 | | maxLength | Ensures the string value length is not greater than this. | 0 to Infinity | 20 | | min | Ensures the numerical value is at least this. | -Infinity to Infinity | 10 | | max | Ensures the numerical value is not greater than this. | -Infinity to Infinity | 20 | | pattern | Validates if the string value given satisfies this pattern through the RegExp.test(str) method. | RegExp | /^[\w\d]+$/ (alphanumeric) | | values | Ensures the string value given is one of these values. | CSV | 'red,blue,green' | **Error Reporting** When a validation rule is not met, a default message will be returned with a `400` error code. If you are going to display this message then you might want to define your own error messages. For example: Instead of showing the client "username did not satisfy the pattern /^[\w\d]+$/", you may instead want the error to read "Please use alphanumerica characters for your Username". To do that, the value of the validation rule becomes a tuple, where the first item in the array is the rule, and the second is the failing message. ```typescript import {Validate} from 'expresskit'; export class User { // With custom message @Validate({ required: [true, 'Please enter a Username'], pattern: [/^[\w\d]+$/, 'Please use alphanumerica characters for your Username'] }) public username: string; // Without custom message @Validate({ required: true, pattern: /^[\w\d-_]+@[\w\d-_]+\.[\w\d]+$/ }) public email: string; } ``` **Body** Validation is applied to the Body of a request. When using the `Body` decorator, pass the DTO to validate against as the first parameter. ```typescript export class UserRouter { @Route('POST', '/user') public static createUser(@Body(User) user: User) {} } ``` When a DTO is provided to the Body decorator, it is validated against the validation rules of that DTO. Additionally, when a DTO is used, the __request is required to have a body__. If a body is not present, a `400` error will be sent. ## Data Scrubbing You may want to scrub data coming in and going out. When data is scrubbed in, use the `ScrubIn` decorator. When going out, use the `ScrubOut` decorator. Use `ScrubIn` for **Read-Only** properties. ```typescript import {ScrubIn} from 'expresskit'; public class User { public id: string; public username: string; @ScrubIn() public created: string; @ScrubIn() public updated: string; } ``` Use `ScrubOut` for sensitive data. In addition to using ScrubOut, you will need to use the `ResponseType` decorator on your route. Without ResponseType, the route can't determine you are responding with a DTO. ```typescript import {ScrubOut, ResponseType} from 'expresskit'; public class User { public id: string; public username: string; @ScrubOut() public password: string; } export class UserRouter { @Route('GET', '/user/:id') @ResponseType(User) public static getUser(@Param('id') userId: string): User {} } ``` ## Keep Reading [Routing](/route/README.md) [Response](/response/README.md) [Middleware](/middleware/README.md) [Resource Resolutions](/resource/README.md) [Rules](/rule/README.md) [DTOs](/dto/README.md) ## More Links [Expresskit Seed Project](https://github.com/iamchairs/expresskit-seed) [Github](https://github.com/iamchairs/restkit) [Issues](https://github.com/iamchairs/restkit/issues) [NPM](https://www.npmjs.com/package/restkit) [Twitter](https://twitter.com/micahwllmsn)