Skip to content

Express Request Enhancement

Enhanced request object functionality provided by Response Handler.

Request Enhancement Overview

Response Handler enhances the Express request object with additional properties and methods for better request handling and tracking.

Enhanced Properties

Request Tracking

Each request gets automatic tracking properties:

javascript
app.use(
  quickSetup({
    enablePerformanceTracking: true,
    requestTracking: true,
  }),
);

app.get('/api/data', (req, res) => {
  console.log('Request ID:', req.requestId);
  console.log('Start Time:', req.startTime);
  console.log('User Agent:', req.userAgent);
  console.log('IP Address:', req.clientIP);

  res.ok({ message: 'Request processed' });
});

Available Enhanced Properties

typescript
interface EnhancedRequest extends Request {
  requestId: string; // Unique request identifier
  startTime: number; // Request start timestamp
  userAgent: string; // Parsed user agent
  clientIP: string; // Client IP address
  correlationId?: string; // Request correlation ID
  sessionData?: any; // Session information
  metadata: RequestMetadata; // Additional request metadata
}

Request Metadata

Automatic Metadata Collection

javascript
app.get('/api/users', (req, res) => {
  // Access request metadata
  const metadata = req.metadata;

  console.log('Request metadata:', {
    method: metadata.method,
    url: metadata.url,
    headers: metadata.headers,
    query: metadata.query,
    body: metadata.body,
    timestamp: metadata.timestamp,
    source: metadata.source,
  });

  res.ok({ users: [] }, 'Users retrieved');
});

Custom Metadata

Add custom metadata to requests:

javascript
app.use((req, res, next) => {
  // Add custom metadata
  req.metadata.customData = {
    apiVersion: '1.0',
    clientVersion: req.headers['x-client-version'],
    feature: 'user-management',
  };

  next();
});

Request Validation

Built-in Validation Helpers

javascript
const { validateRequest } = require('response-handler');

// Custom validation middleware
const validateUserData = validateRequest({
  body: {
    name: { type: 'string', required: true, minLength: 2 },
    email: { type: 'email', required: true },
    age: { type: 'number', min: 18, max: 120 },
  },
  query: {
    page: { type: 'number', default: 1 },
    limit: { type: 'number', default: 10, max: 100 },
  },
});

app.post('/api/users', validateUserData, (req, res) => {
  // req.body and req.query are now validated and sanitized
  const userData = req.body;
  const { page, limit } = req.query;

  res.created(userData, 'User created successfully');
});

Validation Errors

javascript
app.post('/api/users', validateUserData, (req, res) => {
  // If validation fails, it automatically responds with:
  // {
  //   "success": false,
  //   "message": "Validation failed",
  //   "error": {
  //     "validationErrors": [
  //       {
  //         "field": "email",
  //         "message": "Invalid email format",
  //         "value": "invalid-email"
  //       }
  //     ]
  //   }
  // }
});

Request Sanitization

Input Sanitization

Automatic input sanitization for security:

javascript
app.use(
  quickSetup({
    enableSecurity: true,
    sanitization: {
      enabled: true,
      options: {
        removeNullBytes: true,
        trimWhitespace: true,
        escapeHtml: true,
      },
    },
  }),
);

app.post('/api/comments', (req, res) => {
  // req.body is automatically sanitized
  const comment = req.body.comment; // HTML escaped and trimmed

  res.created({ comment }, 'Comment created');
});

Custom Sanitization

javascript
const { sanitizeInput } = require('response-handler');

app.post('/api/data', (req, res) => {
  const sanitizedData = sanitizeInput(req.body, {
    allowedTags: ['b', 'i', 'em', 'strong'],
    allowedAttributes: {},
    maxLength: 1000,
  });

  res.ok(sanitizedData, 'Data processed');
});

Request Rate Limiting

Per-Request Rate Limiting

javascript
app.use(
  quickSetup({
    rateLimiting: {
      enabled: true,
      windowMs: 15 * 60 * 1000, // 15 minutes
      max: 100, // limit each IP to 100 requests per windowMs
      message: 'Too many requests',
    },
  }),
);

app.get('/api/data', (req, res) => {
  // Rate limiting info available in request
  console.log('Rate limit info:', {
    limit: req.rateLimit.limit,
    current: req.rateLimit.current,
    remaining: req.rateLimit.remaining,
    resetTime: req.rateLimit.resetTime,
  });

  res.ok({ data: 'example' });
});

Custom Rate Limiting

javascript
const customRateLimit = (req, res, next) => {
  const userId = req.user?.id;
  if (!userId) return next();

  // Implement custom user-based rate limiting
  const userLimit = getUserRateLimit(userId);
  const currentUsage = getCurrentUsage(userId);

  if (currentUsage >= userLimit) {
    return res.tooManyRequests(
      { limit: userLimit, current: currentUsage },
      'User rate limit exceeded',
    );
  }

  // Add rate limit info to request
  req.userRateLimit = {
    limit: userLimit,
    current: currentUsage,
    remaining: userLimit - currentUsage,
  };

  next();
};

Request Context

Context Management

