Middleware Reference
NeuroLink server adapters provide a comprehensive set of middleware components for common server operations. All middleware follows a consistent pattern and can be composed together for your specific use case.
Middleware Overview
| Middleware | Purpose | Order |
|---|---|---|
createTimingMiddleware() | Measures request duration | 0 |
createRequestIdMiddleware() | Generates/propagates request IDs | 0 |
createErrorHandlingMiddleware() | Centralized error catching and formatting | 1 |
createSecurityHeadersMiddleware() | Adds security headers | 2 |
createLoggingMiddleware() | Request/response logging | 3 |
createRateLimitMiddleware() | Rate limiting | 5 |
createAbortSignalMiddleware() | Client disconnection detection | 5 |
createCompressionMiddleware() | Response compression signaling | 5 |
createAuthMiddleware() | Authentication | 10 |
createRequestValidationMiddleware() | Request body/query/params validation | 15 |
createCacheMiddleware() | Response caching | 20 |
createMCPBodyAttachmentMiddleware() | MCP SDK body compatibility | 10 |
createDeprecationMiddleware() | RFC 8594 deprecation headers | 100 |
The order value determines execution sequence - lower numbers run first.
Timing Middleware
Measures request duration and adds timing headers to responses.
Usage
import { createTimingMiddleware } from "@juspay/neurolink";
server.registerMiddleware(createTimingMiddleware());
Headers Set
| Header | Description | Example |
|---|---|---|
X-Response-Time | Total request processing time in milliseconds | 45.23ms |
Server-Timing | Standard Server-Timing header for performance monitoring | total;dur=45.23 |
When to Use
- Always recommended for production servers
- Essential for performance monitoring and debugging
- Works with browser Developer Tools and APM systems
Request ID Middleware
Ensures every request has a unique identifier for tracing and debugging.
Configuration
type RequestIdOptions = {
/** Header name to check for existing ID (default: "x-request-id") */
headerName?: string;
/** Prefix for generated IDs (default: "req") */
prefix?: string;
/** Custom ID generator function */
generator?: () => string;
};
Usage
import { createRequestIdMiddleware } from "@juspay/neurolink";
// Basic usage
server.registerMiddleware(createRequestIdMiddleware());
// With custom options
server.registerMiddleware(
createRequestIdMiddleware({
headerName: "x-correlation-id",
prefix: "neuro",
generator: () => `neuro-${crypto.randomUUID()}`,
}),
);
Headers
| Header | Direction | Description |
|---|---|---|
X-Request-ID | Request | Propagates existing ID from client (if present) |
X-Request-ID | Response | Returns request ID for client-side correlation |
When to Use
- Always recommended for production servers
- Essential for distributed tracing
- Enables log correlation across services
- Helps with debugging and support tickets
Error Handling Middleware
Catches errors and formats them consistently across all routes.
Configuration
type ErrorHandlingOptions = {
/** Include stack trace in error response (default: false) */
includeStack?: boolean;
/** Custom error handler function */
onError?: (error: Error, ctx: ServerContext) => unknown;
/** Log errors to console (default: true) */
logErrors?: boolean;
};
Usage
import { createErrorHandlingMiddleware } from "@juspay/neurolink";
// Basic usage
server.registerMiddleware(createErrorHandlingMiddleware());
// Development mode with stack traces
server.registerMiddleware(
createErrorHandlingMiddleware({
includeStack: process.env.NODE_ENV === "development",
logErrors: true,
}),
);
// With custom error handler
server.registerMiddleware(
createErrorHandlingMiddleware({
onError: (error, ctx) => ({
error: {
code: "CUSTOM_ERROR",
message: error.message,
requestId: ctx.requestId,
},
}),
}),
);
Error Response Format
{
"error": {
"code": "HTTP_500",
"message": "Internal server error",
"stack": "Error: Something went wrong\n at ..." // Only if includeStack: true
},
"metadata": {
"requestId": "req-1706745600000-abc123",
"timestamp": "2024-02-01T12:00:00.000Z"
}
}
When to Use
- Always recommended for production servers
- Provides consistent error responses
- Prevents leaking sensitive information in production
- Enable stack traces only in development
Security Headers Middleware
Adds common security headers to protect against various web vulnerabilities.
Configuration
type SecurityHeadersOptions = {
/** Content Security Policy directive */
contentSecurityPolicy?: string;
/** X-Frame-Options (default: "DENY") */
frameOptions?: "DENY" | "SAMEORIGIN" | false;
/** X-Content-Type-Options (default: "nosniff") */
contentTypeOptions?: "nosniff" | false;
/** HSTS max-age in seconds (default: 31536000 = 1 year) */
hstsMaxAge?: number | false;
/** Referrer-Policy (default: "strict-origin-when-cross-origin") */
referrerPolicy?: string | false;
/** Additional custom headers */
customHeaders?: Record<string, string>;
};
Usage
import { createSecurityHeadersMiddleware } from "@juspay/neurolink";
// Basic usage with defaults
server.registerMiddleware(createSecurityHeadersMiddleware());
// With custom configuration
server.registerMiddleware(
createSecurityHeadersMiddleware({
contentSecurityPolicy:
"default-src 'self'; script-src 'self' 'unsafe-inline'",
frameOptions: "SAMEORIGIN",
hstsMaxAge: 63072000, // 2 years
customHeaders: {
"X-Custom-Header": "value",
},
}),
);
Headers Set
| Header | Default Value | Description |
|---|---|---|
X-Frame-Options | DENY | Prevents clickjacking |
X-Content-Type-Options | nosniff | Prevents MIME sniffing |
Strict-Transport-Security | max-age=31536000; includeSubDomains | Enforces HTTPS |
Referrer-Policy | strict-origin-when-cross-origin | Controls referrer information |
X-XSS-Protection | 1; mode=block | Legacy XSS protection |
Content-Security-Policy | Not set by default | Content security policy |
When to Use
- Always recommended for production servers
- Required for security compliance (OWASP, PCI-DSS)
- Configure CSP based on your application needs
- Disable HSTS initially if not ready for HTTPS-only
Logging Middleware
Logs request and response information with configurable detail levels.
Configuration
type LoggingOptions = {
/** Log request body (default: false) */
logBody?: boolean;
/** Log response body (default: false) */
logResponse?: boolean;
/** Custom logger instance */
logger?: {
info: (message: string, data?: unknown) => void;
error: (message: string, data?: unknown) => void;
};
/** Paths to skip logging (default: ["/health", "/ready", "/metrics"]) */
skipPaths?: string[];
};
Usage
import { createLoggingMiddleware } from "@juspay/neurolink";
// Basic usage
server.registerMiddleware(createLoggingMiddleware());
// Development mode with body logging
server.registerMiddleware(
createLoggingMiddleware({
logBody: process.env.NODE_ENV === "development",
logResponse: process.env.NODE_ENV === "development",
skipPaths: ["/api/health", "/api/ready"],
}),
);
// With custom logger (e.g., Winston, Pino)
import pino from "pino";
const logger = pino();
server.registerMiddleware(
createLoggingMiddleware({
logger: {
info: (msg, data) => logger.info(data, msg),
error: (msg, data) => logger.error(data, msg),
},
}),
);
Log Output
Request Log:
[Request] POST /api/agent/execute { requestId: "req-123", method: "POST", path: "/api/agent/execute" }
Response Log:
[Response] POST /api/agent/execute { requestId: "req-123", duration: "45ms", status: 200 }
Error Log:
[Error] POST /api/agent/execute { requestId: "req-123", duration: "12ms", error: "Invalid input", status: 400 }
When to Use
- Always recommended for production servers
- Disable body logging in production for performance and privacy
- Use structured logging (JSON) for log aggregation systems
- Skip health check endpoints to reduce noise
Compression Middleware
Signals compression preferences to adapters for response compression.
Configuration
type CompressionOptions = {
/** Minimum response size to compress in bytes (default: 1024) */
threshold?: number;
/** Content types to compress */
contentTypes?: string[];
};
Usage
import { createCompressionMiddleware } from "@juspay/neurolink";
// Basic usage
server.registerMiddleware(createCompressionMiddleware());
// With custom configuration
server.registerMiddleware(
createCompressionMiddleware({
threshold: 2048, // Only compress responses > 2KB
contentTypes: ["text/", "application/json", "application/xml"],
}),
);
How It Works
This middleware stores compression preferences in the request context metadata. The actual compression is handled by the underlying framework (Hono, Express, etc.) or a reverse proxy.
When to Use
- Recommended for responses larger than 1KB
- Works best with text-based content (JSON, HTML, XML)
- Consider disabling for already-compressed content (images, videos)
- Often handled at reverse proxy level (nginx, CloudFlare)
Abort Signal Middleware
Provides client disconnection handling for long-running requests using AbortController.
Configuration
type AbortSignalMiddlewareOptions = {
/** Callback when abort is triggered */
onAbort?: (ctx: ServerContext) => void;
/** Request timeout in milliseconds */
timeout?: number;
};
Usage
import { createAbortSignalMiddleware } from "@juspay/neurolink";
// Basic usage
server.registerMiddleware(createAbortSignalMiddleware());
// With timeout and abort callback
server.registerMiddleware(
createAbortSignalMiddleware({
timeout: 30000, // 30 seconds
onAbort: (ctx) => {
console.log(`Request ${ctx.requestId} was aborted`);
},
}),
);
Using the Abort Signal in Route Handlers
server.registerRoute({
method: "POST",
path: "/api/long-running",
handler: async (ctx) => {
const signal = ctx.abortSignal;
// Pass signal to cancellable operations
const result = await longRunningOperation({ signal });
// Check if aborted before continuing
if (signal?.aborted) {
throw new Error("Request was cancelled");
}
return result;
},
});
Express-Specific Middleware
For Express applications, use the specialized Express middleware:
import { createExpressAbortMiddleware } from "@juspay/neurolink";
app.use(
createExpressAbortMiddleware({
onAbort: () => console.log("Client disconnected"),
}),
);
app.get("/api/stream", (req, res) => {
const signal = res.locals.abortSignal;
// Use signal for cancellation
});
When to Use
- Long-running operations (AI generation, file processing)
- Streaming endpoints where client might disconnect
- Operations that should be cancelled on timeout
- Preventing resource waste on abandoned requests
MCP Body Attachment Middleware
Bridges the gap between Fastify's body parsing and the MCP SDK's body access pattern.
Usage
import { createMCPBodyAttachmentMiddleware } from "@juspay/neurolink";
// General middleware for any adapter
server.registerMiddleware(createMCPBodyAttachmentMiddleware());