@connectum/interceptors
Production-ready ConnectRPC interceptors providing resilience patterns, error handling, validation, and serialization. Includes a fixed-order default interceptor chain and a method-filter interceptor for per-method configuration.
Layer: 1 (Protocol)
Related Guides
- Interceptors Overview -- the interceptor chain explained
- Built-in Chain -- 8 production-ready interceptors
- Custom Interceptors -- creating your own interceptors
- Method Filtering -- per-service/per-method routing
Full API Reference
Complete TypeScript API documentation: API Reference
Installation
pnpm add @connectum/interceptorsRequires: Node.js 18+
Quick Start
import { createDefaultInterceptors } from '@connectum/interceptors';
// All defaults (fallback disabled)
const interceptors = createDefaultInterceptors();
// Custom configuration
const interceptors = createDefaultInterceptors({
retry: false,
timeout: { duration: 10_000 },
circuitBreaker: { threshold: 3 },
});When using @connectum/core, pass the result of createDefaultInterceptors() to the interceptors option:
import { createServer } from '@connectum/core';
import { createDefaultInterceptors } from '@connectum/interceptors';
const server = createServer({
services: [routes],
interceptors: createDefaultInterceptors({
errorHandler: { logErrors: true },
timeout: { duration: 15_000 },
retry: false,
}),
});Default Interceptor Chain
The interceptor order is fixed and intentional:
errorHandler -> timeout -> bulkhead -> circuitBreaker -> retry -> fallback -> validation -> serializer| # | Interceptor | Purpose | Default |
|---|---|---|---|
| 1 | errorHandler | Catch-all error normalization (outermost) | Enabled |
| 2 | timeout | Enforce request deadline | Enabled (30s) |
| 3 | bulkhead | Limit concurrent requests | Enabled (10/10) |
| 4 | circuitBreaker | Prevent cascading failures | Enabled (5 failures) |
| 5 | retry | Retry transient failures with backoff | Enabled (3 retries) |
| 6 | fallback | Graceful degradation | Disabled |
| 7 | validation | Validate request messages (@connectrpc/validate) | Enabled |
| 8 | serializer | JSON serialization (innermost) | Enabled |
API Reference
createDefaultInterceptors(options?)
Creates the full interceptor chain with configurable options.
function createDefaultInterceptors(options?: DefaultInterceptorOptions): Interceptor[];Each interceptor can be set to true (defaults), false (disabled), or an options object.
DefaultInterceptorOptions
interface DefaultInterceptorOptions {
errorHandler?: boolean | ErrorHandlerOptions; // default: true
timeout?: boolean | TimeoutOptions; // default: true
bulkhead?: boolean | BulkheadOptions; // default: true
circuitBreaker?: boolean | CircuitBreakerOptions; // default: true
retry?: boolean | RetryOptions; // default: true
fallback?: boolean | FallbackOptions; // default: false
validation?: boolean; // default: true
serializer?: boolean | SerializerOptions; // default: true
}Individual Interceptors
Error Handler
Transforms errors into ConnectError with proper gRPC status codes. Recognizes the SanitizableError protocol from @connectum/core: preserves server-side details for logging while exposing only a safe clientMessage to the client.
import { createErrorHandlerInterceptor } from '@connectum/interceptors';
const interceptor = createErrorHandlerInterceptor({
logErrors: true, // default: NODE_ENV !== "production"
includeStackTrace: false, // default: NODE_ENV !== "production"
});| Option | Type | Default | Description |
|---|---|---|---|
logErrors | boolean | NODE_ENV !== "production" | Log errors to console. Deprecated: use onError instead. |
includeStackTrace | boolean | NODE_ENV !== "production" | Include stack trace in logs |
onError | (info: { error: Error; code: number; serverDetails?: Record<string, unknown>; stack?: string }) => void | -- | Error callback. Replaces console.error when provided. Receives rich error info including serverDetails from SanitizableError. |
Timeout
Enforces a request deadline before any processing begins.
import { createTimeoutInterceptor } from '@connectum/interceptors';
const interceptor = createTimeoutInterceptor({
duration: 15_000, // 15 seconds
skipStreaming: true, // skip for streaming calls
});| Option | Type | Default | Description |
|---|---|---|---|
duration | number | 30000 | Request timeout in milliseconds |
skipStreaming | boolean | true | Skip for streaming calls |
Bulkhead
Limits concurrent requests to prevent resource exhaustion.
import { createBulkheadInterceptor } from '@connectum/interceptors';
const interceptor = createBulkheadInterceptor({
capacity: 20, // max concurrent requests
queueSize: 50, // max queued requests
skipStreaming: true,
});| Option | Type | Default | Description |
|---|---|---|---|
capacity | number | 10 | Maximum concurrent requests |
queueSize | number | 10 | Maximum queued requests |
skipStreaming | boolean | true | Skip for streaming calls |
Circuit Breaker
Prevents cascading failures by breaking the circuit on consecutive errors.
import { createCircuitBreakerInterceptor } from '@connectum/interceptors';
const interceptor = createCircuitBreakerInterceptor({
threshold: 5, // failures before opening
halfOpenAfter: 30_000, // wait before retrying
skipStreaming: true,
});| Option | Type | Default | Description |
|---|---|---|---|
threshold | number | 5 | Consecutive failures before opening |
halfOpenAfter | number | 30000 | Milliseconds before half-open attempt |
skipStreaming | boolean | true | Skip for streaming calls |
Retry
Retries transient failures with exponential backoff. Uses the cockatiel library.
import { createRetryInterceptor } from '@connectum/interceptors';
const interceptor = createRetryInterceptor({
maxRetries: 3,
initialDelay: 200,
maxDelay: 5_000,
retryableCodes: [Code.Unavailable, Code.ResourceExhausted],
skipStreaming: true,
});| Option | Type | Default | Description |
|---|---|---|---|
maxRetries | number | 3 | Maximum retry attempts |
initialDelay | number | 200 | Initial backoff delay (ms) |
maxDelay | number | 5000 | Maximum backoff delay (ms) |
retryableCodes | Code[] | [Unavailable, ResourceExhausted] | Error codes that trigger retry |
skipStreaming | boolean | true | Skip for streaming calls |
Fallback
Provides graceful degradation when the service fails. Disabled by default because it requires a handler function.
import { createFallbackInterceptor } from '@connectum/interceptors';
const interceptor = createFallbackInterceptor({
handler: (error) => ({ items: [], error: error.message }),
skipStreaming: true,
});| Option | Type | Default | Description |
|---|---|---|---|
handler | (error: Error) => T | Promise<T> | (required) | Fallback function |
skipStreaming | boolean | true | Skip for streaming calls |
Validation
Validates request messages using @connectrpc/validate (protovalidate). No configuration options; toggled on/off.
// Enabled by default in createDefaultInterceptors()
// To use standalone:
import { createValidateInterceptor } from '@connectrpc/validate';
const interceptor = createValidateInterceptor();Serializer
Auto-serializes ConnectRPC responses to JSON format.
import { createSerializerInterceptor } from '@connectum/interceptors';
const interceptor = createSerializerInterceptor({
skipGrpcServices: true,
alwaysEmitImplicit: true,
ignoreUnknownFields: true,
});| Option | Type | Default | Description |
|---|---|---|---|
skipGrpcServices | boolean | true | Skip for gRPC services |
alwaysEmitImplicit | boolean | true | Always emit implicit fields in JSON |
ignoreUnknownFields | boolean | true | Ignore unknown fields when deserializing |
Method Filter Interceptor
Routes interceptors to specific methods based on wildcard pattern matching.
import { createMethodFilterInterceptor } from '@connectum/interceptors';
const perMethodInterceptor = createMethodFilterInterceptor({
'*': [logRequest], // all methods
'admin.v1.AdminService/*': [requireAdmin], // all service methods
'user.v1.UserService/DeleteUser': [requireAdmin, auditLog], // exact method
});Pattern Resolution Order
All matching patterns execute in order:
- Global wildcard
"*"(first) - Service wildcard
"Service/*"(second) - Exact match
"Service/Method"(last)
Within each pattern, interceptors execute in array order.
MethodFilterMap
type MethodFilterMap = Record<string, Interceptor[]>;Exports Summary
| Export | Description |
|---|---|
createDefaultInterceptors | Factory for the default interceptor chain |
createErrorHandlerInterceptor | Error normalization |
createLoggerInterceptor | Request logging |
createSerializerInterceptor | JSON serialization |
createRetryInterceptor | Retry with backoff |
createCircuitBreakerInterceptor | Circuit breaker |
createTimeoutInterceptor | Request timeout |
createBulkheadInterceptor | Concurrency limiter |
createFallbackInterceptor | Graceful degradation |
createMethodFilterInterceptor | Per-method interceptor routing |
Related Packages
- @connectum/core -- Uses this package for built-in interceptor chain (dependent)
- @connectum/otel -- OpenTelemetry interceptor (complementary)
