CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-express-http-proxy

Express middleware for proxying HTTP requests to another host and passing the response back to the original caller

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

filtering.mddocs/

Request Filtering

Control which requests get proxied and how proxy responses are handled using filter functions and conditional logic. The filtering system supports both synchronous and Promise-based async operations.

Capabilities

Request Filter

Determine whether a request should be proxied. Return true to continue with proxying, or false to skip proxying and call next().

/**
 * Filter function to determine whether to proxy the request
 * @param {object} req - Express request object
 * @param {object} res - Express response object
 * @returns {boolean|Promise<boolean>} True to proxy, false to skip
 */
filter: (req, res) => boolean | Promise<boolean>;

Usage Examples:

const proxy = require('express-http-proxy');

// Method-based filtering
app.use('/api', proxy('backend.example.com', {
  filter: function(req, res) {
    // Only proxy GET requests
    return req.method === 'GET';
  }
}));

// Authentication-based filtering
app.use('/secure', proxy('secure-api.com', {
  filter: function(req, res) {
    // Only proxy authenticated requests
    return req.headers.authorization && req.user && req.user.isAuthenticated;
  }
}));

// Path-based filtering
app.use('/conditional', proxy('api.example.com', {
  filter: function(req, res) {
    // Skip certain paths
    const skipPaths = ['/health', '/metrics', '/status'];
    return !skipPaths.some(path => req.path.startsWith(path));
  }
}));

// Header-based filtering
app.use('/versioned', proxy('api-v2.example.com', {
  filter: function(req, res) {
    // Only proxy requests with specific API version
    return req.headers['api-version'] === '2.0';
  }
}));

Promise-Based Request Filtering

Use Promises for asynchronous filtering operations that require database lookups, external service calls, or other async operations.

/**
 * Promise-based filter function for async filtering logic
 * @param {object} req - Express request object
 * @param {object} res - Express response object
 * @returns {Promise<boolean>} Promise resolving to true (proxy) or false (skip)
 */
filter: (req, res) => Promise<boolean>;

Usage Examples:

// Database-driven filtering
app.use('/restricted', proxy('restricted-api.com', {
  filter: async function(req, res) {
    const userId = req.user?.id;
    if (!userId) return false;
    
    // Check user permissions in database
    const hasAccess = await db.checkUserAccess(userId, 'restricted-api');
    return hasAccess;
  }
}));

// Rate limiting with async check
app.use('/throttled', proxy('api.example.com', {
  filter: function(req, res) {
    return new Promise((resolve) => {
      const clientId = req.headers['x-client-id'];
      
      rateLimiter.checkLimit(clientId)
        .then(withinLimit => {
          resolve(withinLimit);
        })
        .catch(() => {
          // Default to allow on rate limiter errors
          resolve(true);
        });
    });
  }
}));

// External service validation
app.use('/validated', proxy('validated-api.com', {
  filter: async function(req, res) {
    try {
      const token = req.headers.authorization?.replace('Bearer ', '');
      const isValid = await authService.validateToken(token);
      return isValid;
    } catch (error) {
      console.error('Token validation error:', error);
      return false;
    }
  }
}));

Skip to Next Handler Filter

Inspect the proxy response and decide whether to continue processing through express-http-proxy or call next() to return control to Express.

/**
 * Inspect proxy response and decide whether to continue processing
 * @param {object} proxyRes - The proxy response object
 * @returns {boolean|Promise<boolean>} True to skip to next handler, false to continue processing
 */
skipToNextHandlerFilter: (proxyRes) => boolean | Promise<boolean>;

Usage Examples:

// Status code-based skipping
app.use('/fallback', proxy('primary-api.com', {
  skipToNextHandlerFilter: function(proxyRes) {
    // Skip to next handler for 404 responses
    return proxyRes.statusCode === 404;
  }
}));

// Handle specific error conditions
app.use('/resilient', proxy('unreliable-api.com', {
  skipToNextHandlerFilter: function(proxyRes) {
    // Skip processing for server errors and timeouts
    return proxyRes.statusCode >= 500 || proxyRes.statusCode === 408;
  }
}));

// Content-type based routing
app.use('/dynamic', proxy('api.example.com', {
  skipToNextHandlerFilter: function(proxyRes) {
    // Let Express handle non-JSON responses
    const contentType = proxyRes.headers['content-type'];
    return !contentType || !contentType.includes('application/json');
  }
}));

Promise-Based Skip Filter

Use Promises for asynchronous decision-making based on proxy response analysis.

/**
 * Promise-based skip filter for async response analysis
 * @param {object} proxyRes - The proxy response object
 * @returns {Promise<boolean>} Promise resolving to true (skip) or false (continue)
 */
skipToNextHandlerFilter: (proxyRes) => Promise<boolean>;

Usage Examples:

// Async response validation
app.use('/validated-response', proxy('api.example.com', {
  skipToNextHandlerFilter: async function(proxyRes) {
    // Skip if response doesn't meet quality criteria
    if (proxyRes.statusCode !== 200) return true;
    
    try {
      // Validate response with external service
      const isValidResponse = await responseValidator.validate(proxyRes);
      return !isValidResponse; // Skip if invalid
    } catch (error) {
      console.error('Response validation error:', error);
      return true; // Skip on validation errors
    }
  }
}));

// Circuit breaker pattern
app.use('/circuit-breaker', proxy('monitored-api.com', {
  skipToNextHandlerFilter: function(proxyRes) {
    return new Promise((resolve) => {
      // Check circuit breaker status
      circuitBreaker.shouldSkip(proxyRes.statusCode)
        .then(shouldSkip => {
          if (shouldSkip) {
            console.log('Circuit breaker activated, skipping proxy');
          }
          resolve(shouldSkip);
        })
        .catch(() => resolve(false)); // Continue on error
    });
  }
}));

Filter Behavior and Promise Handling

Success Path vs Error Path

For both filter and skipToNextHandlerFilter:

  • resolve(false) or return false: Executes the "happy path" (continue processing)
  • resolve(true) or return true: Skips the rest of proxy processing and calls next()
  • reject() or thrown error: Also skips proxy processing and calls next()

Filter Execution Order

  1. filter: Executed first, before any proxy processing begins
  2. Proxy request processing: Only if filter returns true
  3. skipToNextHandlerFilter: Executed after receiving proxy response

Combining Filters

app.use('/complex', proxy('api.example.com', {
  // Pre-request filtering
  filter: async function(req, res) {
    // Check authentication
    if (!req.user) return false;
    
    // Check rate limits
    const withinLimits = await rateLimiter.check(req.user.id);
    return withinLimits;
  },
  
  // Post-response filtering
  skipToNextHandlerFilter: function(proxyRes) {
    // Handle errors by skipping to Express error handling
    if (proxyRes.statusCode >= 400) {
      console.log('Proxy returned error status:', proxyRes.statusCode);
      return true; // Skip to next handler
    }
    return false; // Continue processing
  }
}));

Performance Considerations

Streaming Impact

Note that defining skipToNextHandlerFilter disables streaming mode, which may impact performance with large payloads since responses must be buffered for inspection.

Error Handling

app.use('/error-handling', proxy('api.example.com', {
  filter: function(req, res) {
    try {
      // Your filtering logic here
      return someConditionCheck(req);
    } catch (error) {
      console.error('Filter error:', error);
      return false; // Default to not proxying on error
    }
  }
}));

docs

body-processing.md

error-handling.md

filtering.md

index.md

network-configuration.md

path-resolution.md

request-modification.md

response-processing.md

tile.json