validation-patterns.md

Comprehensive validation patterns for micro-block commands with detailed error feedback

validation-patterns.mdv1.0.09.1 KB
validation-patterns.md(markdown)
1# Validation Patterns for Micro-Block Architecture
2
3## Overview
4
5This document defines validation patterns for micro-block commands that provide detailed error feedback instead of simple boolean validation.
6
7## Core Validation Principles
8
91. **Error-Throwing Validation**: Commands throw detailed errors instead of returning boolean validation results
102. **Specific Error Messages**: Each validation error provides clear, actionable feedback
113. **Field-Level Validation**: Errors identify the specific field and path that failed validation
124. **Validation Error Metadata**: Errors include structured metadata for automated processing
13
14## Validation Interface
15
16### Base Command Validation
17
18```typescript
19export interface BaseCommand {
20  /** 
21   * Validate that the command can execute with current configuration.
22   * Throws detailed validation errors instead of returning boolean.
23   * Use raiseError() method to throw errors with validation details.
24   */
25  validate(): void;
26  execute(): Promise<any>;
27  getMetadata(): CommandMetadata;
28}
29```
30
31## Error Handling Pattern
32
33### BaseError with Validation Support
34
35```typescript
36export class BaseError extends Error {
37  public readonly timestamp: Date;
38  public readonly code?: string;
39  public readonly details?: Record<string, any>;
40  
41  // Validation error properties
42  public invalidInput: boolean = false;
43  public invalidInputName: string = '';
44  public invalidInputPath: string = '';
45
46  constructor(message: string, code?: string, details?: Record<string, any>) {
47    super(message);
48    this.name = this.constructor.name;
49    this.timestamp = new Date();
50    this.code = code;
51    this.details = details;
52    
53    Object.setPrototypeOf(this, new.target.prototype);
54    if (Error.captureStackTrace) {
55      Error.captureStackTrace(this, this.constructor);
56    }
57  }
58  
59  /**
60   * Mark this error as a validation error with specific input details
61   */
62  setValidationError(inputName: string, inputPath: string): this {
63    this.invalidInput = true;
64    this.invalidInputName = inputName;
65    this.invalidInputPath = inputPath;
66    return this;
67  }
68}
69```
70
71### Command-Specific Error Classes
72
73```typescript
74export class CreateUserError extends BaseError {
75  constructor(message: string, code?: string, details?: Record<string, any>) {
76    super(message, code, details);
77    Object.setPrototypeOf(this, CreateUserError.prototype);
78    this.name = "CreateUserError";
79  }
80}
81```
82
83## Validation Implementation Patterns
84
85### Input Validation Pattern
86
87```typescript
88validate(): void {
89  // Check for null/undefined input
90  if (!this.input) {
91    const error = new CreateUserError(
92      'Command input cannot be null or undefined',
93      'VALIDATION_ERROR'
94    );
95    error.setValidationError('input', 'input');
96    throw this.raiseError(error);
97  }
98  
99  // Check required fields
100  if (!this.input.email) {
101    const error = new CreateUserError(
102      'Email field is required and cannot be empty',
103      'VALIDATION_ERROR'
104    );
105    error.setValidationError('email', 'input.email');
106    throw this.raiseError(error);
107  }
108  
109  // Check field format
110  if (!this.isValidEmail(this.input.email)) {
111    const error = new CreateUserError(
112      'Email must be a valid email address format',
113      'VALIDATION_ERROR'
114    );
115    error.setValidationError('email', 'input.email');
116    throw this.raiseError(error);
117  }
118  
119  // Check field length
120  if (this.input.password && this.input.password.length < 8) {
121    const error = new CreateUserError(
122      'Password must be at least 8 characters long',
123      'VALIDATION_ERROR'
124    );
125    error.setValidationError('password', 'input.password');
126    throw this.raiseError(error);
127  }
128}
129```
130
131### Service Dependency Validation
132
133```typescript
134validate(): void {
135  // Validate service dependencies
136  if (!this.databaseService) {
137    const error = new CreateUserError(
138      'IDatabaseService is required for user creation',
139      'MISSING_SERVICE'
140    );
141    error.setValidationError('databaseService', 'services.IDatabaseService');
142    throw this.raiseError(error);
143  }
144  
145  // Validate service health
146  if (!this.databaseService.isHealthy()) {
147    const error = new CreateUserError(
148      'Database service is not healthy and cannot process requests',
149      'SERVICE_UNHEALTHY'
150    );
151    error.setValidationError('databaseService', 'services.IDatabaseService');
152    throw this.raiseError(error);
153  }
154}
155```
156
157### Complex Object Validation
158
159```typescript
160validate(): void {
161  // Validate nested objects
162  if (this.input.profile) {
163    if (!this.input.profile.firstName) {
164      const error = new CreateUserError(
165        'Profile first name is required when profile is provided',
166        'VALIDATION_ERROR'
167      );
168      error.setValidationError('firstName', 'input.profile.firstName');
169      throw this.raiseError(error);
170    }
171    
172    if (!this.input.profile.lastName) {
173      const error = new CreateUserError(
174        'Profile last name is required when profile is provided',
175        'VALIDATION_ERROR'
176      );
177      error.setValidationError('lastName', 'input.profile.lastName');
178      throw this.raiseError(error);
179    }
180  }
181  
182  // Validate arrays
183  if (this.input.tags && this.input.tags.length === 0) {
184    const error = new CreateUserError(
185      'Tags array cannot be empty when provided',
186      'VALIDATION_ERROR'
187    );
188    error.setValidationError('tags', 'input.tags');
189    throw this.raiseError(error);
190  }
191}
192```
193
194## Validation Helper Methods
195
196### Command Base Class Helpers
197
198```typescript
199export abstract class BaseCommand {
200  protected raiseError(error: BaseError): BaseError {
201    this.logger?.error(`Validation failed: ${error.message}`, {
202      command: this.getMetadata().name,
203      errorCode: error.code,
204      invalidInput: error.invalidInput,
205      invalidInputName: error.invalidInputName,
206      invalidInputPath: error.invalidInputPath
207    });
208    return error;
209  }
210  
211  protected isValidEmail(email: string): boolean {
212    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
213    return emailRegex.test(email);
214  }
215  
216  protected isValidUrl(url: string): boolean {
217    try {
218      new URL(url);
219      return true;
220    } catch {
221      return false;
222    }
223  }
224}
225```
226
227## Error Code Standards
228
229### Validation Error Codes
230
231- `VALIDATION_ERROR` - General input validation failure
232- `MISSING_SERVICE` - Required service dependency not provided
233- `SERVICE_UNHEALTHY` - Service dependency is not healthy
234- `INVALID_FORMAT` - Field format validation failure
235- `INVALID_LENGTH` - Field length validation failure
236- `INVALID_RANGE` - Field value outside acceptable range
237- `MISSING_REQUIRED_FIELD` - Required field not provided
238- `INVALID_COMBINATION` - Invalid combination of field values
239
240## Testing Validation
241
242### Validation Test Pattern
243
244```typescript
245describe('CreateUserCommand Validation', () => {
246  it('should throw validation error for missing email', async () => {
247    const command = new CreateUserCommand({
248      password: 'password123',
249      name: 'Test User'
250      // email missing
251    });
252    
253    expect(() => command.validate()).toThrow(CreateUserError);
254    
255    try {
256      command.validate();
257    } catch (error) {
258      expect(error.invalidInput).toBe(true);
259      expect(error.invalidInputName).toBe('email');
260      expect(error.invalidInputPath).toBe('input.email');
261      expect(error.code).toBe('VALIDATION_ERROR');
262    }
263  });
264  
265  it('should throw validation error for invalid email format', async () => {
266    const command = new CreateUserCommand({
267      email: 'invalid-email',
268      password: 'password123',
269      name: 'Test User'
270    });
271    
272    expect(() => command.validate()).toThrow(CreateUserError);
273    
274    try {
275      command.validate();
276    } catch (error) {
277      expect(error.invalidInput).toBe(true);
278      expect(error.invalidInputName).toBe('email');
279      expect(error.invalidInputPath).toBe('input.email');
280      expect(error.message).toContain('valid email address format');
281    }
282  });
283});
284```
285
286## Best Practices
287
288### Validation Design
2891. **Fail Fast**: Validate input before any business logic execution
2902. **Specific Messages**: Provide clear, actionable error messages
2913. **Field Identification**: Always identify the specific field that failed
2924. **Consistent Codes**: Use standardized error codes across commands
2935. **Logging Integration**: Log validation failures for debugging
294
295### Error Handling
2961. **Structured Errors**: Use BaseError with validation metadata
2972. **Error Propagation**: Let validation errors bubble up with full context
2983. **User-Friendly Messages**: Write error messages for end users, not developers
2994. **Localization Ready**: Design error messages for easy localization
3005. **Recovery Guidance**: When possible, suggest how to fix the validation error
301
302### Testing Strategy
3031. **Comprehensive Coverage**: Test all validation scenarios
3042. **Error Metadata**: Verify error metadata is set correctly
3053. **Edge Cases**: Test boundary conditions and edge cases
3064. **Service Dependencies**: Test validation with missing/unhealthy services
3075. **Integration Testing**: Test validation in full command execution flow
308
309This validation pattern ensures that commands provide rich, actionable feedback when validation fails, enabling better error handling and user experience in AI-collaborative development scenarios.

Metadata

Path
utaba/main/patterns/micro-block/validation-patterns.md
Namespace
utaba/main/patterns/micro-block
Author
utaba
Category
patterns
Technology
typescript
Contract Version
1.0.0
MIME Type
text/markdown
Published
18-Jul-2025
Last Updated
18-Jul-2025