javascript
app.use((req, res, next) => {
  // Create request context
  req.context = {
    requestId: req.requestId,
    userId: req.user?.id,
    sessionId: req.sessionID,
    traceId: req.headers['x-trace-id'],
    startTime: Date.now(),
  };

  next();
});

app.get('/api/users', async (req, res) => {
  try {
    // Pass context to services
    const users = await userService.getUsers(req.context);

    res.ok(users, 'Users retrieved', {
      context: {
        requestId: req.context.requestId,
        executionTime: Date.now() - req.context.startTime,
      },
    });
  } catch (error) {
    res.error(error, 'Failed to retrieve users');
  }
});

Request Logging

Automatic Request Logging

javascript
app.use(
  quickSetup({
    enableLogging: true,
    requestLogging: {
      enabled: true,
      includeBody: true,
      includeHeaders: ['authorization', 'content-type'],
      excludePaths: ['/health', '/metrics'],
    },
  }),
);

// Logs will include:
// {
//   "level": "info",
//   "message": "HTTP Request",
//   "requestId": "req_123",
//   "method": "POST",
//   "url": "/api/users",
//   "headers": {
//     "content-type": "application/json"
//   },
//   "body": { "name": "John" },
//   "timestamp": "2023-01-01T12:00:00Z"
// }

Custom Request Logging

javascript
app.use((req, res, next) => {
  const startTime = Date.now();

  // Log request start
  console.log(`[${req.requestId}] ${req.method} ${req.url} - Started`);

  // Log response end
  res.on('finish', () => {
    const duration = Date.now() - startTime;
    console.log(`[${req.requestId}] ${req.method} ${req.url} - ${res.statusCode} - ${duration}ms`);
  });

  next();
});

Request Caching

Request-Level Caching

javascript
const requestCache = new Map();

app.use((req, res, next) => {
  // Create cache key
  const cacheKey = `${req.method}:${req.url}:${JSON.stringify(req.query)}`;

  // Check cache
  if (requestCache.has(cacheKey)) {
    const cachedResponse = requestCache.get(cacheKey);
    return res.ok(cachedResponse.data, cachedResponse.message);
  }

  // Store original json method
  const originalJson = res.json;

  // Override json to cache response
  res.json = function (body) {
    if (res.statusCode === 200 && body.success) {
      requestCache.set(cacheKey, {
        data: body.data,
        message: body.message,
        timestamp: Date.now(),
      });

      // Clean cache after 5 minutes
      setTimeout(() => requestCache.delete(cacheKey), 5 * 60 * 1000);
    }

    return originalJson.call(this, body);
  };

  next();
});

Request Transformation

Data Transformation

javascript
const transformRequest = (transformer) => {
  return (req, res, next) => {
    if (req.body) {
      req.body = transformer(req.body);
    }
    next();
  };
};

// Transform camelCase to snake_case
const camelToSnake = transformRequest((data) => {
  return Object.keys(data).reduce((acc, key) => {
    const snakeKey = key.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
    acc[snakeKey] = data[key];
    return acc;
  }, {});
});

app.post('/api/users', camelToSnake, (req, res) => {
  // req.body.firstName becomes req.body.first_name
  console.log(req.body); // { first_name: "John", last_name: "Doe" }

  res.created(req.body, 'User created');
});

Request Hooks

Before/After Hooks

javascript
app.use(
  quickSetup({
    hooks: {
      beforeRequest: (req, res, next) => {
        req.processingStartTime = Date.now();
        console.log(`Processing request: ${req.method} ${req.url}`);
        next();
      },
      afterRequest: (req, res) => {
        const processingTime = Date.now() - req.processingStartTime;
        console.log(`Request processed in ${processingTime}ms`);
      },
    },
  }),
);

Security Enhancements

Security Headers

javascript
app.use(
  quickSetup({
    enableSecurity: true,
    securityHeaders: {
      contentSecurityPolicy: true,
      xssProtection: true,
      noSniff: true,
      frameguard: true,
      hsts: true,
    },
  }),
);

app.get('/api/data', (req, res) => {
  // Security headers automatically added
  res.ok({ data: 'secure' });
});

Request Fingerprinting

javascript
app.use((req, res, next) => {
  // Create request fingerprint for security
  req.fingerprint = {
    ip: req.clientIP,
    userAgent: req.userAgent,
    acceptLanguage: req.headers['accept-language'],
    hash: generateFingerprint(req),
  };

  next();
});

Performance Monitoring

Request Performance Tracking

javascript
app.use(
  quickSetup({
    enablePerformanceTracking: true,
    performanceMetrics: {
      trackRequestSize: true,
      trackResponseSize: true,
      trackProcessingTime: true,
      trackMemoryUsage: true,
    },
  }),
);

app.get('/api/performance', (req, res) => {
  const metrics = {
    requestSize: req.metrics.requestSize,
    processingTime: req.metrics.processingTime,
    memoryUsage: req.metrics.memoryUsage,
  };

  res.ok(metrics, 'Performance metrics');
});

The enhanced request object provides powerful capabilities for building robust, secure, and performant applications with comprehensive request handling and monitoring.

Released under the ISC License.