Skip to main content

Command Palette

Search for a command to run...

Controllers: Building & Routing the Users Controller (Manual + CLI)

Published
3 min read
M

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

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.ts

  • update src/users/users.module.ts (adds UsersController to controllers)

If you moved AppModule or 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() → handles GET /users

  • @Post() → handles POST /users

  • @Put(':id') → handles PUT /users/:id

  • @Patch(':id') → handles PATCH /users/:id

  • @Delete(':id') → handles DELETE /users/:id

You’ll soon add parameters (@Param()), query strings (@Query()), and bodies (@Body()), plus validation via DTOs.


Test quickly with Postman

  1. Start dev server: npm run start:dev (default port 3000)

  2. GET {{base_url}}/users (e.g., http://localhost:3000/users)

  3. POST {{base_url}}/usersHeaders: Content-Type: application/jsonBody: {} (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 users later 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/json on POST/PUT/PATCH.

  • App didn’t restart: Ensure start:dev is 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