Middleware

Using middleware in Aurelia Store to intercept and transform state changes

Middleware act as an intermediary step in your application to allow you to intercept, modify, or block state changes. They run either before or after your action handlers execute, giving you powerful control over state transitions.

How Middleware Works

Middleware functions receive:

  • The current state

  • The dispatched action

  • Optional settings you provide during registration

They can:

  • Transform state by returning a new state object

  • Block actions by returning false

  • Pass through by returning undefined or nothing

  • Run asynchronously by returning a Promise

Creating Middleware

A middleware function has the following signature:

import { IStateMiddleware } from '@aurelia/state';

// Basic middleware (no settings)
const loggingMiddleware: IStateMiddleware<MyState> = (state, action, settings) => {
  console.log('Action dispatched:', action);
  console.log('Current state:', state);
  // Return undefined to pass through without changes
};

// Middleware with settings
interface ValidationSettings {
  strict: boolean;
}

const validationMiddleware: IStateMiddleware<MyState, ValidationSettings> = (state, action, settings) => {
  if (settings.strict && !isValidAction(action)) {
    return false; // Block the action
  }
  // Pass through
};

Registering Middleware

Use registerMiddleware() on the store to add middleware. Specify whether it should run 'before' or 'after' action handlers:

Common Middleware Patterns

Logging Middleware

Validation Middleware

Transform Middleware

Async Middleware

Analytics Middleware

Middleware Execution Order

When multiple middleware are registered for the same placement, they execute in registration order:

Each middleware receives the state returned by the previous middleware:

Blocking Actions

Returning false from middleware prevents the action from completing:

  • Before middleware returns false: Action handlers don't run, state isn't updated

  • After middleware returns false: State changes from handlers are discarded

Type Safety

Use TypeScript generics for type-safe middleware:

Best Practices

  1. Keep middleware focused — Each middleware should have a single responsibility

  2. Avoid side effects in 'before' middleware — Save side effects (API calls, logging) for 'after' middleware when possible

  3. Clean up middleware — Unregister middleware when components are destroyed to prevent memory leaks

  4. Handle errors gracefully — Errors in middleware are caught and logged, but the state passes through unchanged

  5. Use settings for configuration — Pass configuration via settings rather than closures for better testability

  6. Consider async implications — Async middleware can delay state updates; use sparingly for time-sensitive operations

Last updated

Was this helpful?