Routing
The Routing module in Orchestr provides a powerful, Laravel-inspired routing system for Node.js applications. It offers an elegant API for defining routes, handling HTTP requests, and managing application flow through middleware.
Overview
The Routing module consists of five core classes that work together to provide a complete routing solution:
Router
The main routing engine that registers routes and dispatches requests
Route
Represents individual routes with their methods, URIs, and actions
Controller
Base class for organizing route logic into controller classes
Request
HTTP request wrapper providing convenient access to request data
Response
HTTP response wrapper for building and sending responses
The routing system is inspired by Laravel's routing API, providing a familiar and elegant syntax while leveraging TypeScript's type safety.
Key Features
Fluent Route API
Route.get(), Route.post(), Route.put() and more for clean route definition
Dynamic Parameters
Pattern matching for route parameters and wildcards
Controller Support
Organize route logic in controller classes with dependency injection
Middleware Pipeline
Global and route-level middleware support
Route Groups
Share attributes across multiple routes
Named Routes
Easy URL generation with route names
File-Based Routes
Auto-discovery and organization of route files
Facade Pattern
Static access through Route facade
Basic Routing
Routes are registered using HTTP verb methods on the Router class. The most common way to define routes is through the Route facade.
Route Registration
Simple Routes
import { Route } from '@orchestr-sh/orchestr';
// Basic GET route
Route.get('/', async (req, res) => {
return res.send('Hello World');
});
// POST route
Route.post('/users', async (req, res) => {
const data = req.all();
return res.status(201).json({ user: data });
});
// PUT route
Route.put('/users/:id', async (req, res) => {
const id = req.routeParam('id');
const data = req.all();
return res.json({ message: `Updated user ${id}`, data });
});
// DELETE route
Route.delete('/users/:id', async (req, res) => {
const id = req.routeParam('id');
return res.json({ message: `Deleted user ${id}` });
});Available HTTP Methods
// GET - Retrieve resources
Route.get('/users', handler);
// POST - Create resources
Route.post('/users', handler);
// PUT - Update/replace resources
Route.put('/users/:id', handler);
// PATCH - Partially update resources
Route.patch('/users/:id', handler);
// DELETE - Remove resources
Route.delete('/users/:id', handler);
// OPTIONS - Get allowed methods
Route.options('/users', handler);
// HEAD - Get headers only
Route.head('/users', handler);
// Match multiple methods
Route.match(['GET', 'POST'], '/users', handler);
// Any method
Route.any('/webhook', handler);Route Parameters
Route parameters allow you to capture dynamic values from URLs:
// Required parameter
Route.get('/users/:id', async (req, res) => {
const id = req.routeParam('id'); // '123'
return res.json({ user: { id } });
});
// Multiple parameters
Route.get('/users/:id/posts/:postId', async (req, res) => {
const userId = req.routeParam('id');
const postId = req.routeParam('postId');
return res.json({ userId, postId });
});
// Optional parameter with ?
Route.get('/users/:id/posts/:postId?', async (req, res) => {
const id = req.routeParam('id'); // Required
const postId = req.routeParam('postId'); // Optional
return res.json({ id, postId });
});
// Pattern matching with regex
Route.get('/users/[0-9]+', async (req, res) => {
const id = req.routeParam(0); // Entire matched string
return res.json({ id });
});Controllers
Controllers help organize your route logic into reusable classes with automatic dependency injection:
Controller Benefits
import { Controller, Request, Response } from '@orchestr-sh/orchestr';
class UserController extends Controller {
async index(req: Request, res: Response) {
// GET /users
const users = await this.getUsers();
return res.json({ users });
}
async show(req: Request, res: Response) {
// GET /users/:id
const id = req.routeParam('id');
const user = await this.findUser(id);
return res.json({ user });
}
async store(req: Request, res: Response) {
// POST /users
const data = req.only(['name', 'email']);
const user = await this.createUser(data);
return res.status(201).json({ user });
}
// Private methods
private async getUsers() {
// Database logic here
return [];
}
private async findUser(id: string) {
// Database logic here
return { id };
}
private async createUser(data: any) {
// Database logic here
return { ...data, id: '1' };
}
}
// Register controller routes
Route.get('/users', [UserController, 'index']);
Route.get('/users/:id', [UserController, 'show']);
Route.post('/users', [UserController, 'store']);Request & Response
The Request and Response objects provide convenient methods for handling HTTP data:
import { Request, Response } from '@orchestr-sh/orchestr';
Route.post('/users', async (req: Request, res: Response) => {
// Request methods
const body = await req.json(); // Parse JSON body
const formData = req.all(); // All request data
const name = req.input('name'); // Single input value
const id = req.routeParam('id'); // Route parameter
const headers = req.headers(); // All headers
const userAgent = req.header('User-Agent'); // Specific header
// Response methods
return res.json({ user: body }); // JSON response
return res.status(201).json(data); // With status code
return res.send('Hello'); // Plain text
return res.download('/path/to/file'); // File download
return res.redirect('/dashboard'); // Redirect
return res.cookie('theme', 'dark'); // Set cookie
// Chaining methods
return res
.status(200)
.header('X-Custom', 'value')
.json({ success: true });
};Middleware
Middleware allows you to filter HTTP requests entering your application:
import { Middleware, Request, Response } from '@orchestr-sh/orchestr';
const authMiddleware: Middleware = async (req: Request, res: Response, next: Function) => {
const token = req.header('Authorization');
if (!token || !isValidToken(token)) {
return res.status(401).json({ error: 'Unauthorized' });
}
// Continue to next middleware
return next();
};
// Apply middleware to specific routes
Route.get('/profile', authMiddleware, async (req, res) => {
const user = await getCurrentUser(req);
return res.json({ user });
});
// Apply middleware to route groups
Route.group({ middleware: [authMiddleware] }, () => {
Route.get('/dashboard', handler1);
Route.post('/settings', handler2);
});Route Groups
Route groups allow you to share attributes across multiple routes:
// Group with URL prefix
Route.group({ prefix: '/api/v1' }, () => {
Route.get('/users', handler1); // /api/v1/users
Route.post('/posts', handler2); // /api/v1/posts
});
// Group with middleware
Route.group({
prefix: '/admin',
middleware: [authMiddleware, adminMiddleware]
}, () => {
Route.get('/dashboard', handler1);
Route.post('/settings', handler2);
});
// Group with multiple attributes
Route.group({
prefix: '/api/v1',
middleware: [corsMiddleware, rateLimitMiddleware],
name: 'api.'
}, () => {
Route.get('/users', handler1); // Named: api.users
Route.post('/posts', handler2); // Named: api.posts
});Named Routes
Named routes allow you to generate URLs for your routes:
// Define named routes
Route.get('/users', handler).setName('users.index');
Route.post('/users', handler).setName('users.store');
Route.get('/users/:id', handler).setName('users.show');
// Generate URLs
import { Route } from '@orchestr-sh/orchestr';
const userIndexUrl = Route.url('users.index'); // /users
const userShowUrl = Route.url('users.show', { id: 123 }); // /users/123
const userStoreUrl = Route.url('users.store'); // /users
// Route redirects
Route.redirect('/home', '/dashboard'); // Permanent redirect
Route.temporaryRedirect('/old-path', '/new-path'); // Temporary redirectBest Practices
Route Organization
Security Considerations
RESTful Routes
Use standard HTTP methods and naming conventions
Parameter Validation
Validate route parameters and request body data
Error Handling
Consistent error responses and status codes
Documentation
Document your API routes for developers
Testing
Write unit tests for your routes and controllers
Performance
Use caching and optimize database queries