or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

index.mddocs/

Connect

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.

Package Information

  • Package Name: connect
  • Package Type: npm
  • Language: JavaScript
  • Installation: npm install connect

Core Imports

const connect = require("connect");

For ES modules:

import connect from "connect";

Basic Usage

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);

Architecture

Connect implements a middleware stack pattern where:

  • App Instance: Function that handles HTTP requests and maintains middleware stack
  • Middleware Stack: Array of middleware functions executed in sequence
  • Request Flow: Each request flows through middleware until one responds or all complete
  • Error Handling: Special 4-parameter middleware functions handle errors
  • Route Mounting: Middleware can be mounted on specific URL paths
  • Asynchronous Execution: Uses setImmediate (or process.nextTick fallback) for non-blocking flow
  • Final Handler: Integrates with finalhandler module for unhandled requests/errors

Capabilities

App Creation

Creates 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.

Middleware Registration

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);

Request Handling

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
  • Route matching is case-insensitive
  • Routes must end at path separator (/) or dot (.) boundaries
app.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: /foobar

Server Creation

Creates 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);

Event Handling

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();
});

Types

Middleware Function Signatures

/**
 * 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);

App Properties and Request Objects

/**
 * 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;
}

Error Handling

Connect uses a special error-handling pattern:

  • Error Propagation: Call next(error) to pass errors to error handlers
  • Error Middleware: Functions with 4 parameters (err, req, res, next) handle errors
  • Error Flow: Errors skip regular middleware and go to next error handler
  • Default Handler: Uses finalhandler 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");
});

Advanced Usage

Sub-applications

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);
});

HTTP Server Integration

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);

Complex Routing Patterns

// 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");
});

Implementation Details

Middleware Execution Flow

Connect processes requests through several internal steps:

  1. URL Preservation: req.originalUrl is set to preserve the original request URL
  2. Stack Iteration: Middleware functions are called sequentially from the stack array
  3. Route Matching: Each middleware's route is compared against the request URL path
  4. URL Modification: For mounted middleware, req.url is temporarily modified
  5. Error Routing: Errors skip regular middleware and flow to error handlers only
  6. Final Handling: Unhandled requests/errors are passed to finalhandler

Route Matching Rules

// 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.

Environment Integration

Connect respects the NODE_ENV environment variable:

  • Development: Error stack traces are logged to console
  • Test: Error logging is suppressed
  • Production: Minimal error information is exposed