High performance middleware framework for Node.js HTTP servers
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Connect is an extensible HTTP server framework for Node.js using middleware to handle requests. It provides a minimalist foundation for building web applications, APIs, and HTTP services through a composable middleware stack architecture.
npm install connectconst connect = require("connect");For ES modules:
import connect from "connect";const connect = require("connect");
const http = require("http");
// Create app
const app = connect();
// Add middleware
app.use(function(req, res, next) {
res.writeHead(200, { "Content-Type": "text/plain" });
res.end("Hello from Connect!");
});
// Start server
app.listen(3000);
// or: http.createServer(app).listen(3000);Connect implements a middleware stack pattern where:
setImmediate (or process.nextTick fallback) for non-blocking flowfinalhandler module for unhandled requests/errorsCreates a new Connect application instance that can handle HTTP requests.
/**
* Create a new Connect server application
* @returns {Function} Connect app function with middleware capabilities
*/
function connect();The returned app is both a function (req, res, next) => void and an object with methods.
Adds middleware functions to the application stack for processing requests.
/**
* Add middleware function to the app stack
* @param {string} [route] - Optional path to mount middleware on (defaults to '/')
* @param {Function|Server} fn - Middleware function, HTTP server, or Connect app
* @returns {Function} The app instance for chaining
*/
app.use([route], fn);
/**
* Add middleware function to the app stack (no route)
* @param {Function|Server} fn - Middleware function, HTTP server, or Connect app
* @returns {Function} The app instance for chaining
*/
app.use(fn);Usage Examples:
// Basic middleware
app.use(function(req, res, next) {
console.log("Request:", req.method, req.url);
next();
});
// Path-mounted middleware
app.use("/api", function(req, res, next) {
// Only handles requests starting with /api
// req.url is modified: "/api/users" becomes "/users"
// req.originalUrl preserves original: "/api/users"
next();
});
// Mounting other Connect apps
const adminApp = connect();
adminApp.use(function(req, res, next) {
res.end("Admin section");
});
app.use("/admin", adminApp);
// Mounting HTTP servers
const http = require("http");
const staticServer = http.createServer(/* static handler */);
app.use("/static", staticServer);
// Error-handling middleware (4 parameters)
app.use(function(err, req, res, next) {
console.error(err.stack);
res.statusCode = 500;
res.end("Internal Server Error");
});
// Chaining
app.use(middleware1).use("/admin", middleware2);Processes HTTP requests through the middleware stack. Connect automatically sets req.originalUrl to preserve the original URL and manipulates req.url for mounted middleware.
/**
* Handle HTTP requests through middleware stack
* @param {IncomingMessage} req - Node.js HTTP request object
* @param {ServerResponse} res - Node.js HTTP response object
* @param {Function} [out] - Optional callback for unhandled requests or errors
*/
app.handle(req, res, [out]);
/**
* Alias for app.handle - app itself is callable
* @param {IncomingMessage} req - Node.js HTTP request object
* @param {ServerResponse} res - Node.js HTTP response object
* @param {Function} [next] - Optional callback for unhandled requests
*/
app(req, res, [next]);URL Manipulation Behavior:
When middleware is mounted on a route, Connect modifies the request URL:
req.originalUrl is set to the full original URL (only set once)req.url is modified to remove the mounted path/) or dot (.) boundariesapp.use("/api/v1", function(req, res, next) {
// Request to "/api/v1/users/123"
console.log(req.originalUrl); // "/api/v1/users/123"
console.log(req.url); // "/users/123"
next();
});
// Route boundary examples:
app.use("/foo", handler); // Matches: /foo, /foo/, /foo/bar, /foo.bar
// Does NOT match: /foobarCreates and starts an HTTP server using the Connect app as the request handler.
/**
* Start HTTP server listening for requests
* @param {...*} args - Same arguments as Node.js http.Server.listen()
* @returns {Server} Node.js HTTP server instance
*/
app.listen(...args);Usage Examples:
// Listen on port 3000
const server = app.listen(3000);
// Listen with hostname and callback
app.listen(3000, "localhost", function() {
console.log("Server running on http://localhost:3000");
});
// Using http.createServer directly
const http = require("http");
const server = http.createServer(app);
server.listen(3000);Connect apps inherit from EventEmitter and can emit/listen for events.
/**
* Add event listener (inherited from EventEmitter)
* @param {string} event - Event name
* @param {Function} listener - Event listener function
* @returns {Function} The app instance
*/
app.on(event, listener);
/**
* Emit event (inherited from EventEmitter)
* @param {string} event - Event name
* @param {...*} args - Arguments to pass to listeners
* @returns {boolean} Whether event had listeners
*/
app.emit(event, ...args);Usage Examples:
// Listen for custom events
app.on("user:login", function(user) {
console.log("User logged in:", user.name);
});
// Emit events from middleware
app.use(function(req, res, next) {
if (req.url === "/login") {
app.emit("user:login", { name: "John" });
}
next();
});/**
* Standard middleware function
* @param {IncomingMessage} req - HTTP request object
* @param {ServerResponse} res - HTTP response object
* @param {Function} next - Call to continue to next middleware or pass error
*/
function middleware(req, res, next);
/**
* Error-handling middleware function (4 parameters)
* @param {Error} err - Error object from previous middleware
* @param {IncomingMessage} req - HTTP request object
* @param {ServerResponse} res - HTTP response object
* @param {Function} next - Call to continue to next error handler or pass error
*/
function errorMiddleware(err, req, res, next);/**
* Connect app properties
*/
interface ConnectApp {
/** Middleware stack array (internal, but publicly accessible) */
stack: Array<{route: string, handle: Function}>;
/** Mount route path (defaults to '/') */
route: string;
/** Alias for app.handle */
(req: IncomingMessage, res: ServerResponse, next?: Function): void;
/** Add middleware to the stack */
use(fn: Function): ConnectApp;
use(route: string, fn: Function): ConnectApp;
/** Handle requests through middleware stack */
handle(req: IncomingMessage, res: ServerResponse, out?: Function): void;
/** Start HTTP server */
listen(...args: any[]): http.Server;
/** Event emitter methods (inherited) */
on(event: string, listener: Function): ConnectApp;
emit(event: string, ...args: any[]): boolean;
}
/**
* Enhanced request object (Node.js IncomingMessage with Connect additions)
*/
interface ConnectRequest extends IncomingMessage {
/** Original URL before any modifications (set by Connect) */
originalUrl?: string;
}Connect uses a special error-handling pattern:
next(error) to pass errors to error handlers(err, req, res, next) handle errorsfinalhandler module if no error middleware handles the error// Middleware that might error
app.use(function(req, res, next) {
if (req.url === "/error") {
return next(new Error("Something went wrong"));
}
next();
});
// Error handler
app.use(function(err, req, res, next) {
res.statusCode = 500;
res.end("Error: " + err.message);
});Complex Error Handling Examples:
// Multiple error handlers for different error types
app.use(function(req, res, next) {
if (req.url === "/auth-error") {
const err = new Error("Unauthorized");
err.status = 401;
return next(err);
}
next();
});
// Handle auth errors specifically
app.use(function(err, req, res, next) {
if (err.status === 401) {
res.statusCode = 401;
res.setHeader("Content-Type", "application/json");
res.end(JSON.stringify({ error: "Unauthorized access" }));
return;
}
next(err); // Pass to next error handler
});
// General error handler (should be last)
app.use(function(err, req, res, next) {
console.error(err.stack);
res.statusCode = err.status || 500;
res.end("Internal Server Error");
});Connect apps can be mounted as middleware in other Connect apps, creating modular application structures.
const main = connect();
const admin = connect();
const api = connect();
// Build admin sub-app
admin.use(function(req, res, next) {
// Admin authentication middleware
if (!req.headers.authorization) {
res.statusCode = 401;
res.end("Unauthorized");
return;
}
next();
});
admin.use(function(req, res, next) {
res.end("Admin Dashboard: " + req.url);
});
// Build API sub-app
api.use(function(req, res, next) {
res.setHeader("Content-Type", "application/json");
next();
});
api.use("/users", function(req, res, next) {
res.end(JSON.stringify({ users: [] }));
});
// Mount sub-apps in main app
main.use("/admin", admin); // All /admin/* requests go to admin app
main.use("/api", api); // All /api/* requests go to api app
// Main app middleware
main.use(function(req, res, next) {
res.end("Main app: " + req.url);
});Connect apps work with any Node.js HTTP server and can be combined with other server technologies.
const https = require("https");
const http2 = require("http2");
const fs = require("fs");
// HTTPS server
const httpsOptions = {
key: fs.readFileSync("private-key.pem"),
cert: fs.readFileSync("certificate.pem")
};
https.createServer(httpsOptions, app).listen(443);
// HTTP/2 server
const http2Server = http2.createSecureServer(httpsOptions, app);
http2Server.listen(8443);
// Multiple servers with same app
const httpServer = http.createServer(app);
const httpsServer = https.createServer(httpsOptions, app);
httpServer.listen(80);
httpsServer.listen(443);// Conditional routing based on request properties
app.use(function(req, res, next) {
if (req.method === "POST" && req.url.startsWith("/api/")) {
// Handle API POST requests differently
res.setHeader("Content-Type", "application/json");
}
next();
});
// Route parameter extraction (manual)
app.use("/users", function(req, res, next) {
// req.url is "/123" for request to "/users/123"
const userId = req.url.slice(1); // Remove leading slash
if (userId && /^\d+$/.test(userId)) {
req.userId = userId;
}
next();
});
// Multiple route patterns
app.use("/api/v1", apiV1Handler);
app.use("/api/v2", apiV2Handler);
app.use("/api", function(req, res, next) {
// Catch-all for other API routes
res.statusCode = 404;
res.end("API version not found");
});Connect processes requests through several internal steps:
req.originalUrl is set to preserve the original request URLstack arrayreq.url is temporarily modifiedfinalhandler// Route matching follows specific rules:
app.use("/foo", handler);
// Matches these URLs:
// "/foo" - exact match
// "/foo/" - with trailing slash
// "/foo/bar" - with additional path
// "/foo.html" - with dot separator
// Does NOT match:
// "/foobar" - no separator after route
// "/FOO" - case-insensitive (actually matches in Connect)Note: Route matching is case-insensitive in Connect.
Connect respects the NODE_ENV environment variable: