UNPKG

@thalorlabs/errors

Version:

Enhanced exception handling system for TypeScript applications with comprehensive error classes and debugging capabilities

531 lines (411 loc) 11.9 kB
# @thalorlabs/errors A comprehensive, production-ready exception handling system for TypeScript applications with enhanced features for debugging, monitoring, and API responses. ## Installation ```bash npm install @thalorlabs/errors ``` ## Features - **Base CustomError class** with enhanced context and debugging capabilities - **HTTP-specific error classes** for common API scenarios - **Specialized error classes** for validation, rate limiting, and database operations - **Comprehensive test coverage** (100% for all exception classes) - **TypeScript support** with full type safety - **Structured error responses** for consistent API responses - **Request tracking** with requestId and context support - **Timestamp tracking** for debugging and monitoring ## Quick Start ```typescript import { // Base error class CustomError, // 4xx Client Errors BadRequestError, UnauthorizedError, ForbiddenError, NotFoundError, ConflictError, UnprocessableEntityError, TooManyRequestsError, // 5xx Server Errors InternalServerError, NotImplementedError, ServiceUnavailableError, GatewayTimeoutError, // Specialized error classes ValidationError, // Alias for UnprocessableEntityError (422) RateLimitError, DatabaseError, AuthenticationError, // Legacy alias for UnauthorizedError // Optional/Nice-to-have errors AuthenticationTimeoutError, ThirdPartyServiceError, PaymentRequiredError, QuotaExceededError, } from '@thalorlabs/errors'; // Basic usage throw new BadRequestError('Invalid input data'); throw new UnauthorizedError('Invalid API key'); throw new ForbiddenError('Insufficient permissions'); // With context and request tracking throw new ValidationError( 'Validation failed', [{ field: 'email', message: 'Invalid email format' }], 'req-123', { userId: 'user-456' } ); // Rate limiting with retry information throw new TooManyRequestsError('Rate limit exceeded', 60, 100, 0, new Date()); // Database errors with detailed context throw new DatabaseError( 'Connection failed', 'MongoDB', 'find', DatabaseErrorType.CONNECTION_FAILED, originalError, 'req-123', { collection: 'users' } ); ``` ## Error Classes ### CustomError (Base Class) The foundation for all custom errors with enhanced debugging capabilities. ```typescript class CustomError extends Error { statusCode: number; status: 'success' | 'failure'; timestamp: Date; requestId?: string; context?: Record<string, any>; } ``` **Methods:** - `getStatusText()`: Returns human-readable status text - `toJSON()`: Complete JSON representation for logging - `getErrorResponse()`: API-friendly response format ### HTTP Error Classes #### 4xx Client Errors ##### BadRequestError (400) ```typescript throw new BadRequestError('Malformed input data', 'invalid-json', 'req-123'); ``` ##### UnauthorizedError (401) ```typescript throw new UnauthorizedError('Invalid API key', 'expired-token', 'req-123'); ``` ##### ForbiddenError (403) ```typescript throw new ForbiddenError( 'Insufficient permissions', 'admin-required', 'req-123' ); ``` ##### NotFoundError (404) ```typescript throw new NotFoundError('User not found', 'user-id-123', 'req-123'); ``` ##### ConflictError (409) ```typescript throw new ConflictError( 'Resource already exists', 'duplicate-email', 'req-123' ); ``` ##### UnprocessableEntityError (422) ```typescript throw new UnprocessableEntityError( 'Semantically invalid request', 'validation-failed', 'req-123' ); ``` ##### TooManyRequestsError (429) ```typescript throw new TooManyRequestsError( 'Rate limit exceeded', 60, // retryAfter seconds 100, // limit 0, // remaining new Date('2024-01-01T13:00:00Z'), // resetTime 'req-123' ); ``` #### 5xx Server Errors ##### InternalServerError (500) ```typescript throw new InternalServerError( 'Unexpected server error', 'database-connection-failed', 'req-123' ); ``` ##### NotImplementedError (501) ```typescript throw new NotImplementedError( 'Endpoint not yet implemented', 'v2-api-missing', 'req-123' ); ``` ##### ServiceUnavailableError (503) ```typescript throw new ServiceUnavailableError( 'External service down', 'weather-api', 'req-123' ); ``` ##### GatewayTimeoutError (504) ```typescript throw new GatewayTimeoutError( 'Upstream service timeout', 'database-query-timeout', 'req-123' ); ``` ### Specialized Error Classes #### ValidationError (422) For input validation errors with detailed field-level information. ```typescript const validationError = new ValidationError( 'Validation failed', [ { field: 'email', message: 'Invalid email format', value: 'invalid-email' }, { field: 'password', message: 'Password too short', value: '123' }, ], 'req-123' ); // Add more validation errors dynamically validationError.addValidationError('age', 'Must be 18 or older', 16, 'MIN_AGE'); throw validationError; ``` **Response Format:** ```json { "status": "failure", "error": "Validation failed", "timestamp": "2024-01-01T12:00:00.000Z", "requestId": "req-123", "errors": [ { "field": "email", "message": "Invalid email format", "value": "invalid-email" } ] } ``` #### RateLimitError (429) For rate limiting scenarios with retry information. ```typescript throw new RateLimitError( 'Rate limit exceeded', 60, // retryAfter seconds 100, // limit 0, // remaining new Date('2024-01-01T13:00:00Z'), // resetTime 'req-123' ); ``` **Response Format:** ```json { "status": "failure", "error": "Rate limit exceeded", "timestamp": "2024-01-01T12:00:00.000Z", "requestId": "req-123", "retryAfter": 60, "limit": 100, "remaining": 0, "resetTime": "2024-01-01T13:00:00.000Z" } ``` #### DatabaseError (500) For database-related errors with detailed context. ```typescript throw new DatabaseError( 'Connection timeout', 'MongoDB', 'find', DatabaseErrorType.CONNECTION_FAILED, originalError, 'req-123', { collection: 'users', query: { _id: '123' } } ); ``` **DatabaseErrorType enum:** - `CONNECTION_FAILED` - `QUERY_FAILED` - `TRANSACTION_FAILED` - `CONSTRAINT_VIOLATION` - `TIMEOUT` - `DEADLOCK` - `UNKNOWN` ### Optional/Nice-to-have Error Classes #### AuthenticationTimeoutError (440) For authentication timeout scenarios (custom status code). ```typescript throw new AuthenticationTimeoutError( 'Login session expired', 'jwt-expired', 'req-123' ); ``` #### ThirdPartyServiceError (502/503) For external service failures with detailed context. ```typescript throw new ThirdPartyServiceError( 'Payment gateway failed', 'stripe-api', originalError, 'req-123', { endpoint: '/process-payment' } ); ``` #### PaymentRequiredError (402) For payment/subscription required scenarios. ```typescript throw new PaymentRequiredError( 'Premium feature requires payment', 'subscription-required', 'req-123' ); ``` #### QuotaExceededError (429) For quota/usage limit scenarios with detailed information. ```typescript throw new QuotaExceededError( 'Monthly API quota exceeded', 'api-calls', 1000, // current usage 1000, // max quota new Date('2024-02-01T00:00:00Z'), // reset time 'req-123' ); ``` ## Integration with Middleware The exception system integrates seamlessly with your existing `TryCatchMiddleware`: ```typescript // In TryCatchMiddleware.ts if (error instanceof CustomError) { res.status(error.statusCode).json(error.getErrorResponse()); } ``` ## Best Practices ### 1. Use Specific Error Types ```typescript // Good throw new ValidationError('Invalid input', validationErrors); // Avoid throw new CustomError(422, 'Invalid input'); ``` ### 2. Include Context for Debugging ```typescript throw new DatabaseError( 'Query failed', 'PostgreSQL', 'SELECT', DatabaseErrorType.QUERY_FAILED, originalError, requestId, { table: 'users', query: 'SELECT * FROM users WHERE id = ?' } ); ``` ### 3. Use Request IDs for Tracing ```typescript // Extract request ID from request headers or generate one const requestId = req.headers['x-request-id'] || generateRequestId(); throw new BadRequestError('Invalid data', 'field-name', requestId); ``` ### 4. Structured Error Responses ```typescript // For API responses const response = error.getErrorResponse(); // For logging const logData = error.toJSON(); logger.error('Error occurred', logData); ``` ## Testing All error classes have comprehensive test coverage: ```bash npm test npm run test:coverage ``` **Test Coverage:** - ✅ 100% statement coverage - ✅ 97.36% branch coverage - ✅ 100% function coverage - ✅ 100% line coverage ## Migration from Basic Errors If you're upgrading from the basic error system: ```typescript // Before throw new BadRequestError('Invalid input', 'field-name'); // After (backward compatible) throw new BadRequestError('Invalid input', 'field-name'); // Enhanced (recommended) throw new BadRequestError('Invalid input', 'field-name', requestId, { field: 'email', }); ``` ## Type Safety The system is fully typed with TypeScript: ```typescript // All error classes extend CustomError const error: CustomError = new ValidationError('Test'); // Type-safe error handling if (error instanceof ValidationError) { // TypeScript knows this is a ValidationError console.log(error.validationErrors); } ``` ## Performance Considerations - **Minimal overhead**: Base error class adds only essential properties - **Optional context**: Context and requestId are optional to avoid unnecessary memory usage - **Efficient serialization**: `toJSON()` and `getErrorResponse()` methods for different use cases - **Stack trace preservation**: Full Error inheritance maintains stack traces ## Future Enhancements The system is designed to be extensible: - Add new specialized error types as needed - Extend context with additional metadata - Add error correlation IDs for distributed systems - Implement error aggregation and reporting - Add error recovery suggestions ## Project Structure ``` src/ ├── index.ts # Main exports ├── CustomError.ts # Base error class ├── AuthenticationError.ts # Legacy alias for UnauthorizedError ├── AuthenticationTimeoutError.ts ├── ConflictError.ts # 4xx Client Errors ├── ForbiddenError.ts ├── NotFoundError.ts ├── TooManyRequestsError.ts ├── UnauthorizedError.ts ├── UnprocessableEntityError.ts ├── GatewayTimeoutError.ts # 5xx Server Errors ├── InternalServerError.ts ├── NotImplementedError.ts ├── ServiceUnavailableError.ts ├── DatabaseError.ts # Specialized error classes ├── RateLimitError.ts ├── ValidationError.ts ├── ThirdPartyServiceError.ts # Optional error classes ├── PaymentRequiredError.ts ├── QuotaExceededError.ts └── tests/ # Comprehensive test suite ├── CustomError.test.ts ├── AuthenticationError.test.ts └── ... (all error classes) ``` ## TypeScript Support This package includes full TypeScript support with: - Complete type definitions - IntelliSense support - Compile-time type checking - Type-safe error handling ## License ISC This enhanced exception system provides a solid foundation for robust error handling in production TypeScript applications.