Request Pipeline and Middleware
Relevant source files - app.js - config/arcjet.js - controllers/user.controller.js - middlewares/arcjet.middleware.js - middlewares/auth.middleware.js - middlewares/error.middleware.js - models/subscription.model.js - models/user.model.js
This section details the sequential processing of HTTP requests within the Subscription Tracker API. The application utilizes a layered Express.js middleware stack to handle cross-cutting concerns—such as security, parsing, and error handling—before requests reach the domain-specific route handlers.
Request Lifecycle Overview
When a request hits the Express server, it passes through a series of global middlewares defined in app.js before being dispatched to specific routers. The pipeline is designed to fail fast: if a security check (Arcjet) or authentication guard fails, the request is terminated early with an appropriate HTTP status code.
Pipeline Flow Diagram
The following diagram illustrates the path of a request from the client through the middleware stack to the final response or error handler.
Request Flow through app.js
[Flowchart Diagram]
Sources:app.js16-42middlewares/arcjet.middleware.js3-36
Global Middleware Layers
The global stack is initialized in app.js and applies to every incoming request.
1. Pre-Processing and Parsing
The initial layers prepare the request object for downstream consumption:
- CORS: Configured via
cors()to allow cross-origin resource sharing app.js20 - Body Parsing:
express.json()andexpress.urlencoded()parse incoming request bodies intoreq.bodyapp.js21-22 - Cookie Parsing:
cookieParser()extracts cookie data intoreq.cookiesapp.js23 - Static Files: The
public/directory is served viaexpress.static, providing access to the API tester and Swagger assets app.js24
2. Arcjet Security Layer
The arcjetMiddleware acts as a Web Application Firewall (WAF) and rate limiter. It is placed after the parsers but before the routes to protect the API endpoints.
- Bypass Logic: To ensure availability, the middleware bypasses checks for health endpoints (
/api/v1/health), documentation (/api-docs), and non-API static routes middlewares/arcjet.middleware.js5-10 -
Protection Rules: It utilizes the
aj.protect()method with three primary rules defined inconfig/arcjet.js: -
Shield: Active WAF protection against common attacks config/arcjet.js9
- Bot Detection: Blocks malicious bots while allowing search engines config/arcjet.js10-13
- Token Bucket: Implements rate limiting with a capacity of 10 and a refill rate of 5 tokens every 10 seconds config/arcjet.js14-19
- Identification: Requests are identified by IP address, extracted from
req.ipor thex-forwarded-forheader middlewares/arcjet.middleware.js15-18
Sources:app.js25middlewares/arcjet.middleware.js3-36config/arcjet.js4-21
Authentication and Authorization Middleware
While the layers above are global, specific routes (Users, Subscriptions, Test) are protected by the authorize middleware. This middleware bridges the gap between the raw request and the authenticated req.user object.
Logic of middlewares/auth.middleware.js
sequenceDiagram
participant R as Request
participant M as authorize Middleware
participant J as jsonwebtoken
participant DB as MongoDB (User Model)
participant C as Controller
R->>M: Authorization: Bearer <token>
M->>M: Extract Token
M->>R: 401 Unauthorized
M->>J: jwt.verify(token, JWT_SECRET)
J-->>M: Decoded (userId)
M->>DB: User.findById(userId).select('-password')
DB-->>M: userDocument
M->>R: 401 Unauthorized
M->>M: req.user = userDocument
M->>C: next()
Sources:middlewares/auth.middleware.js5-35controllers/user.controller.js17
Global Error Handling
The errorMiddleware is the final layer in the pipeline, attached after all route definitions in app.jsapp.js42 It serves as a centralized catch-all for errors thrown in controllers or previous middlewares.
Specialized Error Handling
The middleware standardizes error responses by detecting specific database and validation errors:
| Error Type | Detection Criteria | Resulting Status |
|---|---|---|
| Cast Error | err.name === 'CastError' |
404 Not Found |
| Duplicate Key | err.code === 11000 |
400 Bad Request |
| Validation Error | err.name === 'ValidationError' |
400 Bad Request |
| Generic Error | Default fallback | 500 Internal Server Error |
Implementation Detail: For ValidationError, the middleware maps over the Mongoose err.errors object to concatenate all validation messages into a single string middlewares/error.middleware.js21-26