data-transfer-object
Advanced tools
Comparing version 0.3.0 to 0.4.0
import { ValidationError, ValidatorOptions } from 'class-validator'; | ||
export * from 'class-validator'; | ||
declare type NonFunctionPropertyNames<T> = { | ||
@@ -33,13 +32,29 @@ [K in keyof T]: T[K] extends Function ? never : K; | ||
* Runs all synchronous validators on this object. | ||
* To run asynchronous validators as well, use `.validateAsync()`. | ||
* To run asynchronous validators as well, use `.getValidationErrorsAsync()`. | ||
* @param opts Options to pass to the validator system. | ||
*/ | ||
validate(opts?: ValidatorOptions): ValidationError[]; | ||
getValidationErrors(opts?: ValidatorOptions): ValidationError[]; | ||
/** | ||
* Runs all synchronous and asynchronous validators on this object. | ||
* Always returns a promise. To validate synchronously, use `.validate()`. | ||
* Always returns a promise. To validate synchronously, use `.getValidationErrors()`. | ||
* @param opts Options to pass to the validator system. | ||
*/ | ||
validateAsync(opts?: ValidatorOptions): Promise<ValidationError[]>; | ||
getValidationErrorsAsync(opts?: ValidatorOptions): Promise<ValidationError[]>; | ||
/** | ||
* Validates this object (sync validators only), and returns its plain data if validations pass. | ||
* Otherwise, throws an error or runs the appropriate handler set with `setValidationErrorHandler()`. | ||
* | ||
* To run both sync and async validators, use `.validateAsync()`. | ||
* @param opts Options to pass to the validator system. | ||
*/ | ||
validate(opts?: ValidatorOptions): Data<this>; | ||
/** | ||
* Validates this object asynchronously, and resolves to its plain data if validations pass. | ||
* Otherwise, rejects with an error or runs the appropriate handler set with `setValidationErrorHandler()`. | ||
* | ||
* To validate synchronously, use `.validate()`. | ||
* @param opts Options to pass to the validator system. | ||
*/ | ||
validateAsync(opts?: ValidatorOptions): Promise<Data<this>>; | ||
/** | ||
* Returns a JSON friendly object containing only data properties of this object (ie, no validation functions). | ||
@@ -50,1 +65,2 @@ * Automatically used by `JSON.stringify()`. | ||
} | ||
export {}; |
"use strict"; | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); | ||
}) : (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
o[k2] = m[k]; | ||
})); | ||
var __exportStar = (this && this.__exportStar) || function(m, exports) { | ||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); | ||
}; | ||
var _a, _b; | ||
@@ -16,5 +6,9 @@ Object.defineProperty(exports, "__esModule", { value: true }); | ||
const class_validator_1 = require("class-validator"); | ||
__exportStar(require("class-validator"), exports); | ||
const validation_exception_1 = require("./validation-exception"); | ||
const validation_error_handler_1 = require("./validation-error-handler"); | ||
// Strict options by default | ||
const defaultOpts = { | ||
whitelist: true, | ||
forbidNonWhitelisted: true, | ||
forbidUnknownValues: true, | ||
}; | ||
@@ -29,2 +23,14 @@ // Must use symbols for private properties so that they are not included in validation | ||
/** | ||
* Checks the input error list, and if non-empty, throws an error. | ||
* @param errors The error list to check against. | ||
*/ | ||
function assertEmptyErrorList(errors) { | ||
if (errors.length) { | ||
if (!validation_error_handler_1.onValidationError) | ||
throw new validation_exception_1.ValidationException(errors); | ||
validation_error_handler_1.onValidationError(errors); | ||
throw new validation_exception_1.ValidationException(errors); | ||
} | ||
} | ||
/** | ||
* Creates a new data transfer object which will validate and reshape its input | ||
@@ -48,6 +54,6 @@ * data based on the validators of its own properties. Must be extended, should | ||
* Runs all synchronous validators on this object. | ||
* To run asynchronous validators as well, use `.validateAsync()`. | ||
* To run asynchronous validators as well, use `.getValidationErrorsAsync()`. | ||
* @param opts Options to pass to the validator system. | ||
*/ | ||
validate(opts) { | ||
getValidationErrors(opts) { | ||
if (this[validated]) | ||
@@ -61,6 +67,6 @@ return this[validationErrors]; | ||
* Runs all synchronous and asynchronous validators on this object. | ||
* Always returns a promise. To validate synchronously, use `.validate()`. | ||
* Always returns a promise. To validate synchronously, use `.getValidationErrors()`. | ||
* @param opts Options to pass to the validator system. | ||
*/ | ||
async validateAsync(opts) { | ||
async getValidationErrorsAsync(opts) { | ||
if (this[validated]) | ||
@@ -81,2 +87,26 @@ return this[validationErrors]; | ||
/** | ||
* Validates this object (sync validators only), and returns its plain data if validations pass. | ||
* Otherwise, throws an error or runs the appropriate handler set with `setValidationErrorHandler()`. | ||
* | ||
* To run both sync and async validators, use `.validateAsync()`. | ||
* @param opts Options to pass to the validator system. | ||
*/ | ||
validate(opts) { | ||
const errors = this.getValidationErrors(opts); | ||
assertEmptyErrorList(errors); | ||
return this.toJSON(); | ||
} | ||
/** | ||
* Validates this object asynchronously, and resolves to its plain data if validations pass. | ||
* Otherwise, rejects with an error or runs the appropriate handler set with `setValidationErrorHandler()`. | ||
* | ||
* To validate synchronously, use `.validate()`. | ||
* @param opts Options to pass to the validator system. | ||
*/ | ||
async validateAsync(opts) { | ||
const errors = await this.getValidationErrorsAsync(opts); | ||
assertEmptyErrorList(errors); | ||
return this.toJSON(); | ||
} | ||
/** | ||
* Returns a JSON friendly object containing only data properties of this object (ie, no validation functions). | ||
@@ -83,0 +113,0 @@ * Automatically used by `JSON.stringify()`. |
export * from './data-transfer-object'; | ||
export * from './validation-error-handler'; | ||
export * from './validation-error-map'; | ||
export * from './validation-exception'; | ||
export * from 'class-validator'; |
@@ -14,1 +14,5 @@ "use strict"; | ||
__exportStar(require("./data-transfer-object"), exports); | ||
__exportStar(require("./validation-error-handler"), exports); | ||
__exportStar(require("./validation-error-map"), exports); | ||
__exportStar(require("./validation-exception"), exports); | ||
__exportStar(require("class-validator"), exports); |
import { ValidationError, ValidatorOptions } from 'class-validator'; | ||
export * from 'class-validator'; | ||
declare type NonFunctionPropertyNames<T> = { | ||
@@ -33,13 +32,29 @@ [K in keyof T]: T[K] extends Function ? never : K; | ||
* Runs all synchronous validators on this object. | ||
* To run asynchronous validators as well, use `.validateAsync()`. | ||
* To run asynchronous validators as well, use `.getValidationErrorsAsync()`. | ||
* @param opts Options to pass to the validator system. | ||
*/ | ||
validate(opts?: ValidatorOptions): ValidationError[]; | ||
getValidationErrors(opts?: ValidatorOptions): ValidationError[]; | ||
/** | ||
* Runs all synchronous and asynchronous validators on this object. | ||
* Always returns a promise. To validate synchronously, use `.validate()`. | ||
* Always returns a promise. To validate synchronously, use `.getValidationErrors()`. | ||
* @param opts Options to pass to the validator system. | ||
*/ | ||
validateAsync(opts?: ValidatorOptions): Promise<ValidationError[]>; | ||
getValidationErrorsAsync(opts?: ValidatorOptions): Promise<ValidationError[]>; | ||
/** | ||
* Validates this object (sync validators only), and returns its plain data if validations pass. | ||
* Otherwise, throws an error or runs the appropriate handler set with `setValidationErrorHandler()`. | ||
* | ||
* To run both sync and async validators, use `.validateAsync()`. | ||
* @param opts Options to pass to the validator system. | ||
*/ | ||
validate(opts?: ValidatorOptions): Data<this>; | ||
/** | ||
* Validates this object asynchronously, and resolves to its plain data if validations pass. | ||
* Otherwise, rejects with an error or runs the appropriate handler set with `setValidationErrorHandler()`. | ||
* | ||
* To validate synchronously, use `.validate()`. | ||
* @param opts Options to pass to the validator system. | ||
*/ | ||
validateAsync(opts?: ValidatorOptions): Promise<Data<this>>; | ||
/** | ||
* Returns a JSON friendly object containing only data properties of this object (ie, no validation functions). | ||
@@ -50,1 +65,2 @@ * Automatically used by `JSON.stringify()`. | ||
} | ||
export {}; |
var _a, _b; | ||
import { validate, validateSync } from 'class-validator'; | ||
export * from 'class-validator'; | ||
import { ValidationException } from './validation-exception'; | ||
import { onValidationError } from './validation-error-handler'; | ||
// Strict options by default | ||
const defaultOpts = { | ||
whitelist: true, | ||
forbidNonWhitelisted: true, | ||
forbidUnknownValues: true, | ||
}; | ||
@@ -15,2 +19,14 @@ // Must use symbols for private properties so that they are not included in validation | ||
/** | ||
* Checks the input error list, and if non-empty, throws an error. | ||
* @param errors The error list to check against. | ||
*/ | ||
function assertEmptyErrorList(errors) { | ||
if (errors.length) { | ||
if (!onValidationError) | ||
throw new ValidationException(errors); | ||
onValidationError(errors); | ||
throw new ValidationException(errors); | ||
} | ||
} | ||
/** | ||
* Creates a new data transfer object which will validate and reshape its input | ||
@@ -34,6 +50,6 @@ * data based on the validators of its own properties. Must be extended, should | ||
* Runs all synchronous validators on this object. | ||
* To run asynchronous validators as well, use `.validateAsync()`. | ||
* To run asynchronous validators as well, use `.getValidationErrorsAsync()`. | ||
* @param opts Options to pass to the validator system. | ||
*/ | ||
validate(opts) { | ||
getValidationErrors(opts) { | ||
if (this[validated]) | ||
@@ -47,6 +63,6 @@ return this[validationErrors]; | ||
* Runs all synchronous and asynchronous validators on this object. | ||
* Always returns a promise. To validate synchronously, use `.validate()`. | ||
* Always returns a promise. To validate synchronously, use `.getValidationErrors()`. | ||
* @param opts Options to pass to the validator system. | ||
*/ | ||
async validateAsync(opts) { | ||
async getValidationErrorsAsync(opts) { | ||
if (this[validated]) | ||
@@ -67,2 +83,26 @@ return this[validationErrors]; | ||
/** | ||
* Validates this object (sync validators only), and returns its plain data if validations pass. | ||
* Otherwise, throws an error or runs the appropriate handler set with `setValidationErrorHandler()`. | ||
* | ||
* To run both sync and async validators, use `.validateAsync()`. | ||
* @param opts Options to pass to the validator system. | ||
*/ | ||
validate(opts) { | ||
const errors = this.getValidationErrors(opts); | ||
assertEmptyErrorList(errors); | ||
return this.toJSON(); | ||
} | ||
/** | ||
* Validates this object asynchronously, and resolves to its plain data if validations pass. | ||
* Otherwise, rejects with an error or runs the appropriate handler set with `setValidationErrorHandler()`. | ||
* | ||
* To validate synchronously, use `.validate()`. | ||
* @param opts Options to pass to the validator system. | ||
*/ | ||
async validateAsync(opts) { | ||
const errors = await this.getValidationErrorsAsync(opts); | ||
assertEmptyErrorList(errors); | ||
return this.toJSON(); | ||
} | ||
/** | ||
* Returns a JSON friendly object containing only data properties of this object (ie, no validation functions). | ||
@@ -69,0 +109,0 @@ * Automatically used by `JSON.stringify()`. |
export * from './data-transfer-object'; | ||
export * from './validation-error-handler'; | ||
export * from './validation-error-map'; | ||
export * from './validation-exception'; | ||
export * from 'class-validator'; |
export * from './data-transfer-object'; | ||
export * from './validation-error-handler'; | ||
export * from './validation-error-map'; | ||
export * from './validation-exception'; | ||
export * from 'class-validator'; |
{ | ||
"name": "data-transfer-object", | ||
"version": "0.3.0", | ||
"version": "0.4.0", | ||
"description": "Data Transfer Object class built on `class-validator`.", | ||
@@ -39,3 +39,4 @@ "keywords": [ | ||
"docs:readme": "doctoc --title \"**Table of contents**\" readme.md", | ||
"docs:api": "typedoc src/index.ts" | ||
"docs:api": "typedoc src/index.ts", | ||
"changelog": "standard-changelog" | ||
}, | ||
@@ -56,2 +57,3 @@ "dependencies": { | ||
"rimraf": "^3.0.2", | ||
"standard-changelog": "^2.0.27", | ||
"ts-jest": "^26.4.4", | ||
@@ -58,0 +60,0 @@ "ts-node": "^9.1.1", |
245
readme.md
# data-transfer-object | ||
Data Transfer Object class built on [TypeStacks's `class-validator`](https://github.com/typestack/class-validator). Allows you to build a DTO class that automatically validates input from outside sources and ensures its shape is correct. | ||
Data Transfer Object class built on [TypeStacks's `class-validator`](https://github.com/typestack/class-validator). Allows you to build a class that validates input from outside sources and ensures its shape is correct. Full TypeScript support with strict, strong typing. | ||
@@ -12,7 +12,11 @@ <!-- START doctoc generated TOC please keep comment here to allow auto update --> | ||
- [For browsers (script tag)](#for-browsers-script-tag) | ||
- [Release notes](#release-notes) | ||
- [Usage](#usage) | ||
- [TypeScript notes](#typescript-notes) | ||
- [Documentation](#documentation) | ||
- [Example](#example) | ||
- [Development](#development) | ||
- [Throwing a custom error on validation failure](#throwing-a-custom-error-on-validation-failure) | ||
- [Accessing raw error data in custom error handler](#accessing-raw-error-data-in-custom-error-handler) | ||
- [Get validation errors without throwing an error](#get-validation-errors-without-throwing-an-error) | ||
- [Run async validators](#run-async-validators) | ||
- [Full API Documentation](#full-api-documentation) | ||
- [Comprehensive example](#comprehensive-example) | ||
- [Development and contributions](#development-and-contributions) | ||
- [License](#license) | ||
@@ -34,7 +38,11 @@ | ||
UMD builds aren't available yet. Rollup builds are planned for the future. | ||
Browser builds aren't available yet, but they are planned for the future. | ||
## Release notes | ||
See information about breaking changes and release notes [here](changelog.md). | ||
## Usage | ||
Create a DTO class by importing `DataTransferObject`, extending it with your custom properties, and using the appropriate decorators. This package re-exports all decorators and functions from [TypeStack's `class-validator`](https://github.com/typestack/class-validator). | ||
Create your own classes by importing and extending `DataTransferObject` with your own properties, and using the appropriate validator decorators. This package re-exports all decorators and functions from [TypeStack's `class-validator`](https://github.com/typestack/class-validator). | ||
@@ -51,23 +59,94 @@ ```typescript | ||
Once your class is defined, you can instantiate it, pass your input into it, and validate it: | ||
**TypeScript note:** when using TypeScript with `"strict": true`, you must use non-null assertions (`!:`) when declaring class properties. Also, `experimentalDecorators` and `emitDecoratorMetadata` must be set to `true` in your `tsconfig.json`. | ||
Once your class is defined, you can construct a new instance of it, pass your input into it, and run `.validate()` on it. If your input is valid, it will return a plain object with the validated data. Otherwise, by default, a `ValidationException` will be thrown. | ||
```typescript | ||
const input = new MyDto({ myString: 12 }); | ||
const errors = input.validate(); | ||
// `errors` will be an array of `ValidationError` objects. | ||
console.log(errors); | ||
try { | ||
const validated = new MyDto(input).validate(); | ||
console.log(validated); | ||
// validated === input | ||
} catch (err) { | ||
if (err instanceof ValidationException) { | ||
console.error(err.validationErrors); | ||
// e.g. if `input` was `{ myString: 1234 }`, this would output: | ||
{ "myString": ["property myString should be a string"] } | ||
} | ||
} | ||
``` | ||
// outputs: | ||
[ | ||
{ | ||
target: { myString: 12 }, | ||
value: 12, | ||
property: 'myString', | ||
children: [], | ||
constraints: { isString: 'myString must be a string' }, | ||
### Throwing a custom error on validation failure | ||
You can use `setValidationErrorHandler()` to register a callback to run whenever a `.validate()` call fails on any object across your project. For instance: | ||
```typescript | ||
import { setValidationErrorHandler, ValidationErrorMap } from 'data-transfer-object'; | ||
class CustomError extends Error { | ||
statusCode = 400; | ||
errors: ValidationErrorMap; | ||
constructor(errors: ValidationErrorMap) { | ||
super('Failed to validate'); | ||
this.errors = errors; | ||
} | ||
} | ||
setValidationErrorHandler(errors => { | ||
throw new CustomError(errors); | ||
}); | ||
try { | ||
new MyExampleDto({ invalidData: 42 }).validate(); | ||
} catch (err) { | ||
if (err instanceof CustomError) { | ||
console.error(`Request failed with error code ${err.statusCode}`); | ||
console.error(err.errors); | ||
} | ||
} | ||
``` | ||
#### Accessing raw error data in custom error handler | ||
Under the hood, `data-transfer-object` formats the raw array of `ValidationError` returned by `class-validator` into an object mapping keys to properties and values to validation messages (aka a `ValidationErrorMap`). | ||
If you wish to get direct access to the array of `ValidationError` in your error handler, you may pass in `{ rawErrors: true }` as a second parameter to `.setValidationErrorHandler()`: | ||
```typescript | ||
import { setValidationErrorHandler } from 'data-transfer-object'; | ||
setValidationErrorHandler( | ||
errors => { | ||
// `errors` here is now of type `ValidationError[]`. | ||
console.error(errors); | ||
// example output: | ||
[ | ||
{ | ||
target: { myString: 12 }, | ||
value: 12, | ||
property: 'myString', | ||
children: [], | ||
constraints: { isString: 'myString must be a string' }, | ||
}, | ||
]; | ||
}, | ||
]; | ||
{ rawErrors: true }, | ||
); | ||
``` | ||
### Get validation errors without throwing an error | ||
You may use `.getValidationErrors()` to get an array of `ValidationError` without having to thrown an actual error. To get the plain data later, use `.toJSON()`. | ||
```typescript | ||
const dto = new MyDto({ someData: 'data' }); | ||
const errors = dto.getValidationErrors(); | ||
if (errors.length) { | ||
console.error(errors); | ||
return; | ||
} | ||
const data = dto.toJSON(); | ||
``` | ||
Validating it will also silently drop all unknown properties from the input: | ||
@@ -85,16 +164,24 @@ | ||
### TypeScript notes | ||
### Run async validators | ||
Note that when using TypeScript with `"strict": true`, you must use non-null assertions (`!:`) when declaring class properties. Also, `experimentalDecorators` and `emitDecoratorMetadata` must be set to `true` in your `tsconfig.json`. | ||
`.validate()` and `.getValidationErrors()` will only run synchronous validators, which covers most use cases in a web application. If you would like to run asynchronous validators as well, use `.validateAsync()` and `.getValidationErrorsAsync()` respectively. These counterparts will always return a promise, even if there are no async validators on the validated object. | ||
## Documentation | ||
## Full API Documentation | ||
The most up-to-date documentation for all exported items from this package is automatically generated from code and available at https://danielegarciav.github.io/data-transfer-object/. | ||
## Example | ||
You may wish to uncheck the "Externals" checkbox option (top-right on desktop, cog icon on mobile) in order to hide documentation from `class-validator` and focus only on what this package exports. | ||
In the following example, we have an Express application that lets us sign up users. In order to validate input from the web app client, we create a data transfer object representing the input data, and attach our desired validators: | ||
## Comprehensive example | ||
In the following example, we have an Express application that lets us sign up users. | ||
- We define an `UserSignupInput` data transfer object class. | ||
- We define our own custom errors `ApiError` and `ApiValidationError`, which allow us to define a status code, among other things. | ||
- We define an [Express error handler](https://expressjs.com/en/guide/error-handling.html) to catch any errors and format the result that will be sent back to our client. | ||
- We wire everything up as an Express app, and make it so validation errors throw an `ApiValidationError`, which will be then appropriately handled by our Express error handler. | ||
- We can then write our signup controller. | ||
```typescript | ||
// input-dtos.ts | ||
// input-classes.ts | ||
@@ -118,46 +205,96 @@ import { DataTransferObject, IsString, Length, MinLength } from 'data-transfer-object'; | ||
The Express request handler in our example: | ||
```typescript | ||
// custom-errors.ts | ||
import { ValidationErrorMap } from 'data-transfer-object'; | ||
export class ApiError extends Error { | ||
type: string; | ||
statusCode: number; | ||
constructor(type: ApiErrorType, statusCode?: number, message?: string) { | ||
super(message); | ||
this.name = 'ApiError'; | ||
this.type = type; | ||
this.message = message ?? 'Unspecified error'; | ||
this.statusCode = statusCode ?? 500; | ||
} | ||
} | ||
export class ApiValidationError extends ApiError { | ||
validationMessages: ValidationErrorMap; | ||
constructor(errors: ValidationErrorMap) { | ||
super('InvalidRequest', 400, 'Request is invalid'); | ||
this.validationMessages = errors; | ||
} | ||
} | ||
``` | ||
```typescript | ||
// signup-controller.ts | ||
// error-handler.ts | ||
import { Request, Response } from 'express'; | ||
import { User } from './models'; | ||
import { UserSignupInput } from './input-dtos'; | ||
import { Request, Response, NextFunction } from 'express'; | ||
import { ApiError } from './custom-errors'; | ||
export async function signup(req: Request, res: Response): { | ||
// Construct a new DTO instance passing starting state as argument. | ||
const input = new UserSignupInput(req.body); | ||
export function expressErrorHandler( | ||
error: Error | ApiError, | ||
req: Request, | ||
res: Response, | ||
next: NextFunction, | ||
) { | ||
const statusCode = error instanceof ApiError ? error.statusCode : 500; | ||
const jsonResponse = { error: { ...error, statusCode } }; | ||
// Run validation. Only synchronous validators are run by default, which covers most use cases. | ||
const errors = input.validate(); | ||
// Log non-ApiErrors to console | ||
if (!(error instanceof ApiError)) console.error(error); | ||
// You may also use `.validateAsync()` to run both sync + async validators. | ||
const asyncErrors = await input.validateAsync(); | ||
res.status(statusCode).json(jsonResponse); | ||
} | ||
``` | ||
// Result will be an array of `ValidationError[]` | ||
if (errors.length) { | ||
// Handle validation errors here, for example: | ||
return res.status(400).json(errors); | ||
} | ||
```typescript | ||
// express-server.ts | ||
// Your input is guaranteed to be validated at this point. | ||
await User.register(input); | ||
import Express from 'express'; | ||
import { setValidationErrorHandler } from 'data-transfer-object'; | ||
import { expressErrorHandler } from './error-handler.ts'; | ||
import { ApiValidationError } from './custom-errors.ts'; | ||
import { signup } from './signup-controller.ts'; | ||
// Use `.toJSON()` to get a plain object with just your data. | ||
// `.toJSON()` is automatically called when a DTO instance is stringified. | ||
const data = input.toJSON(); | ||
typeof input.validate === 'function'; | ||
typeof data.validate === 'undefined'; | ||
setValidationErrorHandler(errors => { | ||
throw new ApiValidationError(errors); | ||
}); | ||
return res.status(200).json({ success: true }); | ||
export const app = Express(); | ||
app.use(Express.json()); | ||
app.use('/users/signup', signup); | ||
app.use(expressErrorHandler); | ||
``` | ||
```typescript | ||
// signup-controller.ts | ||
import { Request, Response, NextFunction } from 'express'; | ||
import { User } from './models'; | ||
import { UserSignupInput } from './input-classes'; | ||
export async function signup(req: Request, res: Response, next: NextFunction) { | ||
try { | ||
const { username, password } = new UserSignupInput(req.body).validate(); | ||
await User.register(username, password); | ||
return res.status(200).json({ success: true }); | ||
} catch (err) { | ||
return next(err); | ||
} | ||
} | ||
``` | ||
## Development | ||
We may also use something like [`express-async-errors`](https://github.com/davidbanham/express-async-errors) in order to avoid having to wrap our async code in try/catch statements and manually calling `next()`. This is something that will be automatically addressed by Express 5 once it is released. | ||
Check package.json to find scripts related to installing dependencies, building, testing, linting and generating documentation. | ||
## Development and contributions | ||
Check package.json to find scripts related to installing dependencies, building, testing, linting and generating documentation. I am open to new issues and pull requests! | ||
## License | ||
MIT |
import { validate, validateSync, ValidationError, ValidatorOptions } from 'class-validator'; | ||
export * from 'class-validator'; | ||
import { ValidationException } from './validation-exception'; | ||
import { onValidationError } from './validation-error-handler'; | ||
@@ -16,4 +17,7 @@ // Simple conditional mapping turns function types into `never` types | ||
// Strict options by default | ||
const defaultOpts: ValidatorOptions = { | ||
whitelist: true, | ||
forbidNonWhitelisted: true, | ||
forbidUnknownValues: true, | ||
}; | ||
@@ -31,2 +35,14 @@ | ||
/** | ||
* Checks the input error list, and if non-empty, throws an error. | ||
* @param errors The error list to check against. | ||
*/ | ||
function assertEmptyErrorList(errors: ValidationError[]) { | ||
if (errors.length) { | ||
if (!onValidationError) throw new ValidationException(errors); | ||
onValidationError(errors); | ||
throw new ValidationException(errors); | ||
} | ||
} | ||
/** | ||
* Creates a new data transfer object which will validate and reshape its input | ||
@@ -54,6 +70,6 @@ * data based on the validators of its own properties. Must be extended, should | ||
* Runs all synchronous validators on this object. | ||
* To run asynchronous validators as well, use `.validateAsync()`. | ||
* To run asynchronous validators as well, use `.getValidationErrorsAsync()`. | ||
* @param opts Options to pass to the validator system. | ||
*/ | ||
validate(opts?: ValidatorOptions): ValidationError[] { | ||
getValidationErrors(opts?: ValidatorOptions): ValidationError[] { | ||
if (this[validated]) return this[validationErrors]; | ||
@@ -67,6 +83,6 @@ this[validationErrors] = validateSync(this, { ...defaultOpts, ...opts }); | ||
* Runs all synchronous and asynchronous validators on this object. | ||
* Always returns a promise. To validate synchronously, use `.validate()`. | ||
* Always returns a promise. To validate synchronously, use `.getValidationErrors()`. | ||
* @param opts Options to pass to the validator system. | ||
*/ | ||
async validateAsync(opts?: ValidatorOptions): Promise<ValidationError[]> { | ||
async getValidationErrorsAsync(opts?: ValidatorOptions): Promise<ValidationError[]> { | ||
if (this[validated]) return this[validationErrors]; | ||
@@ -89,2 +105,28 @@ | ||
/** | ||
* Validates this object (sync validators only), and returns its plain data if validations pass. | ||
* Otherwise, throws an error or runs the appropriate handler set with `setValidationErrorHandler()`. | ||
* | ||
* To run both sync and async validators, use `.validateAsync()`. | ||
* @param opts Options to pass to the validator system. | ||
*/ | ||
validate(opts?: ValidatorOptions): Data<this> { | ||
const errors = this.getValidationErrors(opts); | ||
assertEmptyErrorList(errors); | ||
return this.toJSON(); | ||
} | ||
/** | ||
* Validates this object asynchronously, and resolves to its plain data if validations pass. | ||
* Otherwise, rejects with an error or runs the appropriate handler set with `setValidationErrorHandler()`. | ||
* | ||
* To validate synchronously, use `.validate()`. | ||
* @param opts Options to pass to the validator system. | ||
*/ | ||
async validateAsync(opts?: ValidatorOptions): Promise<Data<this>> { | ||
const errors = await this.getValidationErrorsAsync(opts); | ||
assertEmptyErrorList(errors); | ||
return this.toJSON(); | ||
} | ||
/** | ||
* Returns a JSON friendly object containing only data properties of this object (ie, no validation functions). | ||
@@ -91,0 +133,0 @@ * Automatically used by `JSON.stringify()`. |
export * from './data-transfer-object'; | ||
export * from './validation-error-handler'; | ||
export * from './validation-error-map'; | ||
export * from './validation-exception'; | ||
export * from 'class-validator'; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
51399
29
859
296
15