@ticatec/node-exception
Version:
A comprehensive, production-ready error handling library for Node.js Express applications. Provides standardized error types, centralized error handling middleware, and consistent response formats with flexible content negotiation support.
385 lines (311 loc) β’ 10.8 kB
Markdown
# @ticatec/node-exception
[δΈζ](./README_CN.md) | English
[](https://www.npmjs.com/package/@ticatec/node-exception)
[](https://opensource.org/licenses/MIT)
[](https://nodejs.org)
[](https://www.typescriptlang.org/)
A comprehensive, production-ready error handling library for Node.js Express applications. This library provides standardized error types, centralized error handling middleware, and consistent response formats with flexible content negotiation support.
## π Features
- **π― Standardized Error Types**: Eight predefined error classes covering common HTTP scenarios
- **π§ Express Middleware**: Drop-in error handling middleware with zero configuration
- **π Consistent Response Format**: Uniform error responses with comprehensive request context
- **π¨ Content Negotiation**: Automatic response formatting (JSON, HTML, plain text)
- **π Development Support**: Stack trace inclusion in development environments
- **π TypeScript First**: Full TypeScript support with complete type definitions
- **π Logging Integration**: Built-in log4js integration for comprehensive error tracking
- **π IP Detection**: Automatic client and server IP address detection
- **β‘ Zero Dependencies**: Minimal runtime footprint with only essential dependencies
## π¦ Installation
```bash
npm install @ticatec/node-exception
```
### Peer Dependencies
```bash
npm install log4js
```
## π§ Quick Start
```javascript
import express from 'express';
import { handleError, AppError, UnauthenticatedError } from '@ticatec/node-exception';
const app = express();
// Your API routes
app.get('/api/protected', (req, res, next) => {
try {
if (!req.headers.authorization) {
throw new UnauthenticatedError();
}
res.json({ message: 'Success!' });
} catch (error) {
next(error);
}
});
// Error handling middleware (must be the last middleware)
app.use((err, req, res, next) => {
handleError(err, req, res);
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});
```
## π Error Types & Usage
### π AppError
Generic application error with custom error codes for business logic errors.
```javascript
// Database errors
throw new AppError(1001, "Database connection failed");
// Business logic errors
throw new AppError(2001, "Insufficient account balance");
// Validation errors
throw new AppError(3001, "User email already exists");
```
### π« UnauthenticatedError
For authentication failures (HTTP 401).
```javascript
// Missing authentication
if (!req.headers.authorization) {
throw new UnauthenticatedError();
}
// Invalid token
if (!isValidToken(token)) {
throw new UnauthenticatedError();
}
```
### π InsufficientPermissionError
For authorization failures (HTTP 403).
```javascript
// Role-based access control
if (!user.hasRole('admin')) {
throw new InsufficientPermissionError();
}
// Resource ownership
if (resource.ownerId !== user.id) {
throw new InsufficientPermissionError();
}
```
### β IllegalParameterError
For input validation failures (HTTP 400).
```javascript
// Email validation
if (!isValidEmail(email)) {
throw new IllegalParameterError("Invalid email format");
}
// Required field validation
if (!userId) {
throw new IllegalParameterError("User ID is required");
}
// Range validation
if (age < 0 || age > 150) {
throw new IllegalParameterError("Age must be between 0 and 150");
}
```
### π ActionNotFoundError
For non-existent routes or resources (HTTP 404).
```javascript
// Route not found
if (!routeExists(req.path)) {
throw new ActionNotFoundError();
}
// Resource not found
if (!user) {
throw new ActionNotFoundError();
}
```
### β±οΈ TimeoutError
For request timeouts (HTTP 408).
```javascript
// Database query timeout
if (Date.now() - startTime > TIMEOUT_LIMIT) {
throw new TimeoutError();
}
// API request timeout
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new TimeoutError()), 5000);
});
```
### π ProxyError
For proxy server issues (HTTP 502).
```javascript
// Proxy server failure
if (!proxyResponse.ok) {
throw new ProxyError();
}
// Gateway error
if (!upstreamServer.isHealthy()) {
throw new ProxyError();
}
```
### π« ServiceUnavailableError
For service unavailability (HTTP 503).
```javascript
// Service maintenance
if (isMaintenanceMode()) {
throw new ServiceUnavailableError();
}
// Server overload
if (activeConnections > maxConnections) {
throw new ServiceUnavailableError();
}
```
## π¨ Response Format & Content Negotiation
The library automatically handles content negotiation based on the `Accept` header:
### JSON Response (Default)
```json
{
"code": -1,
"client": "192.168.1.50",
"path": "/api/users",
"method": "GET",
"timestamp": 1699123456789,
"message": "Unauthenticated user is accessing the system.",
"stack": "Error: ... (development only)"
}
```
### HTML Response
When `Accept: text/html` is requested:
```html
<h1>Error</h1>
<p><strong>Code:</strong> -1</p>
<p><strong>Message:</strong> Unauthenticated user is accessing the system.</p>
<p><strong>Path:</strong> /api/users</p>
<p><strong>Method:</strong> GET</p>
<p><strong>Timestamp:</strong> 1699123456789</p>
```
### Plain Text Response
When `Accept: text/plain` is requested:
```
Error Code: -1
Message: Unauthenticated user is accessing the system.
Path: /api/users
Method: GET
Timestamp: 1699123456789
```
## π Response Fields
| Field | Type | Description |
|-------|------|-------------|
| `code` | number | Application-specific error code (-1 for generic errors) |
| `client` | string | Client IP address |
| `path` | string | Full request path (baseUrl + path) |
| `method` | string | HTTP method (GET, POST, PUT, DELETE, etc.) |
| `timestamp` | number | Unix timestamp in milliseconds |
| `message` | string \| null | Human-readable error message |
| `stack` | string | Stack trace (development environments only) |
## π Development vs Production
Stack traces are automatically included in development environments:
```javascript
// Enable development mode by setting request header
fetch('/api/users', {
headers: {
'env': 'development' // or 'dev'
}
});
```
## π¦ HTTP Status Code Mapping
| Error Type | HTTP Status | Use Case |
|------------|-------------|----------|
| `UnauthenticatedError` | 401 Unauthorized | Missing or invalid authentication |
| `InsufficientPermissionError` | 403 Forbidden | Insufficient permissions/authorization |
| `IllegalParameterError` | 400 Bad Request | Invalid input parameters or validation |
| `ActionNotFoundError` | 404 Not Found | Non-existent routes or resources |
| `TimeoutError` | 408 Request Timeout | Network requests or operations timeout |
| `AppError` | 500 Internal Server Error | Business logic or application errors |
| `ProxyError` | 502 Bad Gateway | Proxy server or gateway issues |
| `ServiceUnavailableError` | 503 Service Unavailable | Service maintenance or overload |
| Other errors | 500 Internal Server Error | Unexpected system errors |
## π‘ Advanced Usage
### Custom HTTP Container
Create custom HTTP adapters for different frameworks:
```javascript
import { setHttpContainer, HttpContainer } from '@ticatec/node-exception';
class CustomContainer implements HttpContainer {
getRemoteIp(req) {
return req.connection.remoteAddress;
}
getPath(req) {
return req.originalUrl;
}
sendError(req, res, statusCode, data) {
res.status(statusCode).json(data);
}
}
setHttpContainer(new CustomContainer());
```
### Error Code Conventions
Organize your error codes systematically:
```javascript
// Authentication errors: 1000-1999
const AUTH_ERRORS = {
INVALID_TOKEN: 1001,
EXPIRED_TOKEN: 1002,
MISSING_TOKEN: 1003
};
// Validation errors: 2000-2999
const VALIDATION_ERRORS = {
INVALID_EMAIL: 2001,
WEAK_PASSWORD: 2002,
REQUIRED_FIELD: 2003
};
// Business logic errors: 3000-3999
const BUSINESS_ERRORS = {
INSUFFICIENT_BALANCE: 3001,
DUPLICATE_EMAIL: 3002,
LIMIT_EXCEEDED: 3003
};
throw new AppError(AUTH_ERRORS.INVALID_TOKEN, "Authentication token is invalid");
```
## π§ TypeScript Integration
Full TypeScript support with comprehensive type definitions:
```typescript
import {
AppError,
UnauthenticatedError,
InsufficientPermissionError,
IllegalParameterError,
ActionNotFoundError,
handleError
} from '@ticatec/node-exception';
import { Request, Response, NextFunction } from 'express';
// Type-safe error middleware
const errorHandler = (
err: AppError | Error,
req: Request,
res: Response,
next: NextFunction
): void => {
handleError(err, req, res);
};
// Custom error with proper typing
class CustomValidationError extends IllegalParameterError {
constructor(field: string, value: any) {
super(`Invalid ${field}: ${value}`);
}
}
```
## ποΈ Architecture
The library uses a modular architecture with clear separation of concerns:
- **Error Classes** (`Errors.ts`): Standardized error types with global registration
- **Error Handler** (`handleError.ts`): Central error processing and response logic
- **HTTP Container** (`HttpContainer.ts`): Framework-agnostic HTTP abstraction
- **Response Types** (`ErrorResponse.ts`): Standardized response structure
- **Utilities** (`utils.ts`): Response formatting helpers
## π Requirements
- **Node.js**: β₯14.0.0
- **npm**: β₯6.0.0
- **log4js**: ^6.7.0 (peer dependency)
## π€ Contributing
We welcome contributions! Please see our [Contributing Guidelines](https://github.com/ticatec/node-exception/blob/main/CONTRIBUTING.md) for details.
### Development Setup
```bash
git clone https://github.com/ticatec/node-exception.git
cd node-exception
npm install
npm run dev # Start development mode
npm run build # Build the library
npm run typecheck # Type checking
```
## π License
MIT Β© [Henry Feng](https://github.com/henryfeng)
## π Links
- **GitHub Repository**: [https://github.com/ticatec/node-exception](https://github.com/ticatec/node-exception)
- **npm Package**: [https://www.npmjs.com/package/@ticatec/node-exception](https://www.npmjs.com/package/@ticatec/node-exception)
- **Issues**: [https://github.com/ticatec/node-exception/issues](https://github.com/ticatec/node-exception/issues)
- **Documentation**: [https://docs.ticatec.com/node-exception](https://docs.ticatec.com/node-exception)