A modern, feature-rich web framework for Node.js with TypeScript support. Unlike Express, Routly comes with batteries included - validation, CORS, rate limiting, and more are built right in.
- π Lightweight: Built on Node.js native
httpmodule - π£οΈ Advanced Routing: Support for all HTTP methods, route parameters, and route groups
- β‘ Async/Await Native: First-class support for async handlers
- π Built-in Validation: No need for external validation libraries
- π CORS Middleware: Integrated CORS support
- π‘οΈ Rate Limiting: Protect your API from abuse
- πͺ Cookie Parser: Parse and set cookies easily
- π Static Files: Serve static files with ETag support
- π¦ Body Parsing: JSON and URL-encoded body parsing
- π― Route Groups: Organize routes with prefixes and shared middleware
- π§ Error Handling: Centralized error handling with custom errors
- π TypeScript: Full TypeScript support with complete type definitions
npm install routlyimport { Routly, bodyParser } from 'routly';
const app = new Routly();
// Middleware
app.use('/', bodyParser.json());
// Routes
app.get('/', (req, res) => {
res.json({ message: 'Hello Routly!' });
});
app.post('/users', (req, res) => {
res.status(201).json({ user: req.body });
});
// Start server
app.listen(3000, () => {
console.log('Server running on http://localhost:3000');
});Routly supports all standard HTTP methods:
app.get('/users', handler);
app.post('/users', handler);
app.put('/users/:id', handler);
app.patch('/users/:id', handler);
app.delete('/users/:id', handler);
app.options('/users', handler);Organize routes with shared prefixes and middleware:
app.group('/api/v1', (group) => {
// Middleware for this group
group.use('/', authMiddleware);
// Routes
group.get('/users', getUsers);
group.post('/users', createUser);
group.get('/users/:id', getUser);
});Validate request data without external libraries:
import { validators } from 'routly';
app.post('/users', validators.body({
name: { type: 'string', required: true, min: 3, max: 50 },
email: { type: 'email', required: true },
age: { type: 'number', min: 18, max: 120 },
}), (req, res) => {
res.json({ user: req.body });
});Validation Rules:
type: 'string' | 'number' | 'boolean' | 'email' | 'url' | 'array' | 'object'required: booleanmin: minimum length/valuemax: maximum length/valuepattern: RegExpcustom: custom validation functionmessage: custom error message
import { cors } from 'routly';
app.use('/', cors({
origin: '*', // or array of origins, or function
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true,
}));import { rateLimit } from 'routly';
app.use('/api', rateLimit({
windowMs: 60000, // 1 minute
max: 100, // 100 requests per minute
message: 'Too many requests',
}));import { cookieParser } from 'routly';
app.use('/', cookieParser());
app.get('/set-cookie', (req, res) => {
res.cookie('user', 'john', {
maxAge: 3600000,
httpOnly: true
});
res.json({ message: 'Cookie set' });
});
app.get('/get-cookie', (req, res) => {
res.json({ cookies: req.cookies });
});import { serveStatic } from 'routly';
import * as path from 'path';
app.use('/public', serveStatic(path.join(__dirname, 'public'), {
maxAge: 86400, // 1 day cache
etag: true,
}));import { bodyParser } from 'routly';
// JSON parser
app.use('/', bodyParser.json({ limit: 5 * 1024 * 1024 })); // 5MB limit
// URL-encoded parser
app.use('/', bodyParser.urlencoded({ limit: 5 * 1024 * 1024 }));import { errorHandler, asyncHandler, createError } from 'routly';
// Async route with automatic error handling
app.get('/async', asyncHandler(async (req, res) => {
const data = await fetchData();
res.json(data);
}));
// Throw custom errors
app.get('/error', (req, res) => {
throw createError.badRequest('Invalid input');
});
// Error handler middleware (must be last)
app.use('/', errorHandler({
log: true,
showStack: process.env.NODE_ENV !== 'production'
}));Available error creators:
createError.badRequest(message)- 400createError.unauthorized(message)- 401createError.forbidden(message)- 403createError.notFound(message)- 404createError.conflict(message)- 409createError.internal(message)- 500
interface Request {
query: { [key: string]: string | string[] };
params: { [key: string]: string };
body?: any;
cookies?: { [key: string]: string };
ip?: string;
// Helper methods
is(type: string): boolean;
get(header: string): string | string[] | undefined;
accepts(...types: string[]): string | false;
}interface Response {
status(code: number): this;
json(body: any): void;
send(body: string | Buffer): void;
redirect(url: string, status?: number): void;
cookie(name: string, value: string, options?: CookieOptions): this;
sendFile(path: string): void;
}| Feature | Routly | Express |
|---|---|---|
| TypeScript Native | β Built-in | β Needs @types |
| Validation | β Built-in | β Needs express-validator |
| CORS | β Built-in | β Needs cors package |
| Rate Limiting | β Built-in | β Needs express-rate-limit |
| Cookie Parser | β Built-in | β Needs cookie-parser |
| Async/Await | β Native support | |
| Route Groups | β Built-in | β Manual setup |
| Modern API | β Clean & intuitive |
Check out the examples directory for complete working examples:
- basic-server.ts - Basic server setup
- advanced-server.ts - All features showcase
Contributions are welcome! Please feel free to submit a Pull Request.
ISC