@dangao/bun-server 1.7.1 → 1.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +129 -21
- package/dist/di/decorators.d.ts +37 -0
- package/dist/di/decorators.d.ts.map +1 -1
- package/dist/di/index.d.ts +1 -1
- package/dist/di/index.d.ts.map +1 -1
- package/dist/di/module-registry.d.ts +17 -0
- package/dist/di/module-registry.d.ts.map +1 -1
- package/dist/events/decorators.d.ts +52 -0
- package/dist/events/decorators.d.ts.map +1 -0
- package/dist/events/event-module.d.ts +97 -0
- package/dist/events/event-module.d.ts.map +1 -0
- package/dist/events/index.d.ts +5 -0
- package/dist/events/index.d.ts.map +1 -0
- package/dist/events/service.d.ts +76 -0
- package/dist/events/service.d.ts.map +1 -0
- package/dist/events/types.d.ts +184 -0
- package/dist/events/types.d.ts.map +1 -0
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1511 -11
- package/dist/security/filter.d.ts +23 -0
- package/dist/security/filter.d.ts.map +1 -1
- package/dist/security/guards/builtin/auth-guard.d.ts +44 -0
- package/dist/security/guards/builtin/auth-guard.d.ts.map +1 -0
- package/dist/security/guards/builtin/index.d.ts +3 -0
- package/dist/security/guards/builtin/index.d.ts.map +1 -0
- package/dist/security/guards/builtin/roles-guard.d.ts +66 -0
- package/dist/security/guards/builtin/roles-guard.d.ts.map +1 -0
- package/dist/security/guards/decorators.d.ts +50 -0
- package/dist/security/guards/decorators.d.ts.map +1 -0
- package/dist/security/guards/execution-context.d.ts +56 -0
- package/dist/security/guards/execution-context.d.ts.map +1 -0
- package/dist/security/guards/guard-registry.d.ts +67 -0
- package/dist/security/guards/guard-registry.d.ts.map +1 -0
- package/dist/security/guards/index.d.ts +7 -0
- package/dist/security/guards/index.d.ts.map +1 -0
- package/dist/security/guards/reflector.d.ts +57 -0
- package/dist/security/guards/reflector.d.ts.map +1 -0
- package/dist/security/guards/types.d.ts +126 -0
- package/dist/security/guards/types.d.ts.map +1 -0
- package/dist/security/index.d.ts +1 -0
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/security-module.d.ts +20 -0
- package/dist/security/security-module.d.ts.map +1 -1
- package/dist/validation/class-validator.d.ts +108 -0
- package/dist/validation/class-validator.d.ts.map +1 -0
- package/dist/validation/custom-validator.d.ts +130 -0
- package/dist/validation/custom-validator.d.ts.map +1 -0
- package/dist/validation/errors.d.ts +22 -2
- package/dist/validation/errors.d.ts.map +1 -1
- package/dist/validation/index.d.ts +7 -1
- package/dist/validation/index.d.ts.map +1 -1
- package/dist/validation/rules/array.d.ts +33 -0
- package/dist/validation/rules/array.d.ts.map +1 -0
- package/dist/validation/rules/common.d.ts +90 -0
- package/dist/validation/rules/common.d.ts.map +1 -0
- package/dist/validation/rules/conditional.d.ts +30 -0
- package/dist/validation/rules/conditional.d.ts.map +1 -0
- package/dist/validation/rules/index.d.ts +5 -0
- package/dist/validation/rules/index.d.ts.map +1 -0
- package/dist/validation/rules/object.d.ts +30 -0
- package/dist/validation/rules/object.d.ts.map +1 -0
- package/dist/validation/types.d.ts +52 -1
- package/dist/validation/types.d.ts.map +1 -1
- package/docs/events.md +494 -0
- package/docs/guards.md +376 -0
- package/docs/guide.md +309 -1
- package/docs/request-lifecycle.md +444 -0
- package/docs/validation.md +407 -0
- package/docs/zh/events.md +494 -0
- package/docs/zh/guards.md +376 -0
- package/docs/zh/guide.md +309 -1
- package/docs/zh/request-lifecycle.md +444 -0
- package/docs/zh/validation.md +407 -0
- package/package.json +1 -1
- package/src/di/decorators.ts +46 -0
- package/src/di/index.ts +10 -1
- package/src/di/module-registry.ts +39 -0
- package/src/events/decorators.ts +103 -0
- package/src/events/event-module.ts +272 -0
- package/src/events/index.ts +32 -0
- package/src/events/service.ts +352 -0
- package/src/events/types.ts +223 -0
- package/src/index.ts +133 -1
- package/src/security/filter.ts +88 -8
- package/src/security/guards/builtin/auth-guard.ts +68 -0
- package/src/security/guards/builtin/index.ts +3 -0
- package/src/security/guards/builtin/roles-guard.ts +165 -0
- package/src/security/guards/decorators.ts +124 -0
- package/src/security/guards/execution-context.ts +152 -0
- package/src/security/guards/guard-registry.ts +164 -0
- package/src/security/guards/index.ts +7 -0
- package/src/security/guards/reflector.ts +99 -0
- package/src/security/guards/types.ts +144 -0
- package/src/security/index.ts +1 -0
- package/src/security/security-module.ts +72 -2
- package/src/validation/class-validator.ts +322 -0
- package/src/validation/custom-validator.ts +289 -0
- package/src/validation/errors.ts +50 -2
- package/src/validation/index.ts +103 -1
- package/src/validation/rules/array.ts +118 -0
- package/src/validation/rules/common.ts +286 -0
- package/src/validation/rules/conditional.ts +52 -0
- package/src/validation/rules/index.ts +51 -0
- package/src/validation/rules/object.ts +86 -0
- package/src/validation/types.ts +61 -1
- package/tests/auth/auth-decorators.test.ts +241 -0
- package/tests/auth/oauth2-service.test.ts +318 -0
- package/tests/cache/cache-decorators-extended.test.ts +272 -0
- package/tests/cache/cache-interceptors.test.ts +534 -0
- package/tests/cache/cache-service-proxy.test.ts +246 -0
- package/tests/cache/memory-cache-store.test.ts +155 -0
- package/tests/cache/redis-cache-store.test.ts +199 -0
- package/tests/config/config-center-integration.test.ts +334 -0
- package/tests/config/config-module-extended.test.ts +165 -0
- package/tests/controller/param-binder.test.ts +333 -0
- package/tests/di/global-module.test.ts +487 -0
- package/tests/error/error-handler.test.ts +166 -57
- package/tests/error/i18n-extended.test.ts +105 -0
- package/tests/events/event-decorators.test.ts +173 -0
- package/tests/events/event-emitter.test.ts +373 -0
- package/tests/events/event-listener-scanner.test.ts +114 -0
- package/tests/events/event-module.test.ts +204 -0
- package/tests/extensions/logger-module.test.ts +158 -0
- package/tests/files/file-storage.test.ts +136 -0
- package/tests/interceptor/base-interceptor.test.ts +605 -0
- package/tests/interceptor/builtin/cache-interceptor.test.ts +233 -86
- package/tests/interceptor/builtin/log-interceptor.test.ts +469 -0
- package/tests/interceptor/builtin/permission-interceptor.test.ts +219 -120
- package/tests/interceptor/interceptor-chain.test.ts +241 -189
- package/tests/interceptor/interceptor-metadata.test.ts +221 -0
- package/tests/microservice/circuit-breaker.test.ts +221 -0
- package/tests/microservice/service-client-decorators.test.ts +86 -0
- package/tests/microservice/service-client-interceptors.test.ts +274 -0
- package/tests/microservice/service-registry-decorators.test.ts +147 -0
- package/tests/microservice/tracer.test.ts +213 -0
- package/tests/microservice/tracing-collectors.test.ts +168 -0
- package/tests/middleware/builtin/middleware-builtin-extended.test.ts +237 -0
- package/tests/middleware/builtin/rate-limit.test.ts +257 -0
- package/tests/middleware/middleware-decorators.test.ts +222 -0
- package/tests/middleware/middleware-pipeline.test.ts +160 -0
- package/tests/queue/queue-decorators.test.ts +139 -0
- package/tests/queue/queue-service.test.ts +191 -0
- package/tests/request/body-parser-extended.test.ts +291 -0
- package/tests/request/request-wrapper.test.ts +319 -0
- package/tests/router/router-decorators.test.ts +260 -0
- package/tests/router/router-extended.test.ts +298 -0
- package/tests/security/guards/guards-integration.test.ts +371 -0
- package/tests/security/guards/guards.test.ts +775 -0
- package/tests/security/guards/reflector.test.ts +188 -0
- package/tests/security/security-filter.test.ts +182 -0
- package/tests/security/security-module-extended.test.ts +133 -0
- package/tests/security/security-module.test.ts +2 -2
- package/tests/session/memory-session-store.test.ts +172 -0
- package/tests/session/session-decorators.test.ts +163 -0
- package/tests/swagger/ui.test.ts +212 -0
- package/tests/validation/class-validator.test.ts +349 -0
- package/tests/validation/custom-validator.test.ts +335 -0
- package/tests/validation/rules.test.ts +543 -0
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
# Validation System
|
|
2
|
+
|
|
3
|
+
Bun Server Framework provides a powerful validation system for validating request parameters, DTOs, and complex data structures.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Basic Validation](#basic-validation)
|
|
8
|
+
- [Validation Rules](#validation-rules)
|
|
9
|
+
- [Object Rules](#object-rules)
|
|
10
|
+
- [Array Rules](#array-rules)
|
|
11
|
+
- [Common Rules](#common-rules)
|
|
12
|
+
- [Conditional Rules](#conditional-rules)
|
|
13
|
+
- [Class-Level Validation](#class-level-validation)
|
|
14
|
+
- [Nested Object Validation](#nested-object-validation)
|
|
15
|
+
- [Custom Validators](#custom-validators)
|
|
16
|
+
- [Built-in Extended Validators](#built-in-extended-validators)
|
|
17
|
+
- [Error Handling](#error-handling)
|
|
18
|
+
|
|
19
|
+
## Basic Validation
|
|
20
|
+
|
|
21
|
+
Use the `@Validate()` decorator on controller method parameters:
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import { Controller, GET, Query, Validate, IsString, IsEmail, IsOptional, MinLength } from '@dangao/bun-server';
|
|
25
|
+
|
|
26
|
+
@Controller('/api/users')
|
|
27
|
+
class UserController {
|
|
28
|
+
@GET('/search')
|
|
29
|
+
public search(
|
|
30
|
+
@Query('email') @Validate(IsEmail()) email: string,
|
|
31
|
+
@Query('name') @Validate(IsOptional(), IsString(), MinLength(2)) name?: string,
|
|
32
|
+
) {
|
|
33
|
+
return { email, name };
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Validation Rules
|
|
39
|
+
|
|
40
|
+
### Object Rules
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
import { IsObject, IsNotEmpty, IsNotEmptyObject, ValidateNested } from '@dangao/bun-server';
|
|
44
|
+
|
|
45
|
+
// Validate value is an object
|
|
46
|
+
IsObject()
|
|
47
|
+
|
|
48
|
+
// Validate value is not empty (null, undefined, empty string, empty array, empty object)
|
|
49
|
+
IsNotEmpty()
|
|
50
|
+
|
|
51
|
+
// Validate value is a non-empty object
|
|
52
|
+
IsNotEmptyObject()
|
|
53
|
+
|
|
54
|
+
// Mark property for nested validation
|
|
55
|
+
ValidateNested({ each?: boolean }) // each: true for array elements
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Array Rules
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
import {
|
|
62
|
+
IsArray, ArrayMinSize, ArrayMaxSize, ArrayUnique,
|
|
63
|
+
ArrayContains, ArrayNotContains, ArrayNotEmpty
|
|
64
|
+
} from '@dangao/bun-server';
|
|
65
|
+
|
|
66
|
+
// Validate value is an array
|
|
67
|
+
IsArray()
|
|
68
|
+
|
|
69
|
+
// Validate array minimum length
|
|
70
|
+
ArrayMinSize(2)
|
|
71
|
+
|
|
72
|
+
// Validate array maximum length
|
|
73
|
+
ArrayMaxSize(10)
|
|
74
|
+
|
|
75
|
+
// Validate array elements are unique
|
|
76
|
+
ArrayUnique()
|
|
77
|
+
|
|
78
|
+
// Validate array contains specific values
|
|
79
|
+
ArrayContains([1, 2])
|
|
80
|
+
|
|
81
|
+
// Validate array does not contain specific values
|
|
82
|
+
ArrayNotContains(['banned'])
|
|
83
|
+
|
|
84
|
+
// Validate array is not empty
|
|
85
|
+
ArrayNotEmpty()
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Common Rules
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
import {
|
|
92
|
+
IsString, IsNumber, IsBoolean, IsInt, IsPositive, IsNegative,
|
|
93
|
+
Min, Max, IsDate, IsUUID, Length, MaxLength, MinLength,
|
|
94
|
+
Matches, IsIn, IsNotIn, IsUrl, IsJSON, IsEmail,
|
|
95
|
+
Equals, NotEquals, IsDefined, IsAlphanumeric, IsAlpha, IsNumberString
|
|
96
|
+
} from '@dangao/bun-server';
|
|
97
|
+
|
|
98
|
+
// Type validation
|
|
99
|
+
IsString()
|
|
100
|
+
IsNumber()
|
|
101
|
+
IsBoolean()
|
|
102
|
+
IsInt()
|
|
103
|
+
IsDate()
|
|
104
|
+
|
|
105
|
+
// Number validation
|
|
106
|
+
IsPositive()
|
|
107
|
+
IsNegative()
|
|
108
|
+
Min(0)
|
|
109
|
+
Max(100)
|
|
110
|
+
|
|
111
|
+
// String validation
|
|
112
|
+
IsEmail()
|
|
113
|
+
IsUUID('4') // '3', '4', '5', or 'all'
|
|
114
|
+
Length(2, 10)
|
|
115
|
+
MinLength(2)
|
|
116
|
+
MaxLength(10)
|
|
117
|
+
Matches(/^[a-z]+$/)
|
|
118
|
+
IsUrl()
|
|
119
|
+
IsJSON()
|
|
120
|
+
IsAlphanumeric()
|
|
121
|
+
IsAlpha()
|
|
122
|
+
IsNumberString()
|
|
123
|
+
|
|
124
|
+
// Value validation
|
|
125
|
+
IsIn(['a', 'b', 'c'])
|
|
126
|
+
IsNotIn(['x', 'y', 'z'])
|
|
127
|
+
Equals('expected')
|
|
128
|
+
NotEquals('forbidden')
|
|
129
|
+
IsDefined()
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Conditional Rules
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
import { ValidateIf, Transform } from '@dangao/bun-server';
|
|
136
|
+
|
|
137
|
+
// Conditional validation - only validate when condition is true
|
|
138
|
+
ValidateIf((value, obj) => obj.type === 'premium')
|
|
139
|
+
|
|
140
|
+
// Transform value before validation
|
|
141
|
+
Transform((value) => String(value).trim())
|
|
142
|
+
Transform((value) => Number(value))
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Example usage:
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
@ValidateClass()
|
|
149
|
+
class UpdateUserDto {
|
|
150
|
+
@Property(ValidateIf((_, obj) => obj.type === 'premium'), IsEmail())
|
|
151
|
+
premiumEmail?: string;
|
|
152
|
+
|
|
153
|
+
@Property(Transform((v) => String(v).trim()), IsString(), MinLength(1))
|
|
154
|
+
name: string;
|
|
155
|
+
|
|
156
|
+
@Property(Transform((v) => Number(v)), IsInt(), Min(0))
|
|
157
|
+
age: number;
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Class-Level Validation
|
|
162
|
+
|
|
163
|
+
For DTO classes, use `@ValidateClass()` and `@Property()` decorators:
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
import { ValidateClass, Property, IsString, IsEmail, IsOptional, IsInt, Min, Max, MinLength } from '@dangao/bun-server';
|
|
167
|
+
|
|
168
|
+
@ValidateClass()
|
|
169
|
+
class CreateUserDto {
|
|
170
|
+
@Property(IsString(), MinLength(2))
|
|
171
|
+
name: string;
|
|
172
|
+
|
|
173
|
+
@Property(IsEmail())
|
|
174
|
+
email: string;
|
|
175
|
+
|
|
176
|
+
@Property(IsOptional(), IsInt(), Min(0), Max(150))
|
|
177
|
+
age?: number;
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Validate objects manually:
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
import { validateObject, validateObjectSync, ValidationError } from '@dangao/bun-server';
|
|
185
|
+
|
|
186
|
+
// Throws ValidationError on failure
|
|
187
|
+
try {
|
|
188
|
+
validateObject(data, CreateUserDto);
|
|
189
|
+
} catch (error) {
|
|
190
|
+
if (error instanceof ValidationError) {
|
|
191
|
+
console.log(error.issues);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Returns validation result without throwing
|
|
196
|
+
const result = validateObjectSync(data, CreateUserDto);
|
|
197
|
+
if (!result.valid) {
|
|
198
|
+
console.log(result.issues);
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Nested Object Validation
|
|
203
|
+
|
|
204
|
+
For nested objects and arrays:
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
import { ValidateClass, Property, NestedProperty, ArrayNestedProperty, IsString, IsNumber, Min, IsArray, ArrayMinSize } from '@dangao/bun-server';
|
|
208
|
+
|
|
209
|
+
@ValidateClass()
|
|
210
|
+
class AddressDto {
|
|
211
|
+
@Property(IsString())
|
|
212
|
+
city: string;
|
|
213
|
+
|
|
214
|
+
@Property(IsString())
|
|
215
|
+
street: string;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
@ValidateClass()
|
|
219
|
+
class ItemDto {
|
|
220
|
+
@Property(IsString())
|
|
221
|
+
name: string;
|
|
222
|
+
|
|
223
|
+
@Property(IsNumber(), Min(0))
|
|
224
|
+
price: number;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
@ValidateClass()
|
|
228
|
+
class CreateOrderDto {
|
|
229
|
+
@Property(IsString())
|
|
230
|
+
userId: string;
|
|
231
|
+
|
|
232
|
+
// Nested object validation
|
|
233
|
+
@NestedProperty(AddressDto)
|
|
234
|
+
shippingAddress: AddressDto;
|
|
235
|
+
|
|
236
|
+
// Array of nested objects validation
|
|
237
|
+
@Property(IsArray(), ArrayMinSize(1))
|
|
238
|
+
@ArrayNestedProperty(ItemDto)
|
|
239
|
+
items: ItemDto[];
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## Custom Validators
|
|
244
|
+
|
|
245
|
+
### Simple Custom Validator
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
import { createSimpleValidator } from '@dangao/bun-server';
|
|
249
|
+
|
|
250
|
+
const IsEven = createSimpleValidator(
|
|
251
|
+
'isEven',
|
|
252
|
+
(value) => typeof value === 'number' && value % 2 === 0,
|
|
253
|
+
'Must be an even number'
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
// Usage
|
|
257
|
+
@Property(IsEven())
|
|
258
|
+
count: number;
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Parameterized Custom Validator
|
|
262
|
+
|
|
263
|
+
```typescript
|
|
264
|
+
import { createCustomValidator } from '@dangao/bun-server';
|
|
265
|
+
|
|
266
|
+
const IsDivisibleBy = createCustomValidator(
|
|
267
|
+
'isDivisibleBy',
|
|
268
|
+
(value: unknown, divisor: number) => typeof value === 'number' && value % divisor === 0,
|
|
269
|
+
(divisor: number) => `Must be divisible by ${divisor}`
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
// Usage
|
|
273
|
+
@Property(IsDivisibleBy(5)())
|
|
274
|
+
value: number;
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### Regex Custom Validator
|
|
278
|
+
|
|
279
|
+
```typescript
|
|
280
|
+
import { createRegexValidator } from '@dangao/bun-server';
|
|
281
|
+
|
|
282
|
+
const IsSlug = createRegexValidator(
|
|
283
|
+
'isSlug',
|
|
284
|
+
/^[a-z0-9]+(?:-[a-z0-9]+)*$/,
|
|
285
|
+
'Must be a valid slug format'
|
|
286
|
+
);
|
|
287
|
+
|
|
288
|
+
// Usage
|
|
289
|
+
@Property(IsSlug())
|
|
290
|
+
slug: string;
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
## Built-in Extended Validators
|
|
294
|
+
|
|
295
|
+
The framework provides several pre-built validators for common use cases:
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
import {
|
|
299
|
+
IsPhoneNumber, // Chinese phone number
|
|
300
|
+
IsIdCard, // Chinese ID card
|
|
301
|
+
IsIPv4, // IPv4 address
|
|
302
|
+
IsPort, // Port number (0-65535)
|
|
303
|
+
IsPostalCode, // Chinese postal code
|
|
304
|
+
IsCreditCard, // Credit card (Luhn algorithm)
|
|
305
|
+
IsHexColor, // Hex color (#fff or #ffffff)
|
|
306
|
+
IsMacAddress, // MAC address
|
|
307
|
+
IsSemVer, // Semantic version
|
|
308
|
+
IsDivisibleBy, // Divisible by number
|
|
309
|
+
IsBetween, // Number in range
|
|
310
|
+
Contains, // String contains substring
|
|
311
|
+
NotContains, // String does not contain substring
|
|
312
|
+
} from '@dangao/bun-server';
|
|
313
|
+
|
|
314
|
+
// Usage examples
|
|
315
|
+
@Property(IsPhoneNumber())
|
|
316
|
+
phone: string;
|
|
317
|
+
|
|
318
|
+
@Property(IsIPv4())
|
|
319
|
+
ip: string;
|
|
320
|
+
|
|
321
|
+
@Property(IsBetween(1, 100)())
|
|
322
|
+
percentage: number;
|
|
323
|
+
|
|
324
|
+
@Property(Contains('http')())
|
|
325
|
+
url: string;
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
## Error Handling
|
|
329
|
+
|
|
330
|
+
### ValidationError
|
|
331
|
+
|
|
332
|
+
When validation fails, a `ValidationError` is thrown:
|
|
333
|
+
|
|
334
|
+
```typescript
|
|
335
|
+
import { ValidationError, ValidationIssue } from '@dangao/bun-server';
|
|
336
|
+
|
|
337
|
+
try {
|
|
338
|
+
validateObject(data, MyDto);
|
|
339
|
+
} catch (error) {
|
|
340
|
+
if (error instanceof ValidationError) {
|
|
341
|
+
// Access validation issues
|
|
342
|
+
console.log(error.issues);
|
|
343
|
+
|
|
344
|
+
// Get flattened errors (useful for nested objects)
|
|
345
|
+
console.log(error.getFlattened());
|
|
346
|
+
|
|
347
|
+
// Convert to JSON
|
|
348
|
+
console.log(error.toJSON());
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### ValidationIssue Structure
|
|
354
|
+
|
|
355
|
+
```typescript
|
|
356
|
+
interface ValidationIssue {
|
|
357
|
+
index?: number; // Parameter index (for parameter validation)
|
|
358
|
+
property?: string; // Property path (e.g., 'user.address.city')
|
|
359
|
+
rule: string; // Failed rule name
|
|
360
|
+
message: string; // Error message
|
|
361
|
+
value?: unknown; // The value that failed validation
|
|
362
|
+
children?: ValidationIssue[]; // Nested errors
|
|
363
|
+
}
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
### Controller Integration
|
|
367
|
+
|
|
368
|
+
Validation errors are automatically caught and returned as 400 Bad Request responses:
|
|
369
|
+
|
|
370
|
+
```typescript
|
|
371
|
+
@Controller('/api/users')
|
|
372
|
+
class UserController {
|
|
373
|
+
@POST('/')
|
|
374
|
+
public async createUser(@Body() @Validate(IsObject()) body: unknown) {
|
|
375
|
+
const dto = body as CreateUserDto;
|
|
376
|
+
validateObject(dto, CreateUserDto);
|
|
377
|
+
// ... create user
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
## Best Practices
|
|
383
|
+
|
|
384
|
+
1. **Use DTOs for complex validation**: For request bodies with multiple fields, use `@ValidateClass()` decorated DTOs.
|
|
385
|
+
|
|
386
|
+
2. **Combine rules**: Chain multiple rules for comprehensive validation:
|
|
387
|
+
```typescript
|
|
388
|
+
@Property(IsString(), MinLength(2), MaxLength(50), Matches(/^[a-zA-Z\s]+$/))
|
|
389
|
+
name: string;
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
3. **Use IsOptional() first**: Always place `IsOptional()` at the beginning of the rule chain:
|
|
393
|
+
```typescript
|
|
394
|
+
@Property(IsOptional(), IsString(), MinLength(2))
|
|
395
|
+
nickname?: string;
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
4. **Transform before validate**: Use `Transform()` to normalize data before validation:
|
|
399
|
+
```typescript
|
|
400
|
+
@Property(Transform((v) => String(v).toLowerCase().trim()), IsEmail())
|
|
401
|
+
email: string;
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
5. **Custom error messages**: Provide clear, user-friendly error messages:
|
|
405
|
+
```typescript
|
|
406
|
+
IsEmail({ message: 'Please enter a valid email address' })
|
|
407
|
+
```
|