Advanced path filtering and routing capabilities for controlling which requests are proxied and dynamically selecting target servers.
Flexible system for filtering which requests should be proxied based on URL paths, supporting multiple filtering strategies.
/**
* Filter type supporting multiple filtering strategies
*/
type Filter<TReq = http.IncomingMessage> =
| string
| string[]
| ((pathname: string, req: TReq) => boolean);
interface PathFilterOptions<TReq> {
/** Path filter for determining which requests to proxy */
pathFilter?: Filter<TReq>;
}Path Filter Usage Examples:
import { createProxyMiddleware } from "http-proxy-middleware";
// String-based filtering - exact path match
const exactPathProxy = createProxyMiddleware({
target: "http://api.example.com",
pathFilter: "/api",
});
// Array of paths
const multiPathProxy = createProxyMiddleware({
target: "http://api.example.com",
pathFilter: ["/api", "/graphql", "/auth"],
});
// Glob pattern matching
const globProxy = createProxyMiddleware({
target: "http://api.example.com",
pathFilter: "/api/**", // Matches /api and all sub-paths
});
// Multiple glob patterns
const multiGlobProxy = createProxyMiddleware({
target: "http://api.example.com",
pathFilter: ["/api/**", "/v*/users/**", "**/*.json"],
});
// Custom function-based filtering
const customFilterProxy = createProxyMiddleware({
target: "http://api.example.com",
pathFilter: (pathname, req) => {
// Only proxy GET requests to /api paths
return pathname.startsWith("/api") && req.method === "GET";
},
});
// Advanced custom filtering with request inspection
const advancedFilterProxy = createProxyMiddleware({
target: "http://api.example.com",
pathFilter: (pathname, req) => {
// Filter based on path, method, and headers
const isApiPath = pathname.startsWith("/api");
const hasAuthHeader = req.headers.authorization;
const isJsonRequest = req.headers["content-type"]?.includes("application/json");
return isApiPath && hasAuthHeader && (req.method === "GET" || isJsonRequest);
},
});Transform request paths before forwarding them to the target server, supporting both static mappings and dynamic transformations.
/**
* Path rewrite configuration supporting static mappings and dynamic functions
*/
type PathRewrite<TReq = http.IncomingMessage> =
| { [regexp: string]: string }
| ((path: string, req: TReq) => string | undefined)
| ((path: string, req: TReq) => Promise<string>);
interface PathRewriteOptions<TReq> {
/** Configuration for rewriting request paths before forwarding */
pathRewrite?: PathRewrite<TReq>;
}Path Rewrite Usage Examples:
// Static path rewriting with regex patterns
const staticRewriteProxy = createProxyMiddleware({
target: "http://api.example.com",
pathFilter: "/api/**",
pathRewrite: {
"^/api/v1": "/v2", // Rewrite /api/v1/* to /v2/*
"^/api": "", // Remove /api prefix
"/old-endpoint": "/new-endpoint", // Direct replacement
},
});
// Function-based path rewriting
const dynamicRewriteProxy = createProxyMiddleware({
target: "http://api.example.com",
pathFilter: "/api/**",
pathRewrite: (path, req) => {
// Dynamic path transformation based on request properties
if (path.startsWith("/api/users")) {
// Add version prefix for user endpoints
return path.replace("/api/users", "/v2/users");
}
// Add tenant ID from headers to path
const tenantId = req.headers["x-tenant-id"];
if (tenantId && path.startsWith("/api/")) {
return path.replace("/api/", `/tenants/${tenantId}/api/`);
}
return path;
},
});
// Async path rewriting (useful for database lookups, etc.)
const asyncRewriteProxy = createProxyMiddleware({
target: "http://api.example.com",
pathRewrite: async (path, req) => {
// Async transformation - e.g., resolve user ID to username
if (path.startsWith("/api/users/")) {
const userId = path.split("/")[3];
if (userId && /^\d+$/.test(userId)) {
// Look up username from database
const username = await getUsernameById(userId);
return path.replace(`/users/${userId}`, `/users/${username}`);
}
}
return path;
},
});Route requests to different target servers based on request properties, supporting both static routing tables and dynamic routing functions.
/**
* Router configuration for dynamic target selection
*/
type Router<TReq = http.IncomingMessage> =
| { [hostOrPath: string]: httpProxy.ServerOptions['target'] }
| ((req: TReq) => httpProxy.ServerOptions['target'])
| ((req: TReq) => Promise<httpProxy.ServerOptions['target']>);
interface RouterOptions<TReq> {
/** Dynamic routing configuration for selecting target servers */
router?: Router<TReq>;
}Dynamic Routing Usage Examples:
// Static routing table based on host/path patterns
const staticRouterProxy = createProxyMiddleware({
router: {
// Route based on hostname
"localhost:3000": "http://localhost:8000",
"dev.example.com": "http://dev-api.example.com",
"staging.example.com": "http://staging-api.example.com",
"example.com": "http://api.example.com",
// Route based on path patterns
"/api/v1/**": "http://api-v1.example.com",
"/api/v2/**": "http://api-v2.example.com",
"/webhook/**": "http://webhook-processor.example.com",
},
});
// Function-based dynamic routing
const dynamicRouterProxy = createProxyMiddleware({
router: (req) => {
// Route based on request properties
const host = req.headers.host;
const userAgent = req.headers["user-agent"];
const apiVersion = req.headers["api-version"];
// Mobile API routing
if (userAgent?.includes("Mobile")) {
return "http://mobile-api.example.com";
}
// API version routing
if (apiVersion === "v2") {
return "http://api-v2.example.com";
}
// Environment-based routing
if (host?.includes("staging")) {
return "http://staging-api.example.com";
}
// Default routing
return "http://api.example.com";
},
});
// Async routing with external service discovery
const serviceDiscoveryProxy = createProxyMiddleware({
router: async (req) => {
const serviceName = req.headers["x-service"];
const region = req.headers["x-region"] || "us-east-1";
if (serviceName) {
// Look up service endpoint from service discovery
const endpoint = await discoverService(serviceName, region);
return endpoint;
}
// Load balancing between multiple targets
const targets = [
"http://api1.example.com",
"http://api2.example.com",
"http://api3.example.com",
];
// Simple round-robin selection (in production, use more sophisticated logic)
const index = Math.floor(Math.random() * targets.length);
return targets[index];
},
});
// Complex routing combining multiple factors
const complexRouterProxy = createProxyMiddleware({
pathFilter: "/api/**",
router: async (req) => {
const path = req.url || "";
const method = req.method;
const authHeader = req.headers.authorization;
const contentType = req.headers["content-type"];
// Route authenticated requests to secure backend
if (authHeader && authHeader.startsWith("Bearer ")) {
return "http://secure-api.example.com";
}
// Route file uploads to specialized service
if (method === "POST" && contentType?.includes("multipart/form-data")) {
return "http://upload-service.example.com";
}
// Route database queries to read replicas for GET requests
if (method === "GET" && path.includes("/data/")) {
const replicas = await getAvailableReadReplicas();
return selectLeastLoadedReplica(replicas);
}
// Default to primary API
return "http://api.example.com";
},
});Examples combining path filtering, rewriting, and dynamic routing for sophisticated proxy configurations.
Advanced Combined Usage Examples:
// Multi-service API gateway configuration
const apiGatewayProxy = createProxyMiddleware({
pathFilter: ["/api/**", "/graphql", "/auth/**"],
pathRewrite: {
"^/api/v1": "/v1",
"^/api/v2": "/v2",
"^/auth": "/authentication",
},
router: (req) => {
const path = req.url || "";
// Route to different services based on path
if (path.startsWith("/graphql")) {
return "http://graphql-service.example.com";
}
if (path.startsWith("/auth")) {
return "http://auth-service.example.com";
}
// API versioning
if (path.includes("/v1/")) {
return "http://api-v1.example.com";
}
if (path.includes("/v2/")) {
return "http://api-v2.example.com";
}
return "http://api.example.com";
},
});
// Tenant-aware routing with path modification
const tenantAwareProxy = createProxyMiddleware({
pathFilter: (pathname, req) => {
// Only proxy requests with tenant identification
return pathname.startsWith("/api/") &&
(req.headers["x-tenant-id"] || req.headers.host?.includes("tenant"));
},
pathRewrite: (path, req) => {
const tenantId = req.headers["x-tenant-id"] ||
req.headers.host?.split(".")[0];
if (tenantId && path.startsWith("/api/")) {
return path.replace("/api/", `/tenants/${tenantId}/api/`);
}
return path;
},
router: (req) => {
const tenantId = req.headers["x-tenant-id"];
// Route premium tenants to dedicated infrastructure
if (isPremiumTenant(tenantId)) {
return "http://premium-api.example.com";
}
// Route to tenant-specific backend if available
const tenantBackend = getTenantBackend(tenantId);
if (tenantBackend) {
return tenantBackend;
}
// Default multi-tenant backend
return "http://shared-api.example.com";
},
});