Middleware
The SDK supports middleware for cross-cutting concerns like logging and metrics. Middleware functions are executed automatically around command execution.
Note: This is different from the Axios instance logger. Middleware loggers handle command-level logging, while the Axios logger handles HTTP request/response logging.
Understanding Middleware Concepts
There are three key concepts to understand:
- Middleware - A wrapper that runs code before/after command execution
- Logger Interface - A contract defining what methods a logger object must have
- Custom Middleware - Your own middleware implementing the Middleware interface
Quick Comparison
| Concept | What It Is | When to Use |
|---|---|---|
| Logging Middleware | Pre-built middleware for logging commands | Use createLoggingMiddleware(logger) when you want automatic command logging |
| Logger Interface | Contract for logger objects | Implement this when creating a custom logger for Logging Middleware |
| Metrics Middleware | Pre-built middleware for tracking metrics | Use createMetricsMiddleware(client) when you want to track command metrics |
| Custom Middleware | Build-your-own middleware | Implement the Middleware interface when you need custom behavior |
Logging Middleware
Purpose: Automatically logs command execution details (inputs, outputs, errors).
Basic Usage (with console)
import { createInstance, createLoggingMiddleware } from '@mbanq/core-sdk-js';
const client = createInstance({
secret: 'testing123',
signee: 'TESTING',
baseUrl: 'https://example.com',
tenantId: 'testing',
middlewares: [createLoggingMiddleware(console)]
});With Custom Logger
First, create a logger that implements the Logger interface:
// Logger Interface - what your logger must implement
interface Logger {
info: (message: string, ...args: unknown[]) => void; // Required
error: (message: string, ...args: unknown[]) => void; // Required
warn?: (message: string, ...args: unknown[]) => void; // Optional
log?: (message: string, ...args: unknown[]) => void; // Optional
}
// Example: Custom logger implementation
const customLogger = {
info: (message, ...args) => myLoggingService.info(message, args),
error: (message, ...args) => myLoggingService.error(message, args),
warn: (message, ...args) => myLoggingService.warn(message, args)
};
// Use your custom logger with Logging Middleware
const middleware = createLoggingMiddleware(customLogger);
const client = createInstance({
secret: 'testing123',
signee: 'TESTING',
baseUrl: 'https://example.com',
tenantId: 'testing',
middlewares: [middleware]
});Metrics Middleware
Purpose: Tracks command execution metrics (counters for started, completed, and error events).
Usage
import { createInstance, createMetricsMiddleware } from '@mbanq/core-sdk-js';
// Your metrics client must implement the MetricsClient interface
const metricsClient = {
incrementCounter: (counterName) => {
// Increment your counter (e.g., Prometheus, StatsD, etc.)
console.log(`Counter: ${counterName}`);
},
recordError: (error) => {
// Optional: Record error details
console.error('Command error:', error);
}
};
const client = createInstance({
secret: 'testing123',
signee: 'TESTING',
baseUrl: 'https://example.com',
tenantId: 'testing',
middlewares: [createMetricsMiddleware(metricsClient)]
});MetricsClient Interface
interface MetricsClient {
incrementCounter: (counterName: string) => void; // Required
recordError?: (error: Error) => void; // Optional
}Custom Middleware
Purpose: Create your own middleware for custom behavior (e.g., performance monitoring, audit logging, caching).
Middleware Interface
interface Middleware {
before?: (command: Command) => Promise<void>; // Called before execution
after?: (command: Command, response: any) => Promise<void>; // Called after success
onError?: (command: Command, error: Error) => Promise<void>; // Called on error
}Example - Performance Monitoring
const performanceMiddleware = {
before: async (command) => {
command._startTime = Date.now();
console.log(`[${command.metadata.commandName}] Starting...`);
},
after: async (command, response) => {
const duration = Date.now() - command._startTime;
console.log(`[${command.metadata.commandName}] Completed in ${duration}ms`);
},
onError: async (command, error) => {
const duration = Date.now() - command._startTime;
console.error(`[${command.metadata.commandName}] Failed after ${duration}ms:`, error.message);
}
};
const client = createInstance({
secret: 'testing123',
signee: 'TESTING',
baseUrl: 'https://example.com',
tenantId: 'testing',
middlewares: [performanceMiddleware]
});Using Multiple Middleware
You can combine multiple middleware together. They execute in the order provided:
const client = createInstance({
secret: 'testing123',
signee: 'TESTING',
baseUrl: 'https://example.com',
tenantId: 'testing',
middlewares: [
createLoggingMiddleware(console), // Logs commands
createMetricsMiddleware(metricsClient), // Tracks metrics
performanceMiddleware // Custom performance tracking
]
});Execution Order
- All
beforehooks run in order - Command executes
- All
afterhooks run in reverse order (oronErrorif command fails)