Package Exports
- @rodrigopsasaki/vision-express
Readme
@rodrigopsasaki/vision-express
Express middleware for seamless Vision context integration. Automatically creates structured observability contexts for HTTP requests with intelligent defaults and simplified configuration.
Features
- Just Works Out of the Box: No configuration required - intelligent defaults handle everything
- Smart User Detection: Automatically detects users from common authentication patterns
- Smart Correlation ID Detection: Finds correlation IDs from common headers
- Security by Default: Sensitive data is automatically redacted
- Automatic Context Creation: Every HTTP request gets wrapped in a Vision context
- Comprehensive Metadata Capture: Request/response data, headers, timing, errors
- Route Exclusion: Health checks and metrics endpoints excluded by default
- TypeScript Support: Full type safety with extended Express interfaces
- Error Handling: Automatic error capture and context preservation
Installation
npm install @rodrigopsasaki/vision-express
npm install @rodrigopsasaki/vision
Quick Start
import express from "express";
import { vision } from "@rodrigopsasaki/vision";
import { visionMiddleware } from "@rodrigopsasaki/vision-express";
const app = express();
// Initialize Vision with exporters
vision.init({
exporters: [
// Your exporters here
],
});
// Add the Vision middleware - just works out of the box!
app.use(visionMiddleware());
// Your routes now have automatic context tracking
app.get("/users/:id", async (req, res) => {
// Add custom data to the context
vision.set("user_id", req.params.id);
vision.set("operation", "get_user");
const user = await getUser(req.params.id);
res.json(user);
});
API Reference
visionMiddleware(options?)
The recommended default middleware - just works out of the box with intelligent defaults.
import { visionMiddleware } from "@rodrigopsasaki/vision-express";
// Basic usage - no configuration needed
app.use(visionMiddleware());
// With custom options
app.use(
visionMiddleware({
captureBody: true,
excludeRoutes: ["/health", "/metrics"],
extractUser: (req) => req.headers["x-user-id"],
}),
);
createVisionMiddleware(options?)
Creates a Vision Express middleware with custom configuration.
import { createVisionMiddleware } from "@rodrigopsasaki/vision-express";
app.use(
createVisionMiddleware({
captureBody: true,
excludeRoutes: ["/health", "/metrics"],
extractUser: (req) => req.user,
}),
);
createMinimalVisionMiddleware()
Creates a middleware with no Express metadata capture - perfect for when you want Vision context but no Express clutter.
import { createMinimalVisionMiddleware } from "@rodrigopsasaki/vision-express";
app.use(createMinimalVisionMiddleware());
createComprehensiveVisionMiddleware()
Creates a middleware that captures all available data including request bodies (use with caution).
import { createComprehensiveVisionMiddleware } from "@rodrigopsasaki/vision-express";
app.use(createComprehensiveVisionMiddleware());
createSecureVisionMiddleware()
Creates a middleware with extra security redaction - perfect for high-security applications.
import { createSecureVisionMiddleware } from "@rodrigopsasaki/vision-express";
app.use(createSecureVisionMiddleware());
Configuration Options
Basic Options
Option | Type | Default | Description |
---|---|---|---|
enabled |
boolean |
true |
Whether the middleware is enabled |
excludeRoutes |
string[] |
["/health", "/metrics", "/status", "/favicon.ico"] |
Routes to exclude from tracking |
captureHeaders |
boolean |
true |
Capture request headers |
captureQueryParams |
boolean |
true |
Capture query parameters |
captureBody |
boolean |
false |
Capture request body (off by default for security) |
Smart Detection Options
Option | Type | Default | Description |
---|---|---|---|
extractUser |
(req) => unknown |
Smart detection | Extract user from common patterns |
correlationIdHeaders |
string[] |
Common headers | Headers to check for correlation IDs |
Security Options
Option | Type | Default | Description |
---|---|---|---|
redactHeaders |
string[] |
Sensitive headers | Headers to redact |
redactQueryParams |
string[] |
Sensitive params | Query params to redact |
redactBodyFields |
string[] |
Sensitive fields | Body fields to redact |
Response Options
Option | Type | Default | Description |
---|---|---|---|
includeRequestId |
boolean |
true |
Add request ID to response headers |
requestIdHeader |
string |
X-Request-ID |
Header name for request ID |
Smart Defaults
User Detection
The middleware automatically tries to extract user information from common patterns:
// Tries these in order:
req.user; // Passport.js, JWT middleware
req.session.user; // Session-based auth
req.headers["x-user-id"]; // Custom header
req.headers["x-user"]; // Custom header
Correlation ID Detection
Automatically finds correlation IDs from common headers:
// Tries these headers in order:
"x-correlation-id";
"x-request-id";
"x-trace-id";
"x-transaction-id";
"correlation-id";
"request-id";
Security Redaction
By default, these fields are automatically redacted:
Headers:
authorization
cookie
x-api-key
x-auth-token
x-session-token
x-csrf-token
Query Parameters:
token
key
secret
password
auth
api_key
Body Fields:
password
ssn
credit_card
secret
api_key
private_key
Usage Examples
Basic Usage (Recommended)
import express from "express";
import { vision } from "@rodrigopsasaki/vision";
import { visionMiddleware } from "@rodrigopsasaki/vision-express";
const app = express();
// Initialize Vision
vision.init({
exporters: [
{
name: "console",
success: (ctx) => console.log("Request completed:", ctx),
error: (ctx, err) => console.error("Request failed:", ctx, err),
},
],
});
// Add middleware - just works out of the box!
app.use(visionMiddleware());
// Your routes
app.get("/api/users/:id", async (req, res) => {
vision.set("user_id", req.params.id);
vision.set("operation", "get_user");
const user = await getUser(req.params.id);
res.json(user);
});
Custom Configuration
import express from "express";
import { visionMiddleware } from "@rodrigopsasaki/vision-express";
const app = express();
app.use(
visionMiddleware({
// Enable body capture for development
captureBody: true,
// Exclude additional routes
excludeRoutes: ["/health", "/metrics", "/status", "/static", "/favicon.ico"],
// Custom user extraction
extractUser: (req) => (req as any).user || req.headers["x-user-id"],
// Custom correlation ID headers
correlationIdHeaders: ["x-correlation-id", "x-request-id", "x-trace-id"],
// Additional security redaction
redactHeaders: [
"authorization",
"cookie",
"x-api-key",
"x-auth-token",
"x-session-token",
"x-csrf-token",
],
redactQueryParams: ["token", "key", "secret", "password", "auth"],
redactBodyFields: ["password", "ssn", "credit_card", "secret", "api_key"],
}),
);
Different Middleware Options
import express from "express";
import {
visionMiddleware,
createMinimalVisionMiddleware,
createComprehensiveVisionMiddleware,
createSecureVisionMiddleware,
} from "@rodrigopsasaki/vision-express";
const app = express();
// Option 1: Simple Vision (default) - just works out of the box
app.use(visionMiddleware());
// Option 2: Minimal Vision - no Express metadata clutter
app.use(createMinimalVisionMiddleware());
// Option 3: Comprehensive Vision - everything including body
app.use(createComprehensiveVisionMiddleware());
// Option 4: Secure Vision - extra security protection
app.use(createSecureVisionMiddleware());
Accessing Context in Routes
import type { VisionRequest } from "@rodrigopsasaki/vision-express";
app.get("/users/:id", async (req: VisionRequest, res) => {
// Access the Vision context
const ctx = req.visionContext;
console.log("Request ID:", ctx.id);
// Add data to the context
vision.set("user_id", req.params.id);
vision.set("operation", "get_user");
vision.set("timestamp", new Date().toISOString());
// Add structured data
vision.merge("request", {
method: req.method,
path: req.path,
query: req.query,
});
// Add to arrays
vision.push("events", "user_lookup_started");
const user = await getUser(req.params.id);
vision.push("events", "user_lookup_completed");
vision.set("result_count", 1);
res.json(user);
});
Testing with Headers
# Basic request
curl http://localhost:3000/users/123
# With correlation ID
curl -H "X-Correlation-ID: test-123" http://localhost:3000/users/123
# With user context
curl -H "X-User-ID: user-456" http://localhost:3000/users/123
# With sensitive data (automatically redacted)
curl -H "Authorization: Bearer secret-token" \
-H "Cookie: session=abc123" \
"http://localhost:3000/users/123?token=secret&password=123456"
Captured Data
The middleware automatically captures the following data:
Request Data
- HTTP method and path
- Request headers (with automatic redaction)
- Query parameters (with automatic redaction)
- Request body (optional, with automatic redaction)
- Correlation ID (if found in headers)
- User information (if found)
Response Data
- Status code
- Response headers
- Duration (timing)
TypeScript Support
The package provides extended Express interfaces:
import type { VisionRequest, VisionResponse } from "@rodrigopsasaki/vision-express";
app.get("/users/:id", (req: VisionRequest, res: VisionResponse) => {
// req.visionContext is available
const ctx = req.visionContext;
// Add data to context
vision.set("user_id", req.params.id);
});
Security Considerations
- Request Bodies: Disabled by default to prevent logging sensitive data
- Automatic Redaction: Common sensitive fields are redacted by default
- Custom Redaction: Configure which fields to redact based on your needs
- Route Exclusion: Health checks and metrics endpoints excluded by default
Best Practices
- Use Default Middleware: Start with
visionMiddleware()
- it just works - Initialize Vision First: Always initialize Vision with exporters before adding the middleware
- Customize When Needed: Only configure options when you need to override defaults
- Use Route Exclusion: Add custom routes to exclude if needed
- Review Redaction: Ensure sensitive data is properly redacted for your use case
- Handle Errors Gracefully: Let Vision capture errors automatically
- Use TypeScript: Leverage the provided types for better development experience
Integration with Exporters
The middleware works seamlessly with any Vision exporter:
import { vision } from "@rodrigopsasaki/vision";
import { createDatadogExporter } from "@rodrigopsasaki/vision-datadog-exporter";
// Initialize with exporters
vision.init({
exporters: [
createDatadogExporter({
apiKey: process.env.DATADOG_API_KEY,
service: "my-api",
}),
],
});
// Add middleware - just works!
app.use(visionMiddleware());
License
MIT