Skip to content

[Middleware] Add Request Logging, Error Handling, Rate Limiting, and Request Validation Middleware #6

Description

@KarenZita01

Description

The Express application currently lacks essential middleware layers for production readiness. This issue covers the implementation of four critical middleware components: request logging, centralized error handling, rate limiting, and request validation. These middleware layers are fundamental to operating a secure, observable, and resilient API in production environments.

Request Logging Middleware: Every incoming HTTP request should be logged with a unique correlation ID, method, URL, response status code, response time (in milliseconds), and user agent. The logging should be structured (JSON format) and use the Pino logger (if available) or a similar high-performance logger. Sensitive headers like Authorization must be redacted.

Centralized Error Handling Middleware: A global error handler should catch all uncaught errors thrown in route handlers and middleware, returning consistent JSON error responses with appropriate HTTP status codes. Error types should be extended with a custom AppError class that includes a user-friendly message, an internal error code, and an HTTP status code. Development environments should include stack traces; production environments should suppress them.

Rate Limiting Middleware: Basic IP-based rate limiting should be applied globally with configurable window size and max request counts. The middleware must return a 429 Too Many Requests response with Retry-After header when the limit is exceeded. Future issues (Issue #29) will extend this to support tier-based limits.

Request Validation Middleware: A utility middleware pattern for validating request bodies, query parameters, and URL parameters against expected schemas (preferably using Zod, which will be fully adopted in Issue #8). Invalid requests should return a 400 status with detailed error messages listing which fields failed validation and why.

Technical Context & Impact

  • Dependencies: pino for logging, express-rate-limit for rate limiting, uuid for correlation IDs. Zod validation will be formally introduced in Issue [Security] Implement Input Validation with Zod Schemas and Request Sanitization #8 but the middleware pattern should anticipate it.
  • Architecture: Middleware files under src/middleware/: logger.js, errorHandler.js, rateLimiter.js, validate.js. The error handling middleware must be registered last in the middleware chain.
  • Impact: These are cross-cutting concerns that affect every request. They improve debuggability, user experience during errors, API protection from abuse, and data integrity. This issue must be completed before exposing the API to any real users or external services.

Step-by-Step Implementation Guide

  1. Install Dependencies: Run npm install pino express-rate-limit uuid. Create .env entries: LOG_LEVEL (default info), RATE_LIMIT_WINDOW_MS (default 900000), RATE_LIMIT_MAX (default 100).
  2. Create Logger Middleware: Write src/middleware/logger.js that initializes a Pino logger, generates a correlation ID via uuid.v4() for each request, attaches it to req.correlationId, and logs request start and completion with timing.
  3. Create Error Handler: Write src/middleware/errorHandler.js with class AppError extends Error containing statusCode and code properties. Export the global error handler function that returns { error: { code, message, ...(dev && { stack }) } }. Wrap async route handlers with a utility asyncHandler(fn) to catch promise rejections.
  4. Create Rate Limiter: Write src/middleware/rateLimiter.js using express-rate-limit with configurable window and max from environment variables. Include a key generator that uses IP + optional user ID if authenticated.
  5. Create Validation Middleware: Write src/middleware/validate.js exporting validate(schema, source = 'body') that returns middleware validating against a Zod schema. For now, keep it schema-agnostic but design it for Zod compatibility.
  6. Wire Middleware in index.js: Apply logger as first middleware, rate limiter early in chain, validation per-route, and error handler last. Verify ordering is correct.

Verification & Testing Steps

  1. Start the server and make a request to GET / — verify the console outputs structured JSON logs with correlation ID, method, URL, and response time.
  2. Make a request to a non-existent route (GET /nonexistent) — verify a 404 JSON response with { error: { code: "NOT_FOUND", message: "..." } }.
  3. Make requests rapidly to exceed the rate limit — verify a 429 response with Retry-After header after exceeding the max request count.
  4. Make a request with an invalid body to a validation-enabled route — verify a 400 response listing the specific validation failures.
  5. Throw an unhandled error in a route handler — verify the global error handler catches it and returns a 500 JSON response (with stack trace only in development).

Metadata

Metadata

Labels

GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardOfficial Campaign | FWC26Campaign: Official Campaign | FWC26

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions