Skip to content

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:

  1. Middleware - A wrapper that runs code before/after command execution
  2. Logger Interface - A contract defining what methods a logger object must have
  3. Custom Middleware - Your own middleware implementing the Middleware interface

Quick Comparison

ConceptWhat It IsWhen to Use
Logging MiddlewarePre-built middleware for logging commandsUse createLoggingMiddleware(logger) when you want automatic command logging
Logger InterfaceContract for logger objectsImplement this when creating a custom logger for Logging Middleware
Metrics MiddlewarePre-built middleware for tracking metricsUse createMetricsMiddleware(client) when you want to track command metrics
Custom MiddlewareBuild-your-own middlewareImplement the Middleware interface when you need custom behavior

Logging Middleware

Purpose: Automatically logs command execution details (inputs, outputs, errors).

Basic Usage (with console)

javascript
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:

typescript
// 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

javascript
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

typescript
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

typescript
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

javascript
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:

javascript
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

  1. All before hooks run in order
  2. Command executes
  3. All after hooks run in reverse order (or onError if command fails)

Released under the MIT License.