tryError Documentation
Middleware System
Extend tryError with custom logic using a powerful middleware pipeline
Flexible Extension
The middleware system allows you to intercept and modify error handling behavior without modifying tryError's core. Perfect for logging, monitoring, transformation, and integration with external services.
Basic Concepts
Middleware functions intercept TryResult values and can modify them, log them, or perform side effects before passing control to the next middleware.
1import { ErrorMiddleware, TryResult, TryError } from '@try-error/core';
2
3// Basic middleware signature
4type ErrorMiddleware<T = any, E extends TryError = TryError> = (
5 result: TryResult<T, E>,
6 next: () => TryResult<T, E>
7) => TryResult<T, E>;
8
9// Example: Simple logging middleware
10const loggingMiddleware: ErrorMiddleware = (result, next) => {
11 if (isTryError(result)) {
12 console.error('Error occurred:', result);
13 }
14 return next(); // Pass control to next middleware
15};
Using Middleware
1import { MiddlewarePipeline } from '@try-error/core';
2
3// Create a middleware pipeline
4const pipeline = new MiddlewarePipeline();
5
6// Add middleware to the pipeline
7pipeline
8 .use(loggingMiddleware)
9 .use(retryMiddleware(3))
10 .use(transformMiddleware);
11
12// Execute with a result
13const result = pipeline.execute(trySync(() => riskyOperation()));
14
15// Or wrap a function
16const safeFn = pipeline.wrap((x: number) =>
17 trySync(() => {
18 if (x < 0) throw new Error('Negative number');
19 return Math.sqrt(x);
20 })
21);
22
23const result = safeFn(16); // Middleware applied automatically
Built-in Middleware
tryError provides a collection of common middleware patterns ready to use.
Logging Middleware
Log errors to console or external services
import { loggingMiddleware } from '@try-error/core';
// Simple console logging
pipeline.use(loggingMiddleware(console.error));
// Custom logger
const customLogger = (error: TryError) => {
myLoggingService.log({
level: 'error',
message: error.message,
type: error.type,
context: error.context,
timestamp: error.timestamp
});
};
pipeline.use(loggingMiddleware(customLogger));
Retry Middleware
Automatically retry failed operations
import { retryMiddleware } from '@try-error/core';
// Retry up to 3 times
pipeline.use(retryMiddleware(3));
// With custom retry logic
const shouldRetry = (error: TryError) => {
// Only retry network errors
return error.type === 'NetworkError' &&
error.context?.statusCode !== 404;
};
pipeline.use(retryMiddleware(5, shouldRetry));
// Note: Retry middleware tracks attempts internally
// Each call to the pipeline counts as one attempt
Transform Middleware
Modify errors before they're returned
import { transformMiddleware } from '@try-error/core';
// Add additional context
const addRequestId = transformMiddleware(error => ({
...error,
context: {
...error.context,
requestId: generateRequestId()
}
}));
// Sanitize sensitive data
const sanitize = transformMiddleware(error => ({
...error,
message: error.message.replace(/password=S+/g, 'password=***'),
context: omit(error.context, ['password', 'apiKey'])
}));
pipeline.use(addRequestId).use(sanitize);
Circuit Breaker Middleware
Prevent cascading failures in distributed systems
import { circuitBreakerMiddleware } from '@try-error/core';
const circuitBreaker = circuitBreakerMiddleware({
threshold: 5, // Open after 5 failures
timeout: 60000, // Try again after 1 minute
onOpen: () => {
console.warn('Circuit breaker opened!');
alertOpsTeam();
},
onClose: () => {
console.info('Circuit breaker closed');
}
});
pipeline.use(circuitBreaker);
// When circuit is open, requests fail fast with:
// { type: 'CircuitBreakerOpen', message: 'Circuit breaker is open' }
Rate Limit Middleware
Limit error frequency to prevent spam
import { rateLimitMiddleware } from '@try-error/core';
// Allow max 100 errors per second
const rateLimiter = rateLimitMiddleware(1000, 100);
pipeline.use(rateLimiter);
// Errors beyond limit return:
// {
// type: 'RateLimitExceeded',
// message: 'Rate limit exceeded: 100 errors in 1000ms',
// context: { windowMs: 1000, maxErrors: 100, currentCount: 100 }
// }
Context Enrichment
Add contextual information to errors
import { enrichContextMiddleware } from '@try-error/core';
// Add static context
pipeline.use(enrichContextMiddleware(() => ({
service: 'api-gateway',
version: process.env.APP_VERSION,
region: process.env.AWS_REGION
})));
// Add dynamic context
pipeline.use(enrichContextMiddleware(() => ({
timestamp: Date.now(),
requestId: getCurrentRequestId(),
userId: getCurrentUserId(),
memory: process.memoryUsage()
})));
Creating Custom Middleware
Build your own middleware to handle specific requirements.
1// Send errors to monitoring service
2const monitoringMiddleware: ErrorMiddleware = (result, next) => {
3 if (isTryError(result)) {
4 // Non-blocking send to monitoring
5 sendToMonitoring({
6 error: {
7 type: result.type,
8 message: result.message,
9 stack: result.stack,
10 context: result.context
11 },
12 metadata: {
13 service: 'my-service',
14 timestamp: result.timestamp,
15 severity: getSeverity(result.type)
16 }
17 }).catch(console.error); // Don't let monitoring fail the request
18 }
19
20 return next();
21};
22
23// Metrics collection
24const metricsMiddleware: ErrorMiddleware = (result, next) => {
25 const start = performance.now();
26 const nextResult = next();
27 const duration = performance.now() - start;
28
29 if (isTryError(nextResult)) {
30 metrics.increment('errors.total', {
31 type: nextResult.type,
32 duration: Math.round(duration)
33 });
34 }
35
36 return nextResult;
37};
Best Practices
Middleware Order Matters
Middleware executes in the order it's added:
// ❌ Wrong order - retry happens after transform
pipeline
.use(transformMiddleware)
.use(retryMiddleware(3));
// ✅ Correct order - retry original operation
pipeline
.use(retryMiddleware(3))
.use(transformMiddleware);
Always Call Next
// ❌ Forgetting to call next breaks the chain
const badMiddleware = (result, next) => {
if (isTryError(result)) {
console.error(result);
// Missing: return next();
}
return result; // Wrong!
};
// ✅ Always call next or return a result
const goodMiddleware = (result, next) => {
if (isTryError(result)) {
console.error(result);
}
return next(); // Continue the chain
};
Handle Middleware Errors
// Use trySync to safely handle middleware operations
const safeMiddleware: ErrorMiddleware = (result, next) => {
if (isTryError(result)) {
// Safely call external service
const logResult = trySync(() => {
externalService.logError(result);
});
if (isTryError(logResult)) {
// Don't let middleware errors break the app
console.error('Middleware error:', logResult.message);
}
}
return next();
};