Routing and Controllers
Routing in Vercube is a powerful and flexible system that allows you to define API endpoints using decorators. This guide explains how routing works in the framework and how to use it effectively.
Overview
The routing system in Vercube is built on a decorator-based approach, where:
- The
@Controller
decorator defines a base path for a group of related endpoints - HTTP method decorators (
@Get
,@Post
, etc.) define specific routes within that controller - The framework automatically registers these routes and handles incoming requests
Controller Decorator
The @Controller
decorator is used to define a controller class and its base path. It sets up the foundation for all routes defined within that controller.
import { Controller } from '@vercube/core';
@Controller('/users')
export class UserController {
// Route handlers will be defined here
}
In this example, all routes defined in the UserController
will be prefixed with /users
.
HTTP Method Decorators
Vercube provides decorators for all standard HTTP methods:
@Get(path)
- Handle GET requests@Post(path)
- Handle POST requests@Put(path)
- Handle PUT requests@Delete(path)
- Handle DELETE requests@Patch(path)
- Handle PATCH requests@Options(path)
- Handle OPTIONS requests@Head(path)
- Handle HEAD requests@Connect(path)
- Handle CONNECT requests@Trace(path)
- Handle TRACE requests
Each decorator takes a path parameter that defines the route relative to the controller's base path.
import { Controller, Get, Post, Put, Delete } from '@vercube/core';
@Controller('/users')
export class UserController {
@Get('/')
async getAllUsers() {
// Handle GET /users
}
@Get('/:id')
async getUserById() {
// Handle GET /users/:id
}
@Post('/')
async createUser() {
// Handle POST /users
}
@Put('/:id')
async updateUser() {
// Handle PUT /users/:id
}
@Delete('/:id')
async deleteUser() {
// Handle DELETE /users/:id
}
}
Route Parameters
You can define route parameters using the :paramName
syntax. These parameters can be accessed in your route handlers using parameter decorators.
import { Controller, Get, Param } from '@vercube/core';
@Controller('/users')
export class UserController {
@Get('/:id')
async getUserById(@Param('id') id: string) {
// Access the 'id' parameter from the URL
return `User with ID: ${id}`;
}
}
Request Body
To access the request body in POST, PUT, or PATCH requests, use the @Body
decorator:
import { Controller, Post, Body } from '@vercube/core';
@Controller('/users')
export class UserController {
@Post('/')
async createUser(@Body() userData: any) {
// Access the request body
return `Created user: ${JSON.stringify(userData)}`;
}
}
Query Parameters
To access query parameters, use the @QueryParam
or @QueryParams
decorators:
import { Controller, Get, QueryParam, QueryParams } from '@vercube/core';
@Controller('/users')
export class UserController {
@Get('/search')
async searchUsers(
@QueryParam('name') name: string,
@QueryParams() allParams: Record<string, string>
) {
// Access specific query parameter
console.log(`Searching for users with name: ${name}`);
// Access all query parameters
console.log('All query parameters:', allParams);
return `Search results for: ${name}`;
}
}
Headers
To access request headers, use the @Header
or @Headers
decorators:
import { Controller, Get, Header, Headers } from '@vercube/core';
@Controller('/users')
export class UserController {
@Get('/')
async getUsers(
@Header('Authorization') authToken: string,
@Headers() allHeaders: Record<string, string>
) {
// Access specific header
console.log(`Auth token: ${authToken}`);
// Access all headers
console.log('All headers:', allHeaders);
return 'User list';
}
}
Middleware
You can apply middleware to controllers or specific routes using the @Middleware
decorator:
import { Controller, Get, Middleware } from '@vercube/core';
import { AuthMiddleware, LoggingMiddleware } from './middlewares';
// Apply middleware to all routes in the controller
@Controller('/users')
@Middleware(AuthMiddleware)
export class UserController {
// Apply middleware to a specific route
@Get('/')
@Middleware(LoggingMiddleware, { priority: 1 })
async getAllUsers() {
return 'User list';
}
}
Request and Response Objects
You can access the raw request and response objects using the @Request
and @Response
decorators:
import { Controller, Get, Request, Response } from '@vercube/core';
@Controller('/users')
export class UserController {
@Get('/')
async getAllUsers(
@Request() req: Request,
@Response() res: Response
) {
// Access the raw request and response objects
console.log('Request URL:', req.url);
// Modify the response
res.headers.set('X-Custom-Header', 'value');
return 'User list';
}
}
How It Works
Behind the scenes, the routing system:
- Uses the
Controller
decorator to set up metadata for the controller class, including its base path - Uses HTTP method decorators to register routes with the Router service
- The Router service matches incoming requests to the appropriate route
- The RequestHandler service processes the request through middleware and executes the route handler
- The MetadataResolver service resolves parameters, body, query parameters, and headers
This architecture provides a clean, declarative way to define API endpoints while maintaining flexibility and power.
Best Practices
- Organize by Resource: Group related endpoints in the same controller
- Use Meaningful Paths: Choose paths that clearly indicate the resource and action
- Leverage Middleware: Use middleware for cross-cutting concerns like authentication and logging
- Validate Input: Use validation decorators to ensure input data is valid
- Handle Errors: Implement proper error handling for all routes
Conclusion
The routing system in Vercube provides a powerful and intuitive way to define API endpoints. By using decorators, you can create clean, maintainable, and well-organized code that clearly expresses the structure of your API.