@fjell/registry 4.4.23 → 4.4.24

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.
@@ -0,0 +1,356 @@
1
+ # Error Handling
2
+
3
+ Comprehensive error handling and resilience features for production-ready applications.
4
+
5
+ ## Overview
6
+
7
+ The Fjell Client API includes a robust error handling system designed for production environments. It provides automatic retry logic, custom error types, enhanced context, and configurable recovery strategies.
8
+
9
+ ## Key Features
10
+
11
+ ### 🔄 **Automatic Retry Logic**
12
+ - Exponential backoff with jitter
13
+ - Smart error classification (retryable vs non-retryable)
14
+ - Configurable retry strategies
15
+ - Rate limiting respect
16
+
17
+ ### 🎯 **Custom Error Types**
18
+ - Specific error classes for different scenarios
19
+ - Enhanced error context and debugging information
20
+ - Structured error data for programmatic handling
21
+ - Business-friendly error messages
22
+
23
+ ### 🛡️ **Production Resilience**
24
+ - Circuit breaker patterns
25
+ - Graceful degradation strategies
26
+ - Custom error handlers for monitoring integration
27
+ - Business workflow error recovery
28
+
29
+ ## Error Types
30
+
31
+ | Error Type | Code | Retryable | Description |
32
+ |------------|------|-----------|-------------|
33
+ | **NetworkError** | `NETWORK_ERROR` | ✅ | Connection failures, DNS issues |
34
+ | **TimeoutError** | `TIMEOUT_ERROR` | ✅ | Request timeouts |
35
+ | **ServerError** | `SERVER_ERROR` | ✅ | 5xx HTTP status codes |
36
+ | **RateLimitError** | `RATE_LIMIT_ERROR` | ✅ | 429 Too Many Requests |
37
+ | **AuthenticationError** | `AUTHENTICATION_ERROR` | ❌ | 401 Unauthorized |
38
+ | **AuthorizationError** | `AUTHORIZATION_ERROR` | ❌ | 403 Forbidden |
39
+ | **NotFoundError** | `NOT_FOUND_ERROR` | ❌ | 404 Not Found |
40
+ | **ValidationError** | `VALIDATION_ERROR` | ❌ | 400 Bad Request |
41
+ | **ConflictError** | `CONFLICT_ERROR` | ❌ | 409 Conflict |
42
+ | **PayloadTooLargeError** | `PAYLOAD_TOO_LARGE_ERROR` | ❌ | 413 Request Too Large |
43
+
44
+ ## Error Scenarios
45
+
46
+ ### [Network Errors and Timeouts](./network-errors.md)
47
+ Handle connection failures, DNS issues, and request timeouts:
48
+ ```typescript
49
+ try {
50
+ const user = await userApi.get(userKey);
51
+ } catch (error) {
52
+ if (error.code === 'NETWORK_ERROR') {
53
+ // Automatically retried with exponential backoff
54
+ console.log('Network recovered after retries');
55
+ }
56
+ }
57
+ ```
58
+
59
+ ### [Authentication and Authorization](./auth-errors.md)
60
+ Manage authentication failures and permission issues:
61
+ ```typescript
62
+ try {
63
+ const data = await api.get(key);
64
+ } catch (error) {
65
+ if (error.code === 'AUTHENTICATION_ERROR') {
66
+ // Redirect to login
67
+ redirectToLogin();
68
+ }
69
+ }
70
+ ```
71
+
72
+ ### [Validation Errors](./validation-errors.md)
73
+ Handle request validation and data format issues:
74
+ ```typescript
75
+ try {
76
+ const user = await userApi.create(userData);
77
+ } catch (error) {
78
+ if (error.code === 'VALIDATION_ERROR') {
79
+ // Display field-specific errors
80
+ error.validationErrors.forEach(err => {
81
+ showFieldError(err.field, err.message);
82
+ });
83
+ }
84
+ }
85
+ ```
86
+
87
+ ### [Server Errors and Retry Logic](./server-errors.md)
88
+ Automatic retry for server-side failures:
89
+ ```typescript
90
+ // Server errors (5xx) are automatically retried
91
+ const user = await userApi.create(userData);
92
+ // Will retry up to configured maximum on 500, 502, 503 errors
93
+ ```
94
+
95
+ ### [Rate Limiting](./rate-limiting.md)
96
+ Respect API rate limits with appropriate delays:
97
+ ```typescript
98
+ try {
99
+ const results = await api.all(query);
100
+ } catch (error) {
101
+ if (error.code === 'RATE_LIMIT_ERROR') {
102
+ // Automatically retried after rate limit period
103
+ console.log('Rate limit recovered');
104
+ }
105
+ }
106
+ ```
107
+
108
+ ### [Custom Error Handling](./custom-errors.md)
109
+ Implement custom error handlers for monitoring and business logic:
110
+ ```typescript
111
+ const config = {
112
+ errorHandler: (error, context) => {
113
+ // Send to monitoring service
114
+ monitoring.recordError(error, context);
115
+
116
+ // Business-specific error handling
117
+ if (error.code === 'PAYMENT_FAILED') {
118
+ sendPaymentFailureNotification(context.customerId);
119
+ }
120
+ }
121
+ };
122
+ ```
123
+
124
+ ## Configuration
125
+
126
+ ### Basic Configuration
127
+
128
+ ```typescript
129
+ const config = {
130
+ baseUrl: 'https://api.example.com',
131
+ retryConfig: {
132
+ maxRetries: 3,
133
+ initialDelayMs: 1000,
134
+ maxDelayMs: 30000,
135
+ backoffMultiplier: 2,
136
+ enableJitter: true
137
+ },
138
+ enableErrorHandling: true
139
+ };
140
+
141
+ const userApi = createPItemApi<User, 'user'>('user', ['users'], config);
142
+ ```
143
+
144
+ ### Advanced Configuration
145
+
146
+ ```typescript
147
+ const enterpriseConfig = {
148
+ baseUrl: 'https://api.enterprise.com',
149
+ retryConfig: {
150
+ maxRetries: 5,
151
+ initialDelayMs: 500,
152
+ maxDelayMs: 60000,
153
+ backoffMultiplier: 1.5,
154
+ enableJitter: true,
155
+
156
+ // Custom retry logic
157
+ shouldRetry: (error, attemptNumber) => {
158
+ if (error.code === 'PAYMENT_ERROR') {
159
+ return attemptNumber < 2; // Limited retries for payments
160
+ }
161
+ return error.isRetryable && attemptNumber < 5;
162
+ },
163
+
164
+ // Custom retry callback
165
+ onRetry: (error, attemptNumber, delay) => {
166
+ logger.warn(`Retrying API call (attempt ${attemptNumber + 1})`, {
167
+ errorCode: error.code,
168
+ delay
169
+ });
170
+ }
171
+ },
172
+
173
+ // Custom error handler
174
+ errorHandler: (error, context) => {
175
+ // Centralized error logging
176
+ logger.error('API Operation Failed', {
177
+ error: error.message,
178
+ code: error.code,
179
+ operation: context.operation,
180
+ duration: context.duration
181
+ });
182
+
183
+ // Send to error tracking
184
+ errorTracking.captureException(error, { extra: context });
185
+
186
+ // Business logic
187
+ if (error.code === 'RATE_LIMIT_ERROR') {
188
+ circuitBreaker.recordFailure();
189
+ }
190
+ }
191
+ };
192
+ ```
193
+
194
+ ## Best Practices
195
+
196
+ ### 1. **Handle Specific Error Types**
197
+
198
+ ```typescript
199
+ try {
200
+ const result = await api.operation();
201
+ } catch (error) {
202
+ switch (error.code) {
203
+ case 'VALIDATION_ERROR':
204
+ handleValidationErrors(error.validationErrors);
205
+ break;
206
+ case 'AUTHENTICATION_ERROR':
207
+ redirectToLogin();
208
+ break;
209
+ case 'NETWORK_ERROR':
210
+ showNetworkErrorMessage();
211
+ break;
212
+ default:
213
+ showGenericErrorMessage(error.message);
214
+ }
215
+ }
216
+ ```
217
+
218
+ ### 2. **Implement Graceful Degradation**
219
+
220
+ ```typescript
221
+ async function getUserWithFallback(userKey: PriKey<'user'>): Promise<User | null> {
222
+ try {
223
+ return await userApi.get(userKey);
224
+ } catch (error) {
225
+ if (error.code === 'NETWORK_ERROR') {
226
+ // Use cached data
227
+ return await getCachedUser(userKey);
228
+ }
229
+
230
+ if (error.code === 'NOT_FOUND_ERROR') {
231
+ // Return null gracefully
232
+ return null;
233
+ }
234
+
235
+ // Re-throw unexpected errors
236
+ throw error;
237
+ }
238
+ }
239
+ ```
240
+
241
+ ### 3. **Monitor Error Patterns**
242
+
243
+ ```typescript
244
+ const errorMetrics = {
245
+ recordError: (error: ClientApiError, context: any) => {
246
+ metrics.increment('api.errors.total', {
247
+ error_code: error.code,
248
+ operation: context.operation
249
+ });
250
+
251
+ if (error.isRetryable) {
252
+ metrics.increment('api.errors.retryable');
253
+ }
254
+ }
255
+ };
256
+ ```
257
+
258
+ ### 4. **Business Workflow Recovery**
259
+
260
+ ```typescript
261
+ async function createOrderWithRecovery(orderData: OrderData) {
262
+ const transaction = await beginTransaction();
263
+
264
+ try {
265
+ const order = await orderApi.create(orderData);
266
+ const payment = await paymentApi.create({ orderId: order.id });
267
+
268
+ await transaction.commit();
269
+ return order;
270
+
271
+ } catch (error) {
272
+ await transaction.rollback();
273
+
274
+ // Compensating actions
275
+ if (error.code === 'PAYMENT_FAILED') {
276
+ await notificationService.sendPaymentFailure(orderData.customerId);
277
+ }
278
+
279
+ throw error;
280
+ }
281
+ }
282
+ ```
283
+
284
+ ## Testing Error Scenarios
285
+
286
+ ### Unit Testing
287
+
288
+ ```typescript
289
+ describe('Error Handling', () => {
290
+ it('should retry on network errors', async () => {
291
+ const mockApi = createMockApi();
292
+ mockApi.httpGet.mockRejectedValueOnce(new NetworkError('Connection failed'));
293
+ mockApi.httpGet.mockResolvedValueOnce({ id: 'user-123' });
294
+
295
+ const user = await userApi.get(userKey);
296
+ expect(user.id).toBe('user-123');
297
+ expect(mockApi.httpGet).toHaveBeenCalledTimes(2);
298
+ });
299
+
300
+ it('should not retry on validation errors', async () => {
301
+ const mockApi = createMockApi();
302
+ mockApi.httpPost.mockRejectedValue(new ValidationError('Invalid data'));
303
+
304
+ await expect(userApi.create({})).rejects.toThrow('Invalid data');
305
+ expect(mockApi.httpPost).toHaveBeenCalledTimes(1);
306
+ });
307
+ });
308
+ ```
309
+
310
+ ### Integration Testing
311
+
312
+ ```typescript
313
+ describe('Error Recovery', () => {
314
+ it('should handle server downtime gracefully', async () => {
315
+ // Simulate server being down then recovering
316
+ server.use(
317
+ rest.get('/api/users/:id', (req, res, ctx) => {
318
+ return res.once(ctx.status(500));
319
+ }),
320
+ rest.get('/api/users/:id', (req, res, ctx) => {
321
+ return res(ctx.json({ id: 'user-123' }));
322
+ })
323
+ );
324
+
325
+ const user = await userApi.get(userKey);
326
+ expect(user.id).toBe('user-123');
327
+ });
328
+ });
329
+ ```
330
+
331
+ ## Production Checklist
332
+
333
+ - [ ] Configure appropriate retry strategies for your use case
334
+ - [ ] Implement custom error handlers for monitoring and alerting
335
+ - [ ] Set up error tracking (Sentry, Datadog, etc.)
336
+ - [ ] Add business-specific error recovery logic
337
+ - [ ] Implement graceful degradation for critical paths
338
+ - [ ] Monitor error rates and patterns
339
+ - [ ] Test error scenarios in staging environments
340
+ - [ ] Document error handling procedures for your team
341
+ - [ ] Set up alerts for critical error patterns
342
+ - [ ] Implement circuit breakers for external services
343
+
344
+ ## Related Documentation
345
+
346
+ - [Configuration Guide](../configuration.md) - Configure error handling behavior
347
+ - [Operations](../operations/README.md) - Error handling in specific operations
348
+ - [Examples](../../examples-README.md) - Error handling examples and patterns
349
+
350
+ ## Next Steps
351
+
352
+ 1. Review specific error scenario documentation
353
+ 2. Configure error handling for your environment
354
+ 3. Implement custom error handlers for your monitoring stack
355
+ 4. Test error scenarios in your application
356
+ 5. Set up monitoring and alerting for production