Global DTOs
Location: src/common/dto/ (new) or src/modules/global-dto/ (legacy)
Rule: Always use field decorators for new DTOs — never raw @ApiProperty + validators.
Import
import {
RequiredStringField, OptionalStringField,
RequiredNumberField, OptionalNumberField,
RequiredFileField, OptionalFileField,
OptionalBooleanField, OptionalJsonField,
RequiredArrayOfNumbersField,
} from 'src/common/dto'; // or src/modules/global-dto
import { GlobalPaginationDto, checkPagination } from 'src/common/dto';
import { GlobalSearchDto } from 'src/common/dto/search.dto';
import { GlobalStringIdentifierDto } from 'src/common/dto/identifier.dto';
Field Decorators
| Type | Required | Optional |
|---|---|---|
| String | RequiredStringField(desc?) |
OptionalStringField |
| Number | RequiredNumberField(ex?) |
OptionalNumberField |
| Decimal | RequiredDecimalField |
OptionalDecimalField |
| Boolean | RequiredBooleanField |
OptionalBooleanField |
| Date | RequiredDateField |
OptionalDateField |
| File | RequiredFileField(name) |
OptionalFileField |
| Enum | RequiredEnumField(E) |
OptionalEnumField |
| JSON | RequiredJsonField |
OptionalJsonField |
| UUID | RequiredUuidField |
OptionalUuidField |
| Email/URL/Phone/Slug/Hex | RequiredEmailField etc. |
Optional* variants |
| Number array | RequiredArrayOfNumbersField |
OptionalArrayOfStringsField etc. |
Auto-handles: Swagger, string→number transform, "true"/"1" boolean coercion, comma-separated arrays.
Create DTO Example
export class CreateCategoryDto {
@RequiredStringField('Name in Arabic') name_ar: string;
@RequiredStringField('Name in English') name_en: string;
@RequiredStringField('URL slug') slug: string;
@RequiredFileField('image') imageUrl: any;
@OptionalFileField('cover') coverUrl?: any;
@RequiredNumberField() typeId: number;
@OptionalBooleanField() isFiltered?: boolean;
@OptionalJsonField({ layout: 'grid' }) settings?: any;
}
Update DTO
All create fields as optional versions. Files: OptionalFileField.
List/Filter DTO
export class GetAllCategoriesDto {
@OptionalNumberField() typeId?: number;
@OptionalBooleanField() isFiltered?: boolean;
}
Pagination
// Controller — multiple @Query() DTOs merge from same query string
@Get('get-all')
async getAll(
@Query() pagination: GlobalPaginationDto, // page, pageItemsCount
@Query() search: GlobalSearchDto, // search
@Query() dto: GetAllDto,
) { ... }
// Service
...checkPagination(pagination) // { take, skip } or null = return all
Identifier DTOs
@Get('get-category')
async getOne(@Query() id: GlobalStringIdentifierDto, @Query() slug: GetOneDto) { ... }
// id.id (UUID string) OR slug.slug
Barrel Export
// dto/index.ts
export * from './create-feature.dto';
export * from './update-feature.dto';
export * from './get-all-feature.dto';
Full catalog: legacy DECORATORS_GUIDE.md in global-dto folder.