Creates a new Router instance with all HTTP method tries pre-initialized.
The constructor initializes separate Trie data structures for each supported HTTP method, ensuring optimal performance for route matching. This upfront initialization prevents runtime overhead during route registration and request handling.
Initialization: Creates Trie instances for GET, POST, PUT, DELETE, PATCH, HEAD, and OPTIONS methods.
Adds a pre-configured Route instance to the router.
This method provides a more flexible way to add routes by accepting a complete Route instance. It's useful when you need to add routes with custom middleware, constraints, or descriptions that were created using the Route factory methods.
Validation: The route's HTTP method must be one of the supported methods (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS).
The Route instance to add
The Router instance for method chaining
// Create a route with custom options
const userRoute = Route.GET('/users/:id', (ctx) => {
ctx.json({ id: ctx.pathParams.id });
}, {
middleware: [authMiddleware],
constraints: { id: '\\d+' },
description: 'Get user by ID'
});
// Add the pre-configured route
router.addRoute(userRoute);
// Create multiple routes and add them
const routes = [
Route.POST('/users', createUserHandler),
Route.PUT('/users/:id', updateUserHandler),
Route.DELETE('/users/:id', deleteUserHandler)
];
routes.forEach(route => router.addRoute(route));
// Error case - unsupported method
try {
const invalidRoute = { method: 'INVALID', path: '/test', handler: () => {} };
router.addRoute(invalidRoute);
} catch (error) {
console.error(error.message); // "Unsupported HTTP method: INVALID"
}
Adds a new COMMAND route to the router.
This method creates and registers a COMMAND route with the specified path and handler function. COMMAND routes are used for CLI command execution, enabling unified handling of both HTTP requests and CLI operations.
COMMAND Method: Used for CLI command execution. COMMAND routes handle terminal commands through the Wings routing system, allowing the same middleware and routing logic to work for both web and CLI.
The command path pattern (e.g., '/git/commit')
The function to handle COMMAND requests
The Router instance for method chaining
// Basic COMMAND route
router.cmd('/git/commit', async (ctx) => {
const message = ctx.queryParams.get('message') || 'Default commit message';
await executeGitCommit(message);
ctx.text('✅ Committed successfully');
});
// COMMAND route with path parameters
router.cmd('/deploy/:environment', (ctx) => {
const env = ctx.pathParams.environment;
console.log(`Deploying to ${env}...`);
ctx.text(`✅ Deployed to ${env}`);
});
// Method chaining
router
.cmd('/git/status', gitStatusHandler)
.cmd('/git/commit', gitCommitHandler)
.cmd('/deploy/:env', deployHandler);
Adds a new DELETE route to the router.
This method creates and registers a DELETE route with the specified path and handler function. DELETE routes are typically used for removing resources.
DELETE Method: Used for removing resources. DELETE requests should be idempotent and typically don't include a request body.
The path pattern for the route (e.g., '/users/:id')
The function to handle DELETE requests
The Router instance for method chaining
Adds a new GET route to the router.
This method creates and registers a GET route with the specified path and handler function. GET routes are typically used for retrieving resources and should be idempotent and safe.
GET Method: Used for retrieving resources. GET requests should not modify server state and can be cached safely.
The path pattern for the route (e.g., '/users/:id')
The function to handle GET requests
The Router instance for method chaining
// Basic GET route
router.get('/users', (ctx) => {
ctx.json({ users: getAllUsers() });
});
// GET route with path parameters
router.get('/users/:id', (ctx) => {
const userId = ctx.pathParams.id;
const user = getUserById(userId);
ctx.json(user);
});
// Method chaining
router
.get('/users', listUsers)
.get('/users/:id', getUser)
.get('/users/:id/posts', getUserPosts);
Handles an incoming HTTP request through the complete middleware and routing pipeline.
This method orchestrates the entire request processing flow with enhanced error collection:
Request Flow:
Error Collection: Errors from any step are collected in ctx.errors
instead
of immediately throwing. This ensures that after callbacks (like logging) always
run, providing complete request lifecycle tracking even when errors occur.
Error Handling: If any errors are collected during the request lifecycle,
a 500 response is set but no errors are thrown. Middleware (like logger) can
consume errors from ctx.errors
for formatting. Any remaining unconsumed
errors are printed to console.error as a fallback.
Context Mutation: This method modifies the provided Context instance directly and returns it for convenience.
The HTTP lifecycle context
The modified context instance
// Create router with routes and middleware
const router = new Router();
router.use(authMiddleware);
router.get('/users/:id', async (ctx) => {
const userId = ctx.pathParams.id;
const user = await getUserById(userId);
ctx.json(user);
});
// Handle a request
const url = new URL('http://localhost/users/123');
const ctx = new Context('GET', url, new Headers());
const result = await router.handleRequest(ctx);
// Check the response
console.log(result.responseStatusCode); // 200
console.log(result.responseBody); // JSON string with user data
console.log(result.errors); // [] (empty array, no errors)
// Handle a non-existent route
const notFoundUrl = new URL('http://localhost/nonexistent');
const notFoundCtx = new Context('GET', notFoundUrl, new Headers());
const notFoundResult = await router.handleRequest(notFoundCtx);
console.log(notFoundResult.responseStatusCode); // 404
// Handle a request that causes an error
const errorUrl = new URL('http://localhost/users/invalid');
const errorCtx = new Context('GET', errorUrl, new Headers());
const errorResult = await router.handleRequest(errorCtx);
console.log(errorResult.responseStatusCode); // 500 (error response set)
console.log(errorResult.errors.length); // 0 (if logger consumed the errors)
// Error would be logged in formatted output and then consumed by logger
Adds a new HEAD route to the router.
This method creates and registers a HEAD route with the specified path and handler function. HEAD routes are typically used for retrieving headers only, without the response body.
HEAD Method: Used for retrieving headers only, without the response body. HEAD requests are useful for checking if a resource exists or getting metadata without transferring the full content.
The path pattern for the route (e.g., '/users/:id')
The function to handle HEAD requests
The Router instance for method chaining
Lists all registered routes, optionally filtered by HTTP method.
This method returns an array of all Route instances that have been registered with the router. You can optionally filter the results by specifying an HTTP method.
Note: The returned array is a copy of the internal routes array, so modifying it won't affect the router's internal state.
Optional
method: stringOptional HTTP method to filter routes (e.g., 'GET', 'POST')
Array of registered routes
// Get all routes
const allRoutes = router.listRoutes();
console.log(`Total routes: ${allRoutes.length}`);
// Get routes for specific method
const getRoutes = router.listRoutes('GET');
console.log(`GET routes: ${getRoutes.length}`);
// Get routes for another method
const postRoutes = router.listRoutes('POST');
console.log(`POST routes: ${postRoutes.length}`);
// Iterate over routes
router.listRoutes().forEach(route => {
console.log(`${route.method} ${route.path}`);
});
// Filter routes by method
const userRoutes = router.listRoutes().filter(route =>
route.path.startsWith('/users')
);
console.log(`User routes: ${userRoutes.length}`);
// Get routes with descriptions
const documentedRoutes = router.listRoutes().filter(route =>
route.description
);
documentedRoutes.forEach(route => {
console.log(`${route.method} ${route.path}: ${route.description}`);
});
Adds a new OPTIONS route to the router.
This method creates and registers an OPTIONS route with the specified path and handler function. OPTIONS routes are typically used for discovering the allowed HTTP methods and other capabilities of a resource.
OPTIONS Method: Used for discovering the allowed HTTP methods and other capabilities of a resource. OPTIONS requests are commonly used for CORS preflight requests.
The path pattern for the route (e.g., '/users')
The function to handle OPTIONS requests
The Router instance for method chaining
// Basic OPTIONS route
router.options('/users', (ctx) => {
ctx.responseHeaders.set('access-control-allow-methods', 'GET, POST, PUT, DELETE');
ctx.responseHeaders.set('access-control-allow-headers', 'Content-Type, Authorization');
ctx.responseHeaders.set('access-control-max-age', '86400');
ctx.responseStatusCode = 204;
});
Adds a new PATCH route to the router.
This method creates and registers a PATCH route with the specified path and handler function. PATCH routes are typically used for partially updating resources.
PATCH Method: Used for partially updating resources. PATCH requests should be idempotent and typically include only the fields to update in the request body.
The path pattern for the route (e.g., '/users/:id')
The function to handle PATCH requests
The Router instance for method chaining
Adds a new POST route to the router.
This method creates and registers a POST route with the specified path and handler function. POST routes are typically used for creating new resources.
POST Method: Used for creating new resources. POST requests typically include a request body with the data to create.
The path pattern for the route (e.g., '/users')
The function to handle POST requests
The Router instance for method chaining
// Basic POST route
router.post('/users', async (ctx) => {
const userData = ctx.requestBody();
const newUser = await createUser(userData);
ctx.json(newUser);
});
// POST route with validation
router.post('/users', async (ctx) => {
const userData = ctx.requestBody();
if (!userData.name || !userData.email) {
ctx.responseStatusCode = 400;
ctx.json({ error: 'Name and email are required' });
return;
}
const newUser = await createUser(userData);
ctx.json(newUser);
});
Adds a new PUT route to the router.
This method creates and registers a PUT route with the specified path and handler function. PUT routes are typically used for replacing entire resources.
PUT Method: Used for replacing entire resources. PUT requests should be idempotent and typically include a complete resource representation in the request body.
The path pattern for the route (e.g., '/users/:id')
The function to handle PUT requests
The Router instance for method chaining
Adds middleware to the end of the middleware chain.
This method appends middleware to the router's middleware array. Middleware added with this method will be executed before the route handler in the order they were added.
Duplicate Prevention: Middleware with the same identifier will not be added multiple times, preventing duplicate execution.
Execution Order: Middleware added with use()
runs after
middleware added with useEarly()
.
The middleware instance to add
The Router instance for method chaining
// Add authentication middleware
const authMiddleware = new Middleware(async (ctx) => {
const token = ctx.requestHeaders.get('authorization');
if (!token) {
ctx.responseStatusCode = 401;
ctx.responseEnded = true;
return;
}
ctx.data.user = await validateToken(token);
}, 'authentication');
router.use(authMiddleware);
// Add logging middleware
const loggingMiddleware = new Middleware((ctx) => {
console.log(`${ctx.method} ${ctx.path} - ${new Date().toISOString()}`);
}, 'logging');
router.use(loggingMiddleware);
// Method chaining
router
.use(authMiddleware)
.use(loggingMiddleware)
.get('/users', userHandler);
// Duplicate prevention
router.use(authMiddleware); // Won't add duplicate
router.use(authMiddleware); // Won't add duplicate
Adds middleware to the beginning of the middleware chain.
This method prepends middleware to the router's middleware array.
Middleware added with this method will be executed before the route
handler and before middleware added with use()
.
Duplicate Prevention: Middleware with the same identifier will not be added multiple times, preventing duplicate execution.
Execution Order: Middleware added with useEarly()
runs before
middleware added with use()
.
The middleware instance to add
The Router instance for method chaining
// Add CORS middleware early (should run first)
const corsMiddleware = new Middleware((ctx) => {
ctx.responseHeaders.set('access-control-allow-origin', '*');
ctx.responseHeaders.set('access-control-allow-methods', 'GET, POST, PUT, DELETE');
}, 'cors');
router.useEarly(corsMiddleware);
// Add authentication middleware (runs after CORS)
const authMiddleware = new Middleware(async (ctx) => {
// Authentication logic
}, 'authentication');
router.use(authMiddleware);
// Execution order: cors -> auth -> handler
router.get('/users', userHandler);
// Method chaining
router
.useEarly(corsMiddleware)
.use(authMiddleware)
.get('/users', userHandler);
Router - High-performance HTTP request router for the Wings framework. The Router class provides a lean, fast, and isomorphic HTTP router that can handle requests in both Node.js and browser environments. It uses a Trie data structure for optimal performance and supports middleware, path parameters, and complex routing patterns.
Key Features
Performance Characteristics
Route Registration: O(n) where n is the number of path segments Route Matching: O(m) where m is the number of segments in the request path Memory Usage: Minimal overhead (~1KB for typical applications) The router is optimized for scenarios where both route registration and matching performance matter, such as serverless functions and browser SPAs.
Design Philosophy
The Router prioritizes:
Performance Trade-offs
Advantages: