Overview
Data Transfer Objects (DTOs) define the input and output contracts for application use cases. They provide a clear boundary between the external API layer and internal domain logic.CreateOrderDto
The input DTO for creating a new order. Contains all required information for customer and order creation.Interface Definition
src/application/dtos/OrderDto.ts
Fields
Customer’s full name. Must be sanitized and validated before passing to the use case.Example:
"Juan Pérez"Customer’s email address. Will be validated by the
Email value object.Example: "[email protected]"Validation: Must be a valid email formatCustomer’s phone number. Will be validated by the
Phone value object.Example: "+1234567890"Validation: Must be a valid phone formatThe unique identifier of the subscription plan being purchased.Example:
"plan_basic"Validation: Must match an existing plan in PLANS constantNumber of concurrent devices allowed in the subscription.Example:
2Validation: Must match the selected plan’s device limit (1-10)Duration of the subscription in months.Example:
6Validation: Must be one of: 1, 2, 3, 6, 12Total payment amount in the currency unit (e.g., dollars).Example:
29.99Validation: Must match the expected price for the selected plan and durationThe payment processor used for this transaction.Type:
"stripe" | "paypal"Example: "stripe"The payment processor’s transaction or receipt ID for verification.Example:
"pi_3JX7g82eZvKYlo2C0123abcd" (Stripe payment intent ID)Example: "PAYID-M123456-78901234A" (PayPal transaction ID)Usage Example
Validation in API Routes
src/app/api/orders/route.ts
OrderResponseDto
The output DTO returned after successfully creating an order. Contains the complete order details including generated IDs and calculated dates.Interface Definition
src/application/dtos/OrderDto.ts
Fields
The unique identifier for the created order.Example:
"507f1f77bcf86cd799439011"The unique identifier for the created or existing customer.Example:
"507f191e810c19729de860ea"The subscription plan identifier (echoed from input).Example:
"plan_basic"Number of concurrent devices (echoed from input).Example:
2Subscription duration in months (echoed from input).Example:
6Total payment amount (echoed from input).Example:
29.99Payment processor used (echoed from input).Type:
"stripe" | "paypal"Example: "stripe"Payment processor transaction ID (echoed from input).Example:
"pi_3JX7g82eZvKYlo2C0123abcd"The order status. For successful orders, this is always
"completed".Type: "pending" | "completed" | "failed"Example: "completed"ISO 8601 timestamp when the subscription becomes active. Typically set to the order creation time.Format: ISO 8601 stringExample:
"2024-03-15T10:30:00.000Z"ISO 8601 timestamp when the subscription expires. Calculated by adding
months to the activation date.Format: ISO 8601 stringExample: "2024-09-15T10:30:00.000Z" (6 months after activation)Response Example
TypeScript Usage
API Route Response
src/app/api/orders/route.ts
PaymentMethod Type
ThePaymentMethod type is defined in the domain layer and used across DTOs.
src/domain/entities/Order.ts
Supported Payment Methods
Stripe payment processor integration.Receipt ID format: Stripe Payment Intent ID (e.g.,
pi_xxx)PayPal payment processor integration.Receipt ID format: PayPal Transaction ID (e.g.,
PAYID-xxx)Best Practices
Input ValidationAlways sanitize and validate DTO fields before passing them to use cases:
- Use sanitization utilities for strings, emails, phones, numbers, and enums
- Validate business rules (plan exists, amount matches price, etc.)
- Check for honeypot fields to prevent bot submissions
- Apply rate limiting to prevent abuse
Type SafetyDTOs provide compile-time type safety:
- Use TypeScript interfaces to define clear contracts
- Export types from a central location (
@/application/dtos) - Leverage type inference to catch errors early
- Use discriminated unions for polymorphic DTOs
Separation of ConcernsDTOs serve as the boundary between layers:
- API Layer: Receives HTTP requests, validates input, creates DTOs
- Application Layer: Consumes DTOs, orchestrates domain logic, returns DTOs
- Domain Layer: Works with rich domain entities, not DTOs
- Infrastructure Layer: Persists domain entities, not DTOs
