https://github.com/rayattack/routerling
https://github.com/rayattack/routerling
Last synced: about 2 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/rayattack/routerling
- Owner: rayattack
- Created: 2026-01-10T22:44:49.000Z (2 months ago)
- Default Branch: main
- Last Pushed: 2026-01-10T23:31:10.000Z (2 months ago)
- Last Synced: 2026-01-11T07:07:57.489Z (2 months ago)
- Language: JavaScript
- Size: 891 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
- awesome-blazingly-fast - routerling - Extremely Stupid Simple, Blazing Fast, Get Out of your way immediately Microframework for building Python Web Applications. (Python)
README
# Routerling
[](https://rayattack.github.io/routerling/)
A simple, fast, and powerful web framework for Node.js with built-in WebSocket support, lifecycle hooks, and daemon processes.
**[📚 Read the Documentation](https://rayattack.github.io/routerling/)**
## Features
- 🚀 **Fast HTTP Routing** - Efficient route matching and handling
- 🔌 **WebSocket Support** - Built-in WebSocket server with route-based handlers
- 🎯 **Lifecycle Hooks** - STARTUP and SHUTDOWN hooks for initialization and cleanup
- ⚙️ **Daemon Processes** - Register background tasks that run on server startup
- 📦 **Context Object** - Store and share values across request handlers and middleware
- 🌐 **Subdomain Routing** - Route requests based on subdomains
- 📦 **Router Mounting** - Compose applications from multiple routers
- 🎨 **Template Rendering** - Built-in Nunjucks template support
- 📁 **Static Files** - Serve static assets with automatic MIME type detection
- 🍪 **Cookie Parsing** - Built-in cookie support
- 📤 **File Uploads** - Handle multipart form data and file uploads
## Installation
```bash
npm install routerling
```
## Quick Start
```javascript
import { Router, STARTUP, SHUTDOWN } from 'routerling';
const app = new Router();
// Startup hook - runs when server starts
app.ONCE(STARTUP, async () => {
console.log('Server initializing...');
// Connect to database, load config, etc.
});
// Shutdown hook - runs when server stops
app.ONCE(SHUTDOWN, async () => {
console.log('Cleaning up...');
// Close connections, save state, etc.
});
// HTTP routes - handlers receive (req, res, ctx)
app.GET('/', (req, res, ctx) => {
res.json({ message: 'Hello from Routerling!' });
});
app.POST('/api/users', (req, res, ctx) => {
const user = req.body;
res.status = 201;
res.json({ id: 1, ...user });
});
// WebSocket endpoint
app.WS('/chat', (ws, request) => {
ws.on('message', (data) => {
ws.send(`Echo: ${data}`);
});
});
// Start server
app.listen(3000, 'localhost', () => {
console.log('Server running on http://localhost:3000');
});
```
## API Reference
### Router Methods
#### HTTP Methods
- `GET(route, handler, subdomain?)` - Handle GET requests
- `POST(route, handler, subdomain?)` - Handle POST requests
- `PUT(route, handler, subdomain?)` - Handle PUT requests
- `PATCH(route, handler, subdomain?)` - Handle PATCH requests
- `DELETE(route, handler, subdomain?)` - Handle DELETE requests
- `HEAD(route, handler, subdomain?)` - Handle HEAD requests
- `OPTIONS(route, handler, subdomain?)` - Handle OPTIONS requests
- `HTTP(route, handler, subdomain?)` - Handle all HTTP methods
**Route Parameters with Type Coercion:**
- `:id` - String parameter (default)
- `:id:int` - Integer parameter (auto-converted to number)
- `:price:float` - Float parameter (auto-converted to number)
- `:active:bool` - Boolean parameter (auto-converted to boolean)
**Examples:**
```javascript
app.GET('/users/:id:int', (req, res, ctx) => {
// req.params.id is a number, not a string
console.log(typeof req.params.id); // 'number'
});
app.GET('/products/:id:int/reviews/:rating:float', (req, res, ctx) => {
// Both params are auto-converted to numbers
});
```
#### WebSocket
- `WS(route, handler, subdomain?)` - Handle WebSocket connections
#### Lifecycle
- `ONCE(event, handler)` - Register startup/shutdown hooks
- `STARTUP` - Runs when server starts
- `SHUTDOWN` - Runs when server stops
#### Daemons
- `DAEMON(handler)` - Register background process
#### Middleware
- `BEFORE(route, handler, subdomain?)` - Add before middleware
- `AFTER(route, handler, subdomain?)` - Add after middleware
**Wildcard Middleware:**
Middleware supports wildcard patterns to match multiple routes:
```javascript
// Matches /api/users, /api/products, etc.
app.BEFORE('/api/*', (req, res, ctx) => {
ctx.startTime = Date.now();
});
app.AFTER('/api/*', (req, res, ctx) => {
console.log(`Request took ${Date.now() - ctx.startTime}ms`);
});
```
#### Routing
- `subdomain(name)` - Register a subdomain
- `mount(router, isolated?)` - Mount another router
#### Static Assets & Templates
- `ASSETS(path)` - Serve static files from directory
- `TEMPLATES(path, options?)` - Enable template rendering
#### State Management
- `keep(key, value)` - Store value in global state
- `peek(key)` - Retrieve value from global state
- `unkeep(key)` - Remove and return value from global state
#### Server
- `listen(port, hostname, callback?)` - Start HTTP server
- `close()` - Stop server gracefully
### Request Object
```javascript
app.GET('/user/:id', (req, res, ctx) => {
req.params.id // Route parameters
req.query // Query string parameters
req.body // Parsed request body
req.headers // Request headers
req.cookies // Parsed cookies
req.files // Uploaded files
req.method // HTTP method
req.url // Request URL
req.path // URL path
});
```
### Response Object
```javascript
app.GET('/example', (req, res, ctx) => {
res.status = 200; // Set status code
res.body = 'Hello'; // Set response body
res.json({ key: 'value' }); // Send JSON
res.html('
Hello
'); // Send HTML
res.redirect('/other'); // Redirect
res.cookie('name', 'value', opts); // Set cookie
res.header('X-Custom', 'value'); // Set header
});
```
### Context Object
The context object allows you to store and retrieve values across request handlers, middleware, and the request lifecycle.
```javascript
// Store values in context
app.BEFORE('/api/*', (req, res, ctx) => {
ctx.keep('startTime', Date.now());
ctx.user = { id: 1, name: 'John' }; // Proxy syntax
});
app.GET('/api/data', (req, res, ctx) => {
// Retrieve values from context
const user = ctx.user; // Proxy syntax
const startTime = ctx._data.get('startTime');
res.json({ user, processingTime: Date.now() - startTime });
});
// Context methods
ctx.keep(key, value) // Store a value
ctx.has(key) // Check if key exists
ctx.delete(key) // Remove a key
ctx.keys() // Get all keys
ctx.values() // Get all values
ctx.entries() // Get all entries
ctx.clear() // Clear all data
ctx.size // Number of stored values
```
## Examples
### Daemon Process
```javascript
app.DAEMON(async (router) => {
// Background task that runs on startup
setInterval(() => {
console.log('Health check...');
}, 60000);
});
```
### Subdomain Routing
```javascript
app.subdomain('api');
const handler = (req, res, ctx) => {
res.json({ subdomain: 'api' });
};
app.GET('/users', handler, 'api'); // api.example.com/users
app.GET('/users', handler); // www.example.com/users
```
### Router Mounting
```javascript
const apiRouter = new Router();
const getUsers = (req, res, ctx) => res.json({ users: [] });
const createUser = (req, res, ctx) => res.json({ created: true });
apiRouter.GET('/users', getUsers);
apiRouter.POST('/users', createUser);
app.mount(apiRouter);
```
### Template Rendering
```javascript
await app.TEMPLATES('./views');
app.GET('/page', (req, res, ctx) => {
res.render('template.html', { data: 'value' });
});
```
### Static Files
```javascript
await app.ASSETS('./public');
// Serves files from ./public directory
```
## Testing
```bash
npm test
```
## License
MIT
## Author
Tersoo Ortserga