What are controllers?
Controllers in Nest.js are classic TypeScript classes that are decorated with the @Controller() decorator. In such classes, methods corresponding to HTTP operations such as GET, POST, PUT, DELETE are defined, where each method within the controller is decorated with a corresponding HTTP decorator.
Example of a simple controller:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import { Controller, Get, Post, Body, Param } from '@nestjs/common'; @Controller('users') export class UsersController { private users = []; @Get() findAll(): any[] { return this.users; } @Get(':id') findOne(@Param('id') id: string): any { return this.users.find(user => user.id === id); } @Post() create(@Body() user: any): string { this.users.push(user); return 'User created successfully'; } } |
In this example, the @Controller('users') decorator defines the base route (“/users“) for all methods inside the controller. This example controller has three methods for three request types, and all three methods are marked with appropriate decorators depending on the type of HTTP request they handle:
- findAll(): Processes a GET request on route /users and returns a list of all users.
- findOne(): Processes a GET request on route /users/:id and returns the user with the given ID.
- create(): Processes a POST request on route /users and creates a new user.

Creating a controller
To add a controller to a module, the easiest way is to use the following commands in the terminal:
|
1 |
nest generate controller users |
This command will generate a users.controller.ts file within the new folder “users” and will place it in the root of the project, i.e. src/users:
|
1 2 3 4 |
import { Controller } from '@nestjs/common'; @Controller('users') export class UsersController {} |
If a directory named “users” does not exist, this command will create it. If we do not want to create a folder with the name of the controller, but only the controller file, then we use the flag --flat.
|
1 |
nest generate controller nekiKontroler --flat |
The previous command will create in the root directory (“src”) only a file related to the controller nekiKontroler.controller.ts, there is also a way to create a new controller file in an already existing folder, and for that we use the following syntax:
|
1 |
nest generate controller nekiFolder/noviKontroler --flat |
With this command, the file “noviKontroler.controller.ts” will be created in the folder named “nekiFolder”.
The command will also simultaneously add that controller to the module within the list of all controllers:
|
1 2 3 4 5 6 7 8 9 10 11 |
import { Module } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { UsersController } from './cats/Users.controller'; @Module({ imports: [], controllers: [AppController, UsersController], providers: [AppService], }) export class AppModule {} |
Decorators for accessing request data
In addition to decorators for marking the type of request (@Get(), @Post()…), there are also decorators for easier access to request data. These decorators make it easier to work with different parts of an HTTP request and allow simple and readable handling of requests inside the controller:
- @Param('id'): Allows access to parameter id from URL
- @Body(): Allows access to the POST request body.
- @Headers() provides access to HTTP headers.
- @Ip() provides access to the client’s IP address.
- @Body() provides access to the POST request body.
- @Session() provides access to session data.
- @Cookies() enables access to cookies.
- @HostParam('host') provides access to host parameters.
Example
Here’s how you can use some of these decorators in a controller:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
import { Controller, Get, Post, Body, Param, Query, Headers, Session, Ip, HostParam } from '@nestjs/common'; @Controller('example') export class ExampleController { //URL: http://localhost:3000/example/123?search=test @Get(':id') findOne( @Param('id') id: string, @Query() query: any, @Ip() ip: string ): string { console.log('Query:', query); // Query: { search: 'test' } console.log('IP Address:', ip); // IP Address: 127.0.0.1 return `User with id ${id}`; // User with id 123 } // URL: http://localhost:3000/example @Post() create( @Body() body: any, @Session() session: any, @Cookies() cookies: any): string { console.log('Body:', body); // Body: { name: 'John Doe' } console.log('Session:', session); // Session: { ... } // sesijski podaci, ako su prisutni console.log('Cookies:', cookies); // Cookies: { ... } // data from cookies, if present return 'User created successfully'; } // URL: http://subdomain.example.com:3000/example @Get() findWithHostParam( @HostParam('host') host: string): string { console.log('Host:', host); // Host: subdomain.example.com return `Host is ${host}`; } } |
In the previous example, the @Get decorator indicates that the findOne() method will respond to the request. The @Param(‘id’) decorator extracts a parameter named “id” from the request URL, while the @Query() decorator extracts all query parameters from the request URL and stores them in the “query” object (eg for the URL /users/123?search=test, the query will be { search: ‘test’ }). The @Ip() decorator provides the IP address of the client that sent the request.
Availability of services in controllers
Services are used to encapsulate business logic and enable code reuse. Services can be easily introduced into controllers using the dependency injection mechanism whichprovided by Nest.js. In Nest.js, there are several ways to inject services into a controller.
Injecting services through the constructor
The most common way is through constructors, as shown in the following example:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import { Controller, Get, Post, Body, Param } from '@nestjs/common'; import { UsersService } from './users.service'; @Controller('users') export class UsersController { constructor(private readonly usersService: UsersService) {} @Get() findAll(): any[] { return this.usersService.findAll(); } @Get(':id') findOne(@Param('id') id: string): any { return this.usersService.findOne(id); } @Post() create(@Body() user: any): string { return this.usersService.create(user); } } |
In this example, UsersController uses UsersService to process the request. The service is inserted into the controller through the constructor.
Injecting services through a property
Although not so often used, service injection via properties is also possible using the @Inject decorator.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
import { Controller, Get, Post, Body, Param, Inject } from '@nestjs/common'; import { UsersService } from './users.service'; @Controller('users') export class UsersController { @Inject(UsersService) private readonly usersService: UsersService; @Get() findAll(): any[] { return this.usersService.findAll(); } @Get(':id') findOne(@Param('id') id: string): any { return this.usersService.findOne(id); } @Post() create(@Body() user: any): string { return this.usersService.create(user); } } |
NOTE:
There is also “Manual injection” of services but it is quite complicated and is only used in specific cases when you cannot use constructor or property-based injection. This approach uses ModuleRef, which provides access to the Nest.js Dependency Injection (DI) container to manually obtain service instances.

