A high-performance web framework built for Bun, Deno, NodeJS and Cloudflare Workers with trie-based routing, middleware support, and TypeScript-first design. β‘
- β‘ Blazing fast trie-based router
- π§© Middleware pipeline with path matching
- π Dynamic route/middleware removal for hot-reloading
- π TypeScript first-class support
- π§ Route scoping for modular apps
- π§΅ Async/await ready
- π‘ Error handling built-in
# npm
npm install @rabbit-company/web
# yarn
yarn add @rabbit-company/web
# pnpm
pnpm add @rabbit-company/web
import { Web } from '@rabbit-company/web';
const app = new Web<{ user?: { id: string } }>();
// Middleware
app.use(async (ctx, next) => {
console.log(`${ctx.req.method} ${ctx.req.url}`);
await next();
});
// Routes
app.get('/', (ctx) => ctx.text('Hello!'));
app.get('/users/:id', async (ctx) => {
const user = await getUser(ctx.params.id);
return ctx.json(user);
});
// Start server on Node, Deno or Bun
app.listen({ port: 3000 });
// Start server on Cloudflare Workers
export default {
fetch: app.handleCloudflare,
};
console.log('Server running at http://localhost:3000');
// Basic routes (chainable)
app.get("/path", handler).post("/path", handler).put("/path", handler).patch("/path", handler).delete("/path", handler);
// Dynamic routes
app.get("/users/:id", (ctx) => {
return ctx.text(`User ID: ${ctx.params.id}`);
});
// Wildcard routes
app.get("/files/*", (ctx) => {
return ctx.text(`Requested file: ${ctx.params["*"]}`);
});
// Routes with removal capability
const routeId = app.addRoute("GET", "/temp", handler);
// Remove later
app.removeRoute(routeId);
// Add routes that can be removed later
const tempRoute = app.addRoute("GET", "/temporary", (ctx) => {
return ctx.text("This route can be removed");
});
const userRoute = app.addRoute("POST", "/users", createUserHandler);
// Remove individual routes
app.removeRoute(tempRoute);
// Remove routes by criteria
app.removeRoutesBy({ method: "GET" }); // Remove all GET routes
app.removeRoutesBy({ path: "/users" }); // Remove all /users routes
app.removeRoutesBy({ method: "POST", path: "/users" }); // Specific route
// List all routes
const routes = app.getRoutes();
console.log(routes); // [{ id: '...', method: 'GET', path: '/users/:id' }]
// Clear all routes and middleware
app.clear();
π§© Middleware (@rabbit-company/web-middleware
)
// Global middleware (chainable)
app.use(async (ctx, next) => {
console.log("Request started");
await next();
console.log("Request completed");
});
// Path-specific middleware (chainable)
app.use("/admin", adminAuthMiddleware)
.use("POST", "/users", validateUserMiddleware);
// Middleware with removal capability
const authId = app.addMiddleware('/admin', (ctx, next) => {
// Authentication logic
await next();
});
const loggingId = app.addMiddleware(async (ctx, next) => {
console.log(`${ctx.req.method} ${ctx.req.url}`);
await next();
});
// Remove middleware
app.removeMiddleware(authId);
// Remove middleware by criteria
app.removeMiddlewareBy({ method: 'POST' }); // Remove all POST middleware
app.removeMiddlewareBy({ path: '/admin' }); // Remove all /admin middleware
// List all middleware
const middlewares = app.getMiddlewares();
console.log(middlewares); // [{ id: '...', method: 'POST', path: '/users' }]
// Perfect for development hot-reloading
const routeManager = new Map();
function hotReload(routePath, newHandler) {
// Remove old route if exists
if (routeManager.has(routePath)) {
app.removeRoute(routeManager.get(routePath));
}
// Add new route
const routeId = app.addRoute("GET", routePath, newHandler);
routeManager.set(routePath, routeId);
}
// Update route without restarting server
hotReload("/api/users", newUserHandler);
// Request info
ctx.req; // Original Request object
ctx.params; // Route parameters
ctx.query(); // URL query params
// State management
ctx.set("user", user); // Set state
ctx.get("user"); // Get state
// Response helpers
ctx.text("Hello"); // Text response
ctx.json({ data }); // JSON response
ctx.html("<h1>Hi</h1>"); // HTML response
ctx.redirect("/new"); // Redirect
// Headers
ctx.header("X-Custom", "Value"); // Set response header
// API v1 routes (chainable)
app.scope("/api/v1", (v1) => {
v1.get("/users", getUsers).post("/users", createUser);
});
// Mount sub-apps
const adminApp = new Web();
adminApp.get("/dashboard", dashboardHandler);
app.route("/admin", adminApp);
// Scoped routes can still be removed by criteria
app.removeRoutesBy({ path: "/api/v1/users" });
// Global error handler
app.onError((err, ctx) => {
console.error(err);
return ctx.json({ error: "Something went wrong" }, 500);
});
// Route error handling
app.get("/danger", async (ctx) => {
try {
// Risky operation
} catch (err) {
return ctx.json({ error: err.message }, 400);
}
});
get(path, ...handlers)
- Add GET route (chainable)post(path, ...handlers)
- Add POST route (chainable)put(path, ...handlers)
- Add PUT route (chainable)patch(path, ...handlers)
- Add PATCH route (chainable)delete(path, ...handlers)
- Add DELETE route (chainable)options(path, ...handlers)
- Add OPTIONS route (chainable)head(path, ...handlers)
- Add HEAD route (chainable)addRoute(method, path, ...handlers)
- Add route with ID returnremoveRoute(id)
- Remove route by IDremoveRoutesBy(criteria)
- Remove routes by method/pathgetRoutes()
- List all routes with metadata
use(...args)
- Add middleware (chainable)addMiddleware(...args)
- Add middleware with ID returnremoveMiddleware(id)
- Remove middleware by IDremoveMiddlewareBy(criteria)
- Remove middleware by method/pathgetMiddlewares()
- List all middleware with metadata
scope(path, callback)
- Create scoped sub-applicationroute(prefix, subApp)
- Mount sub-applicationclear()
- Remove all routes and middlewareonError(handler)
- Set global error handlerhandle(request)
- Main request handler
Benchmarks against popular frameworks:
bun test v1.2.14 (6a363a38)
tests/benchmark.test.ts:
Web Framework (Simple): 1585.39ms for 1000000 requests (630,758 req/s) (checksum: 16916310)
Hono Framework (Simple): 2050.02ms for 1000000 requests (487,801 req/s) (checksum: 16916359)
Elysia Framework (Simple): 1072.74ms for 1000000 requests (932,192 req/s) (checksum: 16916953)
β Comprehensive Framework Benchmarks > Simple Route Benchmark > benchmarks simple GET route [4731.96ms]
Web Framework (Complex): 1754.07ms for 1000000 requests (570,102 req/s) (checksum: 23023000)
Hono Framework (Complex): 2581.80ms for 1000000 requests (387,326 req/s) (checksum: 23023000)
Elysia Framework (Complex): 1402.50ms for 1000000 requests (713,015 req/s) (checksum: 23023000)
β Comprehensive Framework Benchmarks > Complex Routing Benchmark > benchmarks complex routing scenarios [5751.95ms]
Web Framework (Middleware): 2401.10ms for 1000000 requests (416,475 req/s) (checksum: 80080024)
Hono Framework (Middleware): 3583.00ms for 1000000 requests (279,096 req/s) (checksum: 80080024)
Elysia Framework (Middleware): 1572.81ms for 1000000 requests (635,803 req/s) (checksum: 80080024)
β Comprehensive Framework Benchmarks > Middleware Benchmark > benchmarks middleware performance [7575.94ms]
Web Framework (Params): 1628.38ms for 1000000 requests (614,106 req/s) (checksum: 27227200)
Hono Framework (Params): 2887.76ms for 1000000 requests (346,289 req/s) (checksum: 21421400)
Elysia Framework (Params): 1387.94ms for 1000000 requests (720,491 req/s) (checksum: 27227200)
β Comprehensive Framework Benchmarks > Parameter Extraction Benchmark > benchmarks parameter extraction performance [5918.95ms]
Web Framework (JSON Body): 191.21ms for 50000 requests (261,490 req/s) (checksum: 5490984)
Hono Framework (JSON Body): 199.59ms for 50000 requests (250,512 req/s) (checksum: 5490984)
Elysia Framework (JSON Body): 141.65ms for 50000 requests (352,983 req/s) (checksum: 5490984)
β Comprehensive Framework Benchmarks > JSON Body Parsing Benchmark > benchmarks JSON body parsing performance [552.00ms]
Tested on Framework 16 laptop (Ryzen 7040 Series)
This project is licensed under the MIT License - see the LICENSE file for details. ππ