Skip to content

Sharing Middleware Across Endpoints ​

You can reuse the same idempotency middleware instance across multiple endpoints. This approach provides consistent configuration and shared circuit breaker monitoring across your API.

Why Share Middleware? ​

Consistent Configuration: All endpoints use the same TTL, key validation, and resilience settings.

Shared Circuit Breaker: Monitor storage health from a single state object instead of multiple instances.

Performance: Create the middleware once, use it everywhere.

How It Works ​

The middleware uses request fingerprints to distinguish operations. The fingerprint includes:

  • Request body content
  • HTTP method
  • Excluded fields (if configured)

Each endpoint naturally creates different fingerprints because they have different request bodies and paths. This means:

  • Same idempotency key on /orders → one operation
  • Same idempotency key on /payments → different operation
  • Same idempotency key on same endpoint with same body → duplicate detected

Basic Pattern ​

Create the middleware once and apply it to multiple routes:

javascript
import express from "express";
import { idempotency } from "@idempot/express-middleware";
import { PostgresIdempotencyStore } from "@idempot/postgres-store";

const app = express();
const store = new PostgresIdempotencyStore({
  connectionString: process.env.DATABASE_URL
});

// Create ONE middleware instance
const idempotencyMiddleware = idempotency({
  store,
  required: true,
  ttlMs: 24 * 60 * 60 * 1000 // 24 hours
});

// Apply to multiple endpoints
app.post("/orders", idempotencyMiddleware, createOrderHandler);
app.post("/payments", idempotencyMiddleware, processPaymentHandler);
app.post("/transfers", idempotencyMiddleware, createTransferHandler);

// Monitor circuit breaker from the shared instance
app.get("/health", (req, res) => {
  res.json({
    status: "healthy",
    circuit: idempotencyMiddleware.circuit.status
  });
});

Circuit Breaker State ​

When you share a middleware instance, the circuit breaker state is shared across all endpoints:

javascript
const middleware = idempotency({ store });

// All endpoints share this circuit state
app.post("/orders", middleware, handler);
app.post("/payments", middleware, handler);

// Check if storage is healthy
console.log(middleware.circuit.status); // 'closed', 'open', or 'half-open'

This is usually what you want—if PostgreSQL goes down, you want all endpoints to know about it and respond with 503 Service Unavailable.

When to Create Separate Instances ​

Create separate middleware instances when endpoints need different configurations:

javascript
// Short TTL for webhooks (retries happen quickly)
const webhookIdempotency = idempotency({
  store,
  ttlMs: 60 * 60 * 1000 // 1 hour
});

// Long TTL for financial operations
const paymentIdempotency = idempotency({
  store,
  ttlMs: 7 * 24 * 60 * 60 * 1000 // 7 days
});

app.post("/webhooks", webhookIdempotency, handleWebhook);
app.post("/payments", paymentIdempotency, processPayment);

Complete Example ​

See examples/express-postgres-multi-endpoint.js for a runnable Express application that demonstrates:

  • Single middleware instance protecting /orders, /payments, and /transfers
  • PostgreSQL storage with automatic table creation
  • Circuit breaker monitoring via /health endpoint
  • Curl commands to test idempotency across different endpoints

Run it with:

bash
# Set up PostgreSQL (creates table automatically)
export DATABASE_URL="postgres://user:pass@localhost:5432/mydb"

# Run the example
node examples/express-postgres-multi-endpoint.js

Framework-Specific Notes ​

Express ​

Express middleware can be reused directly:

javascript
const middleware = idempotency({ store });

app.post("/a", middleware, handlerA);
app.post("/b", middleware, handlerB);

Fastify ​

Fastify's plugin system works with shared middleware:

javascript
const middleware = idempotency({ store });

fastify.post("/a", { preHandler: middleware }, handlerA);
fastify.post("/b", { preHandler: middleware }, handlerB);

Hono ​

Hono middleware can be shared the same way:

javascript
const middleware = idempotency({ store });

app.post("/a", middleware, handlerA);
app.post("/b", middleware, handlerB);

Key Takeaway ​

Sharing middleware is safe and recommended when endpoints need the same idempotency behavior. The request fingerprinting ensures proper isolation between endpoints while giving you centralized monitoring and configuration.