Controllers: Building & Routing the Users Controller (Manual + CLI)
As a former 3D Animator with more than 12 years of experience, I have always been fascinated by the intersection of technology and creativity. That's why I recently shifted my career towards MERN stack development and software engineering, where I have been serving since 2021.
With my background in 3D animation, I bring a unique perspective to software development, combining creativity and technical expertise to build innovative and visually engaging applications. I have a passion for learning and staying up-to-date with the latest technologies and best practices, and I enjoy collaborating with cross-functional teams to solve complex problems and create seamless user experiences.
In my current role as a MERN stack developer, I have been responsible for developing and implementing web applications using MongoDB, Express, React, and Node.js. I have also gained experience in Agile development methodologies, version control with Git, and cloud-based deployment using platforms like Heroku and AWS.
I am committed to delivering high-quality work that meets the needs of both clients and end-users, and I am always seeking new challenges and opportunities to grow both personally and professionally.
In the last lessons you created a Users module and set up a client (Postman or any REST client) to hit your local API. Now it’s time to add your first controller.
This post explains:
What a controller is (and why you need it)
How to create UsersController by hand and via the Nest CLI
How routing works with HTTP verb decorators (
@Get,@Post,@Put,@Patch,@Delete)How to wire the controller into the module and test with Postman
What is a controller (in NestJS)?
A controller contains your routing logic. It receives an HTTP request and picks the method to handle it based on the HTTP verb and path.
One class (controller) can handle GET, POST, PUT, PATCH, DELETE.
The base path for the controller comes from
@Controller('...').Methods inside the class are matched via decorators like
@Get(),@Post(), etc.
Naming (
users.controller.ts) is just a convention. What makes it a controller is the@Controller()decorator.
Create UsersController manually (great for understanding)
1) Add the file
src/users/users.controller.ts
2) Define the controller and its routes
// src/users/users.controller.ts
import { Controller, Get, Post, Put, Patch, Delete } from '@nestjs/common';
@Controller('users') // base path → /users
export class UsersController {
@Get()
findAll() {
return 'GET /users';
}
@Post()
create() {
return 'POST /users';
}
@Put(':id')
replace() {
return 'PUT /users/:id';
}
@Patch(':id')
update() {
return 'PATCH /users/:id';
}
@Delete(':id')
remove() {
return 'DELETE /users/:id';
}
}
3) Register the controller in the module
// src/users/users.module.ts
import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
@Module({
controllers: [UsersController], // ← wire it here
})
export class UsersModule {}
4) Run & smoke‑test
npm run start:dev
GET
http://localhost:3000/users→"GET /users"POST
http://localhost:3000/userswith headerContent-Type: application/json→"POST /users"
If you get 404, the controller likely isn’t added to the module’s controllers: [].
Generate the controller with the Nest CLI (quickest in real work)
Preview (safe mode):
nest g controller users --dry-run
Skip test file:
nest g controller users --no-spec --dry-run
Generate for real:
nest g controller users --no-spec
The CLI will:
create
src/users/users.controller.tsupdate
src/users/users.module.ts(addsUsersControllertocontrollers)
If you moved
AppModuleor use a non‑standard layout, the CLI might not auto‑wire things. Add the import manually.
How routing works (decorators, in a nutshell)
@Controller('users')→ base path/users@Get()→ handlesGET /users@Post()→ handlesPOST /users@Put(':id')→ handlesPUT /users/:id@Patch(':id')→ handlesPATCH /users/:id@Delete(':id')→ handlesDELETE /users/:id
You’ll soon add parameters (@Param()), query strings (@Query()), and bodies (@Body()), plus validation via DTOs.
Test quickly with Postman
Start dev server:
npm run start:dev(default port 3000)GET
{{base_url}}/users(e.g.,http://localhost:3000/users)POST
{{base_url}}/users→ Headers:Content-Type: application/json→ Body:{}(for now)
You should see the simple strings defined in your controller. Later, we’ll connect these to real logic in a service and a database.
Best practices (right from the start)
Keep controllers thin. Parse inputs and delegate work to a service.
Prefer
@Body()+ DTOs + ValidationPipe for clean, safe inputs.Keep route names resource‑oriented (
/users,/users/:id).Consider
nest g resource userslater to scaffold controller + service + DTOs quickly.
Troubleshooting
404 Not Found: Wrong path or controller not registered in the module.
415 Unsupported Media Type: Missing
Content-Type: application/jsonon POST/PUT/PATCH.App didn’t restart: Ensure
start:devis running (watch mode) or restart the process.
Up next
We’ll add real data handling:
Read route params and query strings
Accept and validate request bodies (DTOs + Validation Pipe)
Introduce UsersService and move logic out of the controller