alado 2.2.4 → 2.2.6
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 +193 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
- [withAuth](#withauth)
|
|
22
22
|
- [DTOs](#dtos)
|
|
23
23
|
- [validateProperty](#validateproperty)
|
|
24
|
+
- [validate](#validate)
|
|
24
25
|
- [documentProperty](#documentproperty)
|
|
25
26
|
- [transformProperty](#transformproperty)
|
|
26
27
|
- [fileUploadProperty](#fileuploadproperty)
|
|
@@ -108,6 +109,8 @@ app.start(() => console.log('Running on http://localhost:3000'));
|
|
|
108
109
|
|
|
109
110
|
---
|
|
110
111
|
|
|
112
|
+
## Example API: https://github.com/databikers/alado-decorators-api-example
|
|
113
|
+
|
|
111
114
|
## Project Structure
|
|
112
115
|
|
|
113
116
|
Possible layout for a decorator-based Alado project:
|
|
@@ -400,6 +403,196 @@ class CredentialsDto {
|
|
|
400
403
|
|
|
401
404
|
---
|
|
402
405
|
|
|
406
|
+
## Validation
|
|
407
|
+
|
|
408
|
+
The project uses a built-in chainable validator — a lightweight Joi-like class with zero dependencies.
|
|
409
|
+
|
|
410
|
+
### Basic usage
|
|
411
|
+
|
|
412
|
+
```ts
|
|
413
|
+
import { validate } from 'alado';
|
|
414
|
+
|
|
415
|
+
const isEmail = validate.string().email().required().build();
|
|
416
|
+
const isUsername = validate
|
|
417
|
+
.string()
|
|
418
|
+
.min(3)
|
|
419
|
+
.max(20)
|
|
420
|
+
.regex(/^[a-z0-9_]+$/)
|
|
421
|
+
.build();
|
|
422
|
+
const isRole = validate.string().enum('admin', 'user', 'guest').required().build();
|
|
423
|
+
const isAge = validate.number().integer().min(18).max(120).required().build();
|
|
424
|
+
const isId = validate.objectId().required().build();
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
Each chain ends with `.build()` which returns a plain `(input: any) => boolean` function — build once, reuse anywhere.
|
|
428
|
+
|
|
429
|
+
---
|
|
430
|
+
|
|
431
|
+
### Available rules
|
|
432
|
+
|
|
433
|
+
**Type**
|
|
434
|
+
|
|
435
|
+
| Method | Description |
|
|
436
|
+
| ----------- | -------------------------- |
|
|
437
|
+
| `string()` | Must be a string |
|
|
438
|
+
| `number()` | Must be a number (not NaN) |
|
|
439
|
+
| `boolean()` | Must be a boolean |
|
|
440
|
+
| `array()` | Must be an array |
|
|
441
|
+
| `object()` | Must be a plain object |
|
|
442
|
+
|
|
443
|
+
**String**
|
|
444
|
+
|
|
445
|
+
| Method | Description |
|
|
446
|
+
| ---------------- | ----------------------------------------- |
|
|
447
|
+
| `min(n)` | Min length (string) or min value (number) |
|
|
448
|
+
| `max(n)` | Max length (string) or max value (number) |
|
|
449
|
+
| `length(n)` | Exact length |
|
|
450
|
+
| `regex(pattern)` | Must match pattern |
|
|
451
|
+
| `email()` | Valid email format |
|
|
452
|
+
| `uuid()` | Valid UUID v4 |
|
|
453
|
+
| `objectId()` | Valid MongoDB ObjectId (24-char hex) |
|
|
454
|
+
| `url()` | Valid URL |
|
|
455
|
+
| `trim()` | Must have no leading/trailing whitespace |
|
|
456
|
+
|
|
457
|
+
**Number**
|
|
458
|
+
|
|
459
|
+
| Method | Description |
|
|
460
|
+
| ------------ | ------------------ |
|
|
461
|
+
| `integer()` | Must be an integer |
|
|
462
|
+
| `positive()` | Must be > 0 |
|
|
463
|
+
| `negative()` | Must be < 0 |
|
|
464
|
+
|
|
465
|
+
**Generic**
|
|
466
|
+
|
|
467
|
+
| Method | Description |
|
|
468
|
+
| ----------------- | --------------------------------------------- |
|
|
469
|
+
| `enum(...values)` | Must be one of the provided values |
|
|
470
|
+
| `custom(fn)` | Any custom `(value) => boolean` function |
|
|
471
|
+
| `required()` | Reject `null`, `undefined`, and `''` |
|
|
472
|
+
| `optional()` | Allow `null`, `undefined`, and `''` (default) |
|
|
473
|
+
|
|
474
|
+
**Object**
|
|
475
|
+
|
|
476
|
+
| Method | Description |
|
|
477
|
+
| --------------- | -------------------------------------------- |
|
|
478
|
+
| `shape(schema)` | Validate each key against a nested validator |
|
|
479
|
+
|
|
480
|
+
**Array**
|
|
481
|
+
|
|
482
|
+
| Method | Description |
|
|
483
|
+
| ------------- | ------------------------------------- |
|
|
484
|
+
| `items(fn)` | Every element must pass the validator |
|
|
485
|
+
| `minItems(n)` | Minimum array length |
|
|
486
|
+
| `maxItems(n)` | Maximum array length |
|
|
487
|
+
| `unique()` | No duplicate values |
|
|
488
|
+
|
|
489
|
+
---
|
|
490
|
+
|
|
491
|
+
### Object shape
|
|
492
|
+
|
|
493
|
+
```ts
|
|
494
|
+
const isAddress = validate
|
|
495
|
+
.object()
|
|
496
|
+
.shape({
|
|
497
|
+
street: validate.string().min(2).required().build(),
|
|
498
|
+
city: validate.string().min(2).required().build(),
|
|
499
|
+
country: validate.string().length(2).required().build(),
|
|
500
|
+
zip: validate
|
|
501
|
+
.string()
|
|
502
|
+
.regex(/^\d{4,10}$/)
|
|
503
|
+
.build(),
|
|
504
|
+
})
|
|
505
|
+
.required()
|
|
506
|
+
.build();
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
Shapes can be nested to any depth:
|
|
510
|
+
|
|
511
|
+
```ts
|
|
512
|
+
const isUser = validate
|
|
513
|
+
.object()
|
|
514
|
+
.shape({
|
|
515
|
+
id: validate.objectId().required().build(),
|
|
516
|
+
email: validate.string().email().required().build(),
|
|
517
|
+
role: validate.string().enum('admin', 'user').required().build(),
|
|
518
|
+
address: validate
|
|
519
|
+
.object()
|
|
520
|
+
.shape({
|
|
521
|
+
city: validate.string().required().build(),
|
|
522
|
+
country: validate.string().length(2).required().build(),
|
|
523
|
+
})
|
|
524
|
+
.build(),
|
|
525
|
+
})
|
|
526
|
+
.required()
|
|
527
|
+
.build();
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
---
|
|
531
|
+
|
|
532
|
+
### Array items
|
|
533
|
+
|
|
534
|
+
```ts
|
|
535
|
+
const isTagList = validate
|
|
536
|
+
.array()
|
|
537
|
+
.items(validate.string().min(1).max(30).required().build())
|
|
538
|
+
.minItems(1)
|
|
539
|
+
.maxItems(10)
|
|
540
|
+
.unique()
|
|
541
|
+
.required()
|
|
542
|
+
.build();
|
|
543
|
+
|
|
544
|
+
const isOrderItems = validate
|
|
545
|
+
.array()
|
|
546
|
+
.items(
|
|
547
|
+
validate
|
|
548
|
+
.object()
|
|
549
|
+
.shape({
|
|
550
|
+
productId: validate.objectId().required().build(),
|
|
551
|
+
quantity: validate.number().integer().positive().required().build(),
|
|
552
|
+
price: validate.number().positive().required().build(),
|
|
553
|
+
})
|
|
554
|
+
.required()
|
|
555
|
+
.build(),
|
|
556
|
+
)
|
|
557
|
+
.minItems(1)
|
|
558
|
+
.required()
|
|
559
|
+
.build();
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
---
|
|
563
|
+
|
|
564
|
+
### Use with Alado `@validateProperty`
|
|
565
|
+
|
|
566
|
+
```ts
|
|
567
|
+
import { documentProperty, validateProperty, validate } from 'alado';
|
|
568
|
+
|
|
569
|
+
export class CredentialsDto {
|
|
570
|
+
@validateProperty({
|
|
571
|
+
required: true,
|
|
572
|
+
handler: validate.string().email().required().build(),
|
|
573
|
+
error: { statusCode: 400, message: 'Invalid email' },
|
|
574
|
+
})
|
|
575
|
+
@documentProperty({
|
|
576
|
+
schema: { type: 'string', format: 'email' },
|
|
577
|
+
example: 'user@example.com',
|
|
578
|
+
})
|
|
579
|
+
email: string = '';
|
|
580
|
+
|
|
581
|
+
@validateProperty({
|
|
582
|
+
required: true,
|
|
583
|
+
handler: validate.string().min(8).required().build(),
|
|
584
|
+
error: { statusCode: 400, message: 'Password must be at least 8 characters' },
|
|
585
|
+
})
|
|
586
|
+
@documentProperty({
|
|
587
|
+
schema: { type: 'string', minLength: 8 },
|
|
588
|
+
example: 'securePassword',
|
|
589
|
+
})
|
|
590
|
+
password: string = '';
|
|
591
|
+
}
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
---
|
|
595
|
+
|
|
403
596
|
### `documentProperty`
|
|
404
597
|
|
|
405
598
|
Adds OpenAPI/Swagger metadata to a property.
|