Routing
Learn how to define routes in Muzu using decorators.
HTTP Method Decorators​
Muzu provides decorators for all common HTTP methods:
@Get(path)- Handle GET requests@Post(path)- Handle POST requests@Put(path)- Handle PUT requests@Patch(path)- Handle PATCH requests@Delete(path)- Handle DELETE requests
Basic Routing​
import { Controller, Get, Post, Put, Delete } from 'muzu';
@Controller('/api')
class ProductController {
@Get('/products')
getAllProducts() {
return { products: [] };
}
@Post('/products')
createProduct(req: Request) {
const { name, price } = req.body;
return { id: 1, name, price };
}
@Put('/products/:id')
updateProduct(req: Request) {
const { id } = req.params;
return { id, updated: true };
}
@Delete('/products/:id')
deleteProduct(req: Request) {
const { id } = req.params;
return { id, deleted: true };
}
}
Path Parameters​
Define dynamic path parameters using the :paramName syntax:
@Controller('/users')
class UserController {
// Single parameter
@Get(':id')
getUser(req: Request) {
const { id } = req.params;
return { userId: id };
}
// Multiple parameters
@Get(':userId/posts/:postId')
getUserPost(req: Request) {
const { userId, postId } = req.params;
return { userId, postId };
}
// Nested parameters
@Get(':userId/comments/:commentId/replies/:replyId')
getReply(req: Request) {
const { userId, commentId, replyId } = req.params;
return { userId, commentId, replyId };
}
}
Examples:
GET /users/123→{ userId: '123' }GET /users/123/posts/456→{ userId: '123', postId: '456' }GET /users/123/comments/456/replies/789→{ userId: '123', commentId: '456', replyId: '789' }
Query Parameters​
Query parameters are automatically parsed and added to req.params:
@Controller('/products')
class ProductController {
@Get()
searchProducts(req: Request) {
const { page, limit, sort, category } = req.params;
return {
page: page || '1',
limit: limit || '10',
sort: sort || 'desc',
category: category || 'all',
products: []
};
}
@Get(':id')
getProduct(req: Request) {
const { id, includeReviews, includeImages } = req.params;
return {
id,
product: {},
includeReviews: includeReviews === 'true',
includeImages: includeImages === 'true'
};
}
}
Examples:
GET /products?page=2&limit=20&sort=ascGET /products/123?includeReviews=true&includeImages=false
Parameter Priority
If a path parameter and query parameter have the same name, the path parameter takes precedence.
Request and Response Objects​
Request Object​
The Request object extends Node.js IncomingMessage with additional properties:
interface Request extends IncomingMessage {
params?: Record<string, any>; // Path and query parameters
body?: any; // Parsed request body (POST/PUT/PATCH)
[key: string]: any; // Custom properties (added by middleware)
}
Response Object​
The Response object is Node.js ServerResponse:
@Get('/users/:id')
getUser(req: Request, res: Response) {
const { id } = req.params;
// Set status code
res.statusCode = 200;
// Set headers
res.setHeader('X-Custom-Header', 'value');
// Return response body
return { id, name: 'Alice' };
}
Async Handlers​
Muzu automatically detects and handles async route handlers:
@Controller('/users')
class UserController {
@Get(':id')
async getUser(req: Request) {
// Fetch from database
const user = await database.users.findById(req.params.id);
if (!user) {
throw new NotFoundException('User not found');
}
return user;
}
@Post()
async createUser(req: Request) {
const user = await database.users.create(req.body);
return user;
}
}
Response Types​
Route handlers can return different types:
Object Response​
@Get('/user')
getUser() {
return { id: 1, name: 'Alice' }; // Automatically converted to JSON
}
String Response​
@Get('/health')
healthCheck() {
return 'OK'; // Returns plain text
}
Promise Response​
@Get('/data')
async getData() {
const data = await fetchData();
return data; // Promise is awaited automatically
}
No Content Response​
@Delete(':id')
deleteUser(req: Request, res: Response) {
res.statusCode = 204; // No Content
return {}; // Empty response
}
Route Priority​
Muzu uses a Radix tree for routing. Route priority is determined by:
- Static routes take precedence over parameterized routes
- Longer matches take precedence over shorter matches
- Routes are matched based on exact path segments
@Controller('/api')
class ApiController {
@Get('/users/me') // Higher priority (static)
getCurrentUser() {
return { message: 'Current user' };
}
@Get('/users/:id') // Lower priority (dynamic)
getUser(req: Request) {
return { userId: req.params.id };
}
}
GET /api/users/me→ Matches/users/me(static route)GET /api/users/123→ Matches/users/:id(dynamic route)
Next Steps​
- Learn about Controllers and how to organize your routes
- Add Middleware to your routes for authentication and logging
- Set up Request Validation to validate route parameters