@thalorlabs/errors
v1.0.0
Published
Enhanced exception handling system for TypeScript applications with comprehensive error classes and debugging capabilities
Maintainers
Readme
@thalorlabs/errors
A comprehensive, production-ready exception handling system for TypeScript applications with enhanced features for debugging, monitoring, and API responses.
Installation
npm install @thalorlabs/errorsFeatures
- 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
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.
class CustomError extends Error {
statusCode: number;
status: 'success' | 'failure';
timestamp: Date;
requestId?: string;
context?: Record<string, any>;
}Methods:
getStatusText(): Returns human-readable status texttoJSON(): Complete JSON representation for logginggetErrorResponse(): API-friendly response format
HTTP Error Classes
4xx Client Errors
BadRequestError (400)
throw new BadRequestError('Malformed input data', 'invalid-json', 'req-123');UnauthorizedError (401)
throw new UnauthorizedError('Invalid API key', 'expired-token', 'req-123');ForbiddenError (403)
throw new ForbiddenError(
'Insufficient permissions',
'admin-required',
'req-123'
);NotFoundError (404)
throw new NotFoundError('User not found', 'user-id-123', 'req-123');ConflictError (409)
throw new ConflictError(
'Resource already exists',
'duplicate-email',
'req-123'
);UnprocessableEntityError (422)
throw new UnprocessableEntityError(
'Semantically invalid request',
'validation-failed',
'req-123'
);TooManyRequestsError (429)
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)
throw new InternalServerError(
'Unexpected server error',
'database-connection-failed',
'req-123'
);NotImplementedError (501)
throw new NotImplementedError(
'Endpoint not yet implemented',
'v2-api-missing',
'req-123'
);ServiceUnavailableError (503)
throw new ServiceUnavailableError(
'External service down',
'weather-api',
'req-123'
);GatewayTimeoutError (504)
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.
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:
{
"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.
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:
{
"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.
throw new DatabaseError(
'Connection timeout',
'MongoDB',
'find',
DatabaseErrorType.CONNECTION_FAILED,
originalError,
'req-123',
{ collection: 'users', query: { _id: '123' } }
);DatabaseErrorType enum:
CONNECTION_FAILEDQUERY_FAILEDTRANSACTION_FAILEDCONSTRAINT_VIOLATIONTIMEOUTDEADLOCKUNKNOWN
Optional/Nice-to-have Error Classes
AuthenticationTimeoutError (440)
For authentication timeout scenarios (custom status code).
throw new AuthenticationTimeoutError(
'Login session expired',
'jwt-expired',
'req-123'
);ThirdPartyServiceError (502/503)
For external service failures with detailed context.
throw new ThirdPartyServiceError(
'Payment gateway failed',
'stripe-api',
originalError,
'req-123',
{ endpoint: '/process-payment' }
);PaymentRequiredError (402)
For payment/subscription required scenarios.
throw new PaymentRequiredError(
'Premium feature requires payment',
'subscription-required',
'req-123'
);QuotaExceededError (429)
For quota/usage limit scenarios with detailed information.
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:
// In TryCatchMiddleware.ts
if (error instanceof CustomError) {
res.status(error.statusCode).json(error.getErrorResponse());
}Best Practices
1. Use Specific Error Types
// Good
throw new ValidationError('Invalid input', validationErrors);
// Avoid
throw new CustomError(422, 'Invalid input');2. Include Context for Debugging
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
// 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
// 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:
npm test
npm run test:coverageTest 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:
// 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:
// 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()andgetErrorResponse()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.
