@thalorlabs/errors
Version:
Enhanced exception handling system for TypeScript applications with comprehensive error classes and debugging capabilities
531 lines (411 loc) • 11.9 kB
Markdown
# @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.