Skip to main content

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=asc
  • GET /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:

  1. Static routes take precedence over parameterized routes
  2. Longer matches take precedence over shorter matches
  3. 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​