Data Transfer Objects (DTOs)
September 21, 2025 · View on GitHub
- Purpose
- Directory Structure
- Naming Conventions
- Request vs Response DTOs
- Validation Guidelines
- Documentation Standards
- Best Practices
Purpose
DTOs define the structure and validation rules for data exchanged between client and server. They serve as the API contract, ensuring type safety and proper input validation while maintaining separation from business logic.
Directory Structure
DTOs mirror the controller directory structure to maintain consistency and discoverability:
src/dto/
├── {domain}/
│ ├── {action}/
│ │ ├── {Action}Request.ts
│ │ └── {Action}Response.ts
│ ├── {SharedType}Response.ts
│ └── {Domain}Params.ts
Example: auth/login/LoginRequest.ts corresponds to controllers/auth/login/AuthLoginPostController.ts
Naming Conventions
- Request Classes:
{Action}Request(e.g.,LoginRequest,CreateProjectRequest) - Response Interfaces:
{Action}Responseor{Entity}Response(e.g.,AuthResponse,ProjectResponse) - Parameter Classes:
{Entity}Params(e.g.,ProjectParams) - List Responses:
{Entity}ListResponse(e.g.,ProjectListResponse)
Request vs Response DTOs
Request DTOs
- Use classes with
class-validatordecorators - Include validation rules and error messages
- Handle input data from client
Response DTOs
- Use interfaces for type definitions
- Define expected response structure
- No validation needed (output data)
Validation Guidelines
- Use class-validator decorators on request classes
- Provide clear error messages for each validation rule
- Apply appropriate constraints (length, format, required fields)
- Use conditional validation (
ValidateIf) for optional fields - Validate path parameters with dedicated parameter classes
Documentation Standards
- Add JSDoc to all DTOs with class/interface descriptions
- Document each field with purpose and examples when helpful
- Use
@exampletags for realistic sample values - Integrate with TSOA for automatic OpenAPI documentation
Best Practices
- Mirror Controller Structure: Keep DTOs organized like controllers for easy navigation
- Single Responsibility: Each DTO should serve one specific endpoint or shared purpose
- Type Safety First: Leverage TypeScript for compile-time guarantees
- Validate at Boundaries: All incoming data must be validated
- Keep It Simple: DTOs should only handle data structure and validation
- Consistent Patterns: Follow established naming and organizational conventions
- Shared Types: Create shared response DTOs when multiple endpoints return similar data