Dynamic Routes
Dynamic Routes refer to routes that do not have a fixed URL path, but rather rely on parameters to determine what data to return.
Overview
Dynamic routing is the foundation of any RESTful API. It allows a single endpoint pattern to serve data for thousands of different records.
In NestJS, dynamic routes are created by defining variables in the route string using the :parameterName syntax.
Key Concepts
- Path Parameters: The dynamic segment of the URL (e.g.,
123in/users/123). - The
@Param()Decorator: Used to inject the dynamic values from the URL into the controller method. - Nested Dynamic Routes: You can have multiple dynamic segments in a single route.
Code Examples
Standard Dynamic Route
@Controller('users')
export class UsersController {
// The ':id' segment is dynamic
@Get(':id')
getUser(@Param('id') id: string) {
// If request is GET /users/42, 'id' will be "42"
return `Fetching user ${id}`;
}
}
Nested Dynamic Segments
You can create complex hierarchical APIs using multiple dynamic segments.
@Controller('companies')
export class CompaniesController {
// Matches /companies/apple/employees/105
@Get(':companyId/employees/:employeeId')
getEmployee(
@Param('companyId') companyId: string,
@Param('employeeId') employeeId: string,
) {
return `Fetching employee ${employeeId} from company ${companyId}`;
}
}
The Conflict Problem (Static vs Dynamic)
One of the most common mistakes in API design is route conflicts. Consider this:
@Controller('users')
export class UsersController {
@Get(':id')
getUserById(@Param('id') id: string) {
return `User ID: ${id}`;
}
// BUG! This will NEVER execute!
@Get('active')
getActiveUsers() {
return 'Active users';
}
}
If a client requests GET /users/active, Nest evaluates routes top-to-bottom. It sees @Get(':id') first. Since “active” is a valid string, Nest assumes “active” is the id, and executes getUserById("active").
The Solution: Always define static routes before dynamic routes.
@Controller('users')
export class UsersController {
// Static route FIRST
@Get('active')
getActiveUsers() {
return 'Active users';
}
// Dynamic route SECOND
@Get(':id')
getUserById(@Param('id') id: string) {
return `User ID: ${id}`;
}
}
Best Practices
- Route Ordering: Always order your routes from most specific (static strings) to least specific (dynamic parameters and wildcards).
- Validation: Dynamic parameters are always strings. Always use
ParseIntPipeorParseUUIDPipeif you expect the dynamic segment to be a number or UUID.