Controllers
⭐ Interview Importance: LOW
⏱️ Revision Time: 11 min
Controllers are responsible for handling incoming requests and returning responses to the client.
Overview
In NestJS, a controller’s sole purpose is to receive specific requests for the application. The routing mechanism controls which controller receives which requests. Frequently, each controller has more than one route, and different routes can perform different actions.
Controllers are created using classes and decorators. The @Controller() decorator is required to define a basic controller, and it takes an optional route path prefix.
Key Concepts
- Routing: Use decorators like
@Get(),@Post(),@Put(),@Delete(), and@Patch()to define HTTP method handlers. - Request Object: Access underlying request details using decorators like
@Req(),@Body(),@Query(), and@Param(). - Response Generation: By default, if a handler returns a JavaScript object or array, Nest will automatically serialize it to JSON and return a 200 OK status (201 for POST).
- Dependency Injection: Controllers request dependencies (like Services) via their constructor.
Code Examples
A Standard REST Controller
import { Controller, Get, Post, Body, Param, Delete, Put, HttpCode, HttpStatus } from '@nestjs/common';
import { UsersService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
// Prefix all routes with '/users'
@Controller('users')
export class UsersController {
// Inject the service via the constructor
constructor(private readonly usersService: UsersService) {}
@Post()
@HttpCode(HttpStatus.CREATED) // Defaults to 201, but explicit is good
create(@Body() createUserDto: CreateUserDto) {
// Controller delegates business logic to the service
return this.usersService.create(createUserDto);
}
@Get()
findAll() {
return this.usersService.findAll();
}
// Matches GET /users/:id (e.g. /users/123)
@Get(':id')
findOne(@Param('id') id: string) {
return this.usersService.findOne(+id);
}
@Put(':id')
update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
return this.usersService.update(+id, updateUserDto);
}
@Delete(':id')
@HttpCode(HttpStatus.NO_CONTENT) // 204
remove(@Param('id') id: string) {
return this.usersService.remove(+id);
}
}
Request Payload Extraction Decorators
Nest provides several decorators to easily extract parts of the HTTP request:
@Request(),@Req(): The underlying Express/Fastify request object.@Response(),@Res(): The underlying response object (use carefully, disables Nest’s auto-serialization).@Next(): The next middleware function.@Session():req.session@Param(key?: string):req.params(Route parameters)@Body(key?: string):req.body(JSON payload)@Query(key?: string):req.query(Query string parameters)@Headers(name?: string):req.headers
Best Practices
- Thin Controllers: A controller should almost never contain actual business logic. It should only parse the request, validate it (using DTOs and Pipes), pass the data to a Service, and return the result.
- Always use DTOs: Define Data Transfer Objects (classes) for
@Body()payloads. This allows you to useValidationPipeandclass-validatorto strictly type-check and validate incoming data before the controller even executes. - Avoid
@Res()when possible: Using@Res()drops you down to the underlying framework (Express). You lose Nest’s automatic JSON serialization and interceptor compatibility. Rely on returning values normally instead.