15 questions found
How would you implement conditional middleware in Express that only applies to certain requests based on a runtime condition?
Advanced
Conditional middleware wraps the actual middleware logic in a function that checks a condition (a header, a feature flag, a specific route pattern) and either calls the wrapped middleware or simply calls next() directly to skip it -- useful for applying expensive or environment-specific middleware (like detailed request logging) only when actually needed, rather than unconditionally on every single request.
function conditionalMiddleware(condition, middleware) {
return (req, res, next) => condition(req) ? middleware(req, res, next) : next();
}
app.use(conditionalMiddleware(
(req) => req.headers['x-debug'] === 'true',
detailedLoggingMiddleware
));
Real-world example
An API applies its expensive, verbose request/response logging middleware only when a request includes a specific debug header, avoiding the overhead of detailed logging for the vast majority of normal production traffic while still allowing engineers to opt into detailed diagnostics for a specific troubleshooting session.
Common follow-ups: What's the performance consideration of checking a condition on every single request versus only conditionally registering middleware at startup?;How would you apply this same conditional pattern to enable a feature flag-gated middleware?
Performance Optimization & Profiling;Debugging & Diagnostics
What is the difference between res.send(), res.json(), and res.end() in Express, and when should each be used?
Intermediate
res.json() explicitly serializes the given value to JSON and sets the Content-Type header to application/json, the most explicit and predictable choice for an API response. res.send() is more general-purpose, automatically detecting the type of the given argument (a string, buffer, or object, in which case it delegates to res.json() internally) and setting an appropriate Content-Type. res.end() sends the response immediately without any body processing, typically used to end a response that's already had its body written directly via res.write(), or to send a response with genuinely no body at all.
res.json({ status: 'ok' }); // explicit JSON, Content-Type: application/json
res.send('Hello world'); // Content-Type: text/html
res.send({ status: 'ok' }); // delegates to res.json() internally
res.status(204).end(); // no body at all, just ends the response
Real-world example
An API standardizes on always using res.json() explicitly for every response (even simple ones) rather than the more ambiguous res.send(), making every response's Content-Type and serialization behavior explicit and predictable across the entire codebase.
Common follow-ups: Why might explicitly using res.json() everywhere be considered better practice than relying on res.send()'s automatic type detection?;What's the correct way to send a response with a 204 No Content status, given it shouldn't include a body at all?
RESTful API Design with Express;HTTP & Web Servers
How would you implement a middleware that adds a correlation/request ID to every incoming request for tracing purposes across a distributed system?
Advanced
A correlation-ID middleware checks for an existing ID from an incoming header (allowing the ID to be propagated from an upstream service in a microservices architecture), generating a new one if absent, attaching it to the request object (or an AsyncLocalStorage context) so every subsequent log statement and downstream call within that request can include it, and setting it on the response header so the caller can correlate their own logs with the server's.
app.use((req, res, next) => {
req.correlationId = req.headers['x-correlation-id'] || crypto.randomUUID();
res.set('x-correlation-id', req.correlationId);
next();
});
// Later, in any log statement within this request's lifecycle
logger.info(`[${req.correlationId}] Processing order`);
Real-world example
A microservices architecture propagates a single correlation ID from the initial API gateway request all the way through every downstream service call, letting an engineer search their centralized logging system for one ID and see the complete, ordered trail of what happened across every service involved in handling that one request.
Common follow-ups: How does this hand-rolled correlation ID approach compare to using a full distributed tracing system like OpenTelemetry?;How would you ensure this correlation ID survives across an asynchronous boundary like a background job triggered by the request?
Logging & Monitoring;Microservices Architecture with Node.js
What is the purpose of the express.static() built-in middleware, and how would you use it to serve a folder of static assets?
Beginner
express.static() serves files directly from a specified directory (images, CSS, client-side JavaScript, HTML) without needing a custom route handler for each individual file -- it automatically handles setting appropriate Content-Type headers, supports conditional GET requests via ETags for caching, and maps request URLs directly to file paths within the configured directory.
app.use(express.static('public'));
// A request to /images/logo.png automatically serves ./public/images/logo.png
// without needing an explicit route defined for it
Real-world example
A single-page application's Express backend serves its built frontend assets (HTML, CSS, JS bundle) directly via express.static('dist'), letting the same Node.js server that handles the API also serve the frontend, without a separate static file server.
Common follow-ups: How would you configure a custom cache duration for static assets served this way?;What's the security consideration of exposing an entire directory via express.static() if it accidentally contains sensitive files?
HTTP & HTTPS Modules;Caching
How would you implement a global request timeout middleware in Express to prevent a slow request from hanging indefinitely?
Advanced
A timeout middleware starts a timer when a request begins, and if the response hasn't been sent by the time the timer fires, it sends a timeout response (like 503 or 504) and marks the request as timed out so any later attempt by the actual handler to still respond is safely ignored -- this protects against a slow downstream dependency (a hung database query, an unresponsive third-party API) tying up server resources indefinitely.
function requestTimeout(ms) {
return (req, res, next) => {
const timer = setTimeout(() => {
if (!res.headersSent) res.status(503).json({ error: 'Request timed out' });
}, ms);
res.on('finish', () => clearTimeout(timer));
next();
};
}
app.use(requestTimeout(10000));
Real-world example
An API wraps every route with a 10-second global timeout middleware, ensuring that if a specific downstream service call hangs indefinitely due to a network issue, the affected request still returns a clear timeout error to the client rather than hanging forever and slowly exhausting server resources.
Common follow-ups: What happens to the underlying operation (like a database query) that was still in progress when the timeout fires -- does it get cancelled, or does it keep running in the background?;How would you set different timeout durations for different routes based on their expected typical response time?
Performance Optimization & Profiling;Error Handling