@dangao/bun-server 1.1.2 → 1.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/api.md +602 -0
- package/docs/best-practices.md +12 -0
- package/docs/custom-decorators.md +440 -0
- package/docs/deployment.md +447 -0
- package/docs/error-handling.md +462 -0
- package/docs/extensions.md +569 -0
- package/docs/guide.md +634 -0
- package/docs/migration.md +10 -0
- package/docs/performance.md +452 -0
- package/docs/troubleshooting.md +286 -0
- package/docs/zh/api.md +168 -0
- package/docs/zh/best-practices.md +38 -0
- package/docs/zh/custom-decorators.md +466 -0
- package/docs/zh/deployment.md +445 -0
- package/docs/zh/error-handling.md +456 -0
- package/docs/zh/extensions.md +584 -0
- package/docs/zh/guide.md +361 -0
- package/docs/zh/migration.md +86 -0
- package/docs/zh/performance.md +451 -0
- package/docs/zh/troubleshooting.md +279 -0
- package/package.json +4 -3
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
# Error Handling Guide
|
|
2
|
+
|
|
3
|
+
This document introduces the error handling system of Bun Server Framework,
|
|
4
|
+
including error code specifications, internationalization support, and best
|
|
5
|
+
practices.
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
- [Error Code System](#error-code-system)
|
|
10
|
+
- [Error Message Internationalization](#error-message-internationalization)
|
|
11
|
+
- [Exception Filters](#exception-filters)
|
|
12
|
+
- [Best Practices](#best-practices)
|
|
13
|
+
- [Example Code](#example-code)
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Error Code System
|
|
18
|
+
|
|
19
|
+
### Error Code Specification
|
|
20
|
+
|
|
21
|
+
Error codes follow a unified naming convention:
|
|
22
|
+
|
|
23
|
+
- **Format**: `MODULE_ERROR_TYPE_SPECIFIC_ERROR`
|
|
24
|
+
- **Use uppercase letters and underscores**
|
|
25
|
+
- **Module prefixes**:
|
|
26
|
+
- `AUTH` - Authentication and authorization
|
|
27
|
+
- `VALIDATION` - Validation
|
|
28
|
+
- `DATABASE` - Database
|
|
29
|
+
- `FILE` - File operations
|
|
30
|
+
- `MIDDLEWARE` - Middleware
|
|
31
|
+
- `OAUTH2` - OAuth2
|
|
32
|
+
- `CONFIG` - Configuration
|
|
33
|
+
|
|
34
|
+
**Examples**:
|
|
35
|
+
|
|
36
|
+
- `AUTH_INVALID_TOKEN` - Invalid authentication token
|
|
37
|
+
- `VALIDATION_REQUIRED_FIELD` - Required field missing
|
|
38
|
+
- `DATABASE_CONNECTION_FAILED` - Database connection failed
|
|
39
|
+
|
|
40
|
+
### Error Code Categories
|
|
41
|
+
|
|
42
|
+
Error codes are categorized by functional modules, each category corresponds to
|
|
43
|
+
a numeric range:
|
|
44
|
+
|
|
45
|
+
- **1000-1999**: General errors
|
|
46
|
+
- **2000-2999**: Authentication and authorization errors
|
|
47
|
+
- **3000-3999**: Validation errors
|
|
48
|
+
- **4000-4999**: OAuth2 errors
|
|
49
|
+
- **5000-5999**: Database errors
|
|
50
|
+
- **6000-6999**: File operation errors
|
|
51
|
+
- **7000-7999**: Middleware errors
|
|
52
|
+
- **8000-8999**: Configuration errors
|
|
53
|
+
|
|
54
|
+
### Using Error Codes
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
import { ErrorCode, HttpException } from "@dangao/bun-server";
|
|
58
|
+
|
|
59
|
+
// Method 1: Use HttpException.withCode()
|
|
60
|
+
throw HttpException.withCode(ErrorCode.RESOURCE_NOT_FOUND);
|
|
61
|
+
|
|
62
|
+
// Method 2: Use exception class with error code
|
|
63
|
+
throw new NotFoundException(
|
|
64
|
+
"User not found",
|
|
65
|
+
undefined,
|
|
66
|
+
ErrorCode.RESOURCE_NOT_FOUND,
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
// Method 3: With custom message and details
|
|
70
|
+
throw HttpException.withCode(
|
|
71
|
+
ErrorCode.VALIDATION_FAILED,
|
|
72
|
+
"Custom validation message",
|
|
73
|
+
{ field: "email", reason: "Invalid format" },
|
|
74
|
+
);
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Error Message Internationalization
|
|
80
|
+
|
|
81
|
+
### Supported Languages
|
|
82
|
+
|
|
83
|
+
The framework supports the following languages:
|
|
84
|
+
|
|
85
|
+
- `en` - English (default)
|
|
86
|
+
- `zh-CN` - Simplified Chinese
|
|
87
|
+
- `ja` - Japanese (partial)
|
|
88
|
+
- `ko` - Korean (partial)
|
|
89
|
+
|
|
90
|
+
### Automatic Language Detection
|
|
91
|
+
|
|
92
|
+
The framework automatically detects user language based on the HTTP
|
|
93
|
+
`Accept-Language` header:
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
// Request header example
|
|
97
|
+
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Message Template System
|
|
101
|
+
|
|
102
|
+
Error messages support template parameters using `{key}` as placeholders:
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
import { ErrorCode, HttpException } from "@dangao/bun-server";
|
|
106
|
+
|
|
107
|
+
// If error message template is 'Resource {resource} not found'
|
|
108
|
+
throw HttpException.withCode(
|
|
109
|
+
ErrorCode.RESOURCE_NOT_FOUND,
|
|
110
|
+
undefined,
|
|
111
|
+
undefined,
|
|
112
|
+
{ resource: "User" }, // Message template parameters
|
|
113
|
+
);
|
|
114
|
+
// Returns: 'Resource User not found' (English) or '资源 User 未找到' (Chinese)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Manual Language Setting
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
import { ErrorMessageI18n } from "@dangao/bun-server";
|
|
121
|
+
|
|
122
|
+
// Set global language
|
|
123
|
+
ErrorMessageI18n.setLanguage("zh-CN");
|
|
124
|
+
|
|
125
|
+
// Get error message for specific language
|
|
126
|
+
const message = ErrorMessageI18n.getMessage(
|
|
127
|
+
ErrorCode.RESOURCE_NOT_FOUND,
|
|
128
|
+
"zh-CN",
|
|
129
|
+
{ resource: "User" },
|
|
130
|
+
);
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Exception Filters
|
|
136
|
+
|
|
137
|
+
Exception filters allow you to customize error handling logic, handling specific
|
|
138
|
+
exception types or error codes.
|
|
139
|
+
|
|
140
|
+
### Creating Exception Filters
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
import type { ExceptionFilter } from "@dangao/bun-server";
|
|
144
|
+
import type { Context } from "@dangao/bun-server";
|
|
145
|
+
import { ErrorCode, HttpException } from "@dangao/bun-server";
|
|
146
|
+
|
|
147
|
+
class CustomExceptionFilter implements ExceptionFilter {
|
|
148
|
+
public catch(error: unknown, context: Context): Response | undefined {
|
|
149
|
+
if (
|
|
150
|
+
error instanceof HttpException &&
|
|
151
|
+
error.code === ErrorCode.DATABASE_CONNECTION_FAILED
|
|
152
|
+
) {
|
|
153
|
+
// Custom handling for database connection errors
|
|
154
|
+
context.setStatus(503);
|
|
155
|
+
return context.createResponse({
|
|
156
|
+
error: "Database service temporarily unavailable",
|
|
157
|
+
code: error.code,
|
|
158
|
+
retryAfter: 60, // Suggest retry after 60 seconds
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Return undefined to pass to next filter
|
|
163
|
+
return undefined;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Registering Exception Filters
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
import { ExceptionFilterRegistry } from "@dangao/bun-server";
|
|
172
|
+
|
|
173
|
+
const registry = ExceptionFilterRegistry.getInstance();
|
|
174
|
+
registry.register(new CustomExceptionFilter());
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Filter Execution Order
|
|
178
|
+
|
|
179
|
+
Exception filters execute in registration order, the first filter returning a
|
|
180
|
+
non-`undefined` result will be used.
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Best Practices
|
|
185
|
+
|
|
186
|
+
### 1. Use Error Codes
|
|
187
|
+
|
|
188
|
+
**Recommended** ✅:
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
throw HttpException.withCode(ErrorCode.RESOURCE_NOT_FOUND);
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
**Not Recommended** ❌:
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
throw new Error("Resource not found");
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### 2. Provide Error Details
|
|
201
|
+
|
|
202
|
+
For validation errors, provide detailed error information:
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
throw HttpException.withCode(
|
|
206
|
+
ErrorCode.VALIDATION_FAILED,
|
|
207
|
+
"Validation failed",
|
|
208
|
+
{
|
|
209
|
+
field: "email",
|
|
210
|
+
reason: "Invalid email format",
|
|
211
|
+
value: userInput.email,
|
|
212
|
+
},
|
|
213
|
+
);
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### 3. Use Message Template Parameters
|
|
217
|
+
|
|
218
|
+
For error messages requiring dynamic information, use message template
|
|
219
|
+
parameters:
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
throw HttpException.withCode(
|
|
223
|
+
ErrorCode.RESOURCE_NOT_FOUND,
|
|
224
|
+
undefined,
|
|
225
|
+
undefined,
|
|
226
|
+
{ resource: "User", id: userId },
|
|
227
|
+
);
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### 4. Custom Exception Filters
|
|
231
|
+
|
|
232
|
+
For errors requiring special handling, use exception filters:
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
class DatabaseExceptionFilter implements ExceptionFilter {
|
|
236
|
+
public catch(error: unknown, context: Context): Response | undefined {
|
|
237
|
+
if (
|
|
238
|
+
error instanceof HttpException &&
|
|
239
|
+
error.code?.startsWith("DATABASE_")
|
|
240
|
+
) {
|
|
241
|
+
// Unified handling for all database errors
|
|
242
|
+
return context.createResponse({
|
|
243
|
+
error: "Database error occurred",
|
|
244
|
+
code: error.code,
|
|
245
|
+
timestamp: new Date().toISOString(),
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
return undefined;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### 5. Production Error Handling
|
|
254
|
+
|
|
255
|
+
In production environments, avoid exposing sensitive information:
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
// Error handler automatically handles this
|
|
259
|
+
// In production, non-HttpException errors won't expose detailed information
|
|
260
|
+
if (process.env.NODE_ENV === "production") {
|
|
261
|
+
// Only return generic error message
|
|
262
|
+
return context.createResponse({
|
|
263
|
+
error: "Internal Server Error",
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### 6. Error Logging
|
|
269
|
+
|
|
270
|
+
Log errors in exception filters:
|
|
271
|
+
|
|
272
|
+
```typescript
|
|
273
|
+
class LoggingExceptionFilter implements ExceptionFilter {
|
|
274
|
+
public catch(error: unknown, context: Context): Response | undefined {
|
|
275
|
+
// Log error
|
|
276
|
+
console.error("Error occurred:", {
|
|
277
|
+
error,
|
|
278
|
+
path: context.getPath(),
|
|
279
|
+
method: context.getMethod(),
|
|
280
|
+
timestamp: new Date().toISOString(),
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
return undefined; // Continue to next filter
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
## Example Code
|
|
291
|
+
|
|
292
|
+
### Complete Error Handling Example
|
|
293
|
+
|
|
294
|
+
```typescript
|
|
295
|
+
import {
|
|
296
|
+
Application,
|
|
297
|
+
type Context,
|
|
298
|
+
Controller,
|
|
299
|
+
ErrorCode,
|
|
300
|
+
ExceptionFilter,
|
|
301
|
+
ExceptionFilterRegistry,
|
|
302
|
+
GET,
|
|
303
|
+
HttpException,
|
|
304
|
+
Param,
|
|
305
|
+
} from "@dangao/bun-server";
|
|
306
|
+
|
|
307
|
+
// 1. Create custom exception filter
|
|
308
|
+
class ApiExceptionFilter implements ExceptionFilter {
|
|
309
|
+
public catch(error: unknown, context: Context): Response | undefined {
|
|
310
|
+
if (error instanceof HttpException) {
|
|
311
|
+
// Add request ID and timestamp
|
|
312
|
+
return context.createResponse({
|
|
313
|
+
error: error.message,
|
|
314
|
+
code: error.code,
|
|
315
|
+
details: error.details,
|
|
316
|
+
requestId: context.getHeader("x-request-id"),
|
|
317
|
+
timestamp: new Date().toISOString(),
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
return undefined;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// 2. Register exception filter
|
|
325
|
+
const registry = ExceptionFilterRegistry.getInstance();
|
|
326
|
+
registry.register(new ApiExceptionFilter());
|
|
327
|
+
|
|
328
|
+
// 3. Use error codes in controller
|
|
329
|
+
@Controller("/api/users")
|
|
330
|
+
class UserController {
|
|
331
|
+
@GET("/:id")
|
|
332
|
+
public async getUser(@Param("id") id: string) {
|
|
333
|
+
const userId = parseInt(id, 10);
|
|
334
|
+
|
|
335
|
+
if (isNaN(userId)) {
|
|
336
|
+
throw HttpException.withCode(
|
|
337
|
+
ErrorCode.VALIDATION_INVALID_FORMAT,
|
|
338
|
+
"Invalid user ID format",
|
|
339
|
+
{ field: "id", value: id },
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
const user = await this.userService.findById(userId);
|
|
344
|
+
|
|
345
|
+
if (!user) {
|
|
346
|
+
throw HttpException.withCode(
|
|
347
|
+
ErrorCode.RESOURCE_NOT_FOUND,
|
|
348
|
+
undefined,
|
|
349
|
+
undefined,
|
|
350
|
+
{ resource: "User", id: userId },
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
return user;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// 4. Start application
|
|
359
|
+
const app = new Application();
|
|
360
|
+
app.registerController(UserController);
|
|
361
|
+
app.listen();
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### Database Error Handling Example
|
|
365
|
+
|
|
366
|
+
```typescript
|
|
367
|
+
import { ErrorCode, HttpException } from "@dangao/bun-server";
|
|
368
|
+
|
|
369
|
+
try {
|
|
370
|
+
await database.query("SELECT * FROM users WHERE id = ?", [userId]);
|
|
371
|
+
} catch (error) {
|
|
372
|
+
if (error.code === "SQLITE_ERROR") {
|
|
373
|
+
throw HttpException.withCode(
|
|
374
|
+
ErrorCode.DATABASE_QUERY_FAILED,
|
|
375
|
+
"Failed to query user",
|
|
376
|
+
{ sql: error.sql, params: [userId] },
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
throw error;
|
|
380
|
+
}
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
### Validation Error Handling Example
|
|
384
|
+
|
|
385
|
+
```typescript
|
|
386
|
+
import { ErrorCode, HttpException } from "@dangao/bun-server";
|
|
387
|
+
|
|
388
|
+
if (!email || !isValidEmail(email)) {
|
|
389
|
+
throw HttpException.withCode(
|
|
390
|
+
ErrorCode.VALIDATION_INVALID_FORMAT,
|
|
391
|
+
"Invalid email format",
|
|
392
|
+
{
|
|
393
|
+
field: "email",
|
|
394
|
+
value: email,
|
|
395
|
+
expected: "valid email address",
|
|
396
|
+
},
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
---
|
|
402
|
+
|
|
403
|
+
## Error Code Reference
|
|
404
|
+
|
|
405
|
+
### General Errors (1000-1999)
|
|
406
|
+
|
|
407
|
+
- `INTERNAL_ERROR` - Internal server error
|
|
408
|
+
- `INVALID_REQUEST` - Invalid request
|
|
409
|
+
- `RESOURCE_NOT_FOUND` - Resource not found
|
|
410
|
+
- `METHOD_NOT_ALLOWED` - Method not allowed
|
|
411
|
+
- `RATE_LIMIT_EXCEEDED` - Rate limit exceeded
|
|
412
|
+
- `SERVICE_UNAVAILABLE` - Service unavailable
|
|
413
|
+
- `TIMEOUT` - Request timeout
|
|
414
|
+
|
|
415
|
+
### Authentication and Authorization Errors (2000-2999)
|
|
416
|
+
|
|
417
|
+
- `AUTH_REQUIRED` - Authentication required
|
|
418
|
+
- `AUTH_INVALID_TOKEN` - Invalid authentication token
|
|
419
|
+
- `AUTH_TOKEN_EXPIRED` - Authentication token expired
|
|
420
|
+
- `AUTH_INSUFFICIENT_PERMISSIONS` - Insufficient permissions
|
|
421
|
+
- `AUTH_INVALID_CREDENTIALS` - Invalid credentials
|
|
422
|
+
- `AUTH_ACCOUNT_LOCKED` - Account locked
|
|
423
|
+
- `AUTH_ACCOUNT_DISABLED` - Account disabled
|
|
424
|
+
|
|
425
|
+
### Validation Errors (3000-3999)
|
|
426
|
+
|
|
427
|
+
- `VALIDATION_FAILED` - Validation failed
|
|
428
|
+
- `VALIDATION_REQUIRED_FIELD` - Required field missing
|
|
429
|
+
- `VALIDATION_INVALID_FORMAT` - Invalid format
|
|
430
|
+
- `VALIDATION_OUT_OF_RANGE` - Value out of range
|
|
431
|
+
- `VALIDATION_TYPE_MISMATCH` - Type mismatch
|
|
432
|
+
- `VALIDATION_CONSTRAINT_VIOLATION` - Constraint violation
|
|
433
|
+
|
|
434
|
+
### Database Errors (5000-5999)
|
|
435
|
+
|
|
436
|
+
- `DATABASE_CONNECTION_FAILED` - Database connection failed
|
|
437
|
+
- `DATABASE_QUERY_FAILED` - Database query failed
|
|
438
|
+
- `DATABASE_TRANSACTION_FAILED` - Database transaction failed
|
|
439
|
+
- `DATABASE_CONSTRAINT_VIOLATION` - Database constraint violation
|
|
440
|
+
- `DATABASE_TIMEOUT` - Database timeout
|
|
441
|
+
- `DATABASE_POOL_EXHAUSTED` - Database connection pool exhausted
|
|
442
|
+
- `DATABASE_MIGRATION_FAILED` - Database migration failed
|
|
443
|
+
|
|
444
|
+
### File Operation Errors (6000-6999)
|
|
445
|
+
|
|
446
|
+
- `FILE_NOT_FOUND` - File not found
|
|
447
|
+
- `FILE_UPLOAD_FAILED` - File upload failed
|
|
448
|
+
- `FILE_DOWNLOAD_FAILED` - File download failed
|
|
449
|
+
- `FILE_SIZE_EXCEEDED` - File size exceeded
|
|
450
|
+
- `FILE_TYPE_NOT_ALLOWED` - File type not allowed
|
|
451
|
+
- `FILE_ACCESS_DENIED` - File access denied
|
|
452
|
+
- `FILE_PATH_TRAVERSAL` - Path traversal attack detected
|
|
453
|
+
|
|
454
|
+
For a complete list of error codes, refer to `src/error/error-codes.ts`.
|
|
455
|
+
|
|
456
|
+
---
|
|
457
|
+
|
|
458
|
+
## Related Resources
|
|
459
|
+
|
|
460
|
+
- [API Documentation](./api.md)
|
|
461
|
+
- [User Guide](./guide.md)
|
|
462
|
+
- [Best Practices](./best-practices.md)
|