โ† Back to list

๐Ÿš€ Day 2: Building a Core Feature with NestJSโ€Šโ€”โ€ŠThe User Module

On Day 1, we set up our NestJS project.

Ajay Kumar Maurya ยท 2025-08-24 06:55 ยท 0 claps ยท 4.7 min read
#nestjs #nestjs-tutorial #nestjs-module #nestjs-provider #nestjs-service
Open on Medium โ†—

๐Ÿš€ Day 2: Building a Core Feature with NestJS โ€” The User Module

On Day 1, we set up our NestJS project.

Now, on Day 2, weโ€™ll learn how to scaffold a core feature (User) using the Nest CLI.

Weโ€™ll explore:

  • Scaffolding with nest g resource and individual CLI commands
  • How module, controller, service, and test files fit together
  • Request โ†’ Response flow (with diagram)
  • Route mapping, status codes, and error handling
  • Running CRUD endpoints with sample requests
  • Preparing for database integration (coming next)

โ€” โ€”

๐Ÿ“‘ Table of Contents

  1. What is Scaffolding in NestJS?

  2. Creating a User Resource with Nest CLI

  1. Generated Folder Structure

  2. Understanding the Files

  1. Full AppModule Setup

  2. [Request โ†’ Response Flow (with Diagram)](#-request โ€” response-flow-with-diagram)

  3. CRUD Endpoints for User

  1. Error Handling in NestJS
  1. Next Steps (DB Integration Preview)

โ€” โ€”

๐Ÿ”น What is Scaffolding in NestJS?

Scaffolding means automatically generating files and boilerplate code using the Nest CLI.

๐Ÿ‘‰ Instead of writing everything from scratch, the CLI creates a module, service, controller, and test files for you.

Example:

nest g resource user

This generates a complete User feature with CRUD endpoints.

โ€” โ€”

๐Ÿ”น Creating a User Resource with Nest CLI

  • Option 1: Scaffold Full Resource (nest g resource user)

Run:

nest g resource user

Youโ€™ll see interactive prompts:

? What transport layer do you use? (Use arrow keys)
> REST API
GraphQL (code first)
GraphQL (schema first)
Microservice
WebSockets
? Would you like to generate CRUD entry points? (Y/n)

๐Ÿ‘‰ Choose:

  • REST API
  • Yes (to auto-generate CRUD endpoints)

Output (preview of generated files):

CREATE src/user/user.module.ts
CREATE src/user/user.controller.ts
CREATE src/user/user.controller.spec.ts
CREATE src/user/user.service.ts
CREATE src/user/user.service.spec.ts
CREATE src/user/dto/create-user.dto.ts
CREATE src/user/dto/update-user.dto.ts
CREATE src/user/entities/user.entity.ts

โ€” -

  • Option 2: Create Module, Controller, Service Separately

If you donโ€™t want auto-CRUD, you can create them step by step:

nest g module user # Creates user.module.ts
nest g controller user # Creates user.controller.ts + test
nest g service user # Creates user.service.ts + test

๐Ÿ‘‰ For a specific folder:

nest g controller features/user

This would place the controller inside src/features/user/.

๐Ÿ’ก Use โ€” dry-run to preview changes without actually generating:

nest g service user - dry-run

โ€” โ€”

๐Ÿ“‚ Generated Folder Structure

After running nest g resource user:

src/user/
  dto/                    # DTOs go here (weโ€™ll use them formally in the next lesson)
  entities/               # DB models/schemas later
  user.controller.ts      # Routes + request/response
  user.service.ts         # Business logic
  user.module.ts          # Declares the feature
  user.controller.spec.ts # Controller unit tests
  user.service.spec.ts    # Service unit tests

โ€” โ€”

๐Ÿ”น Understanding the Files

Module

๐Ÿ“Œ user.module.ts

import { Module } from '@nestjs/common';
import { UserService } from './user.service';
import { UserController } from './user.controller';
@Module({
controllers: [UserController], // Registers UserController
providers: [UserService], // Registers UserService
})
export class UserModule {}
  • A module groups related controllers & services. UserModule is imported into AppModule so Nest knows about it.

โ€” โ€”

Controller:-

๐Ÿ“Œ user.controller.ts

import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common';
import { UserService } from './user.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';

@Controller('user') // Base route: /user
export class UserController {
  constructor(private readonly userService: UserService) {}

  @Post() // POST /user
  create(@Body() createUserDto: CreateUserDto) {
  return this.userService.create(createUserDto);
  }

  @Get() // GET /user
  findAll() {
  return this.userService.findAll();
  }

  @Get(':id') // GET /user/:id
  findOne(@Param('id') id: string) {
  return this.userService.findOne(+id);
  }

  @Patch(':id') // PATCH /user/:id
  update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
  return this.userService.update(+id, updateUserDto);
  }

  @Delete(':id') // DELETE /user/:id
  remove(@Param('id') id: string) {
  return this.userService.remove(+id);
  }
}
  • Handles routes (API endpoints).
  • Delegates logic to the service layer.

โ€” โ€”

Service

๐Ÿ“Œ user.service.ts:-

import { Injectable } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';

@Injectable() // Makes this service injectable into controllers
export class UserService {
  private users = []; // Temporary in-memory storage

  create(createUserDto: CreateUserDto) {
    const newUser = { id: Date.now(), โ€ฆcreateUserDto };
    this.users.push(newUser);
    return newUser;
  }

  findAll() {
    return this.users;
  }

  findOne(id: number) {
    return this.users.find((user) => user.id === id);
  }

  update(id: number, updateUserDto: UpdateUserDto) {
    const user = this.findOne(id);
    if (!user) return null;
    Object.assign(user, updateUserDto);
    return user;
  }

  remove(id: number) {
    this.users = this.users.filter((user) => user.id !== id);
    return { deleted: true };
  }
}
  • @Injectable() โ†’ Marks class as a service that can be injected into controllers.
  • Business logic lives here.

โ€” โ€”

Test Files

๐Ÿ“Œ user.controller.spec.ts:-

import { Test, TestingModule } from '@nestjs/testing';
import { UserController } from './user.controller';
import { UserService } from './user.service';

describe('UserController', () => {
  let controller: UserController;

  beforeEach(async () => {
  const module: TestingModule = await Test.createTestingModule({
  controllers: [UserController],
  providers: [UserService],
  }).compile();

  controller = module.get<UserController>(UserController);
  });
  it('should be defined', () => {
  expect(controller).toBeDefined();
  });
});

๐Ÿ“Œ user.service.spec.ts:-

import { Test, TestingModule } from '@nestjs/testing';
import { UserService } from './user.service';

describe('UserService', () => {
  let service: UserService;

  beforeEach(async () => {
  const module: TestingModule = await Test.createTestingModule({
  providers: [UserService],
  }).compile();

  service = module.get<UserService>(UserService);
  });
  it('should be defined', () => {
  expect(service).toBeDefined();
  });
  });

โ€” -

๐Ÿ”น Full AppModule Setup

๐Ÿ“Œ app.module.ts:-

import { Module } from '@nestjs/common';
import { UserModule } from './user/user.module';

@Module({
  imports: [UserModule], // Register UserModule here
  controllers: [],
  providers: [],
  })

export class AppModule {}

๐Ÿ‘‰ Why?

  • The AppModule is the root module.
  • Importing UserModule makes its routes/services available to the whole app.

โ€” โ€”

๐Ÿ”น Request โ†’ Response Flow (with Diagram)

NestJS request flow diagram

โ€” โ€”

๐Ÿ”น CRUD Endpoints for User

1. GET All Users

curl http://localhost:3000/user

๐Ÿ‘‰ Returns empty array [] initially.

2. POST Create User

curl -X POST http://localhost:3000/user \
-H "Content-Type: application/json" \
-d '{"name": "Ajay", "email": "ajay@example.com"}'

3. GET One User

curl http://localhost:3000/user/1692817731123

4. PATCH Update User

curl -X PATCH http://localhost:3000/user/1692817731123 \
-H "Content-Type: application/json" \
-d '{"email": "ajay.new@example.com"}'

5. DELETE User

curl -X DELETE http://localhost:3000/user/1692817731123

โ€” โ€”

๐Ÿ”น Error Handling in NestJS

Throwing Errors:-

import { NotFoundException } from '@nestjs/common';

findOne(id: number) {
  const user = this.users.find((u) => u.id === id);
  if (!user) {
    throw new NotFoundException(`User with ID ${id} not found`);
  }
  return user;
}

Custom Error Responses

import { HttpException, HttpStatus } from '@nestjs/common';
  update(id: number, dto: UpdateUserDto) {
    const user = this.findOne(id);
    if (!user) {
      throw new HttpException(
      { status: HttpStatus.NOT_FOUND, error: 'User not found' },
      HttpStatus.NOT_FOUND,
      );
    }
    Object.assign(user, dto);
    return user;
  }

โ€” โ€”

๐Ÿ”น Next Steps (DB Integration Preview)

In the next tutorial, weโ€™ll:

  • Add a database (MongoDB or PostgreSQL)
  • Use TypeORM/Mongoose
  • Implement DTOs, validation pipes, and schemas
  • Replace in-memory storage with a persistent DB

โ€” โ€”


๋ฉ”ํƒ€๋ฐ์ดํ„ฐ
post_id
82cd2c75624e
slug
day-2-building-a-core-feature-with-nestjs-the-user-module-82cd2c75624e
url
https://medium.com/@ajaymaurya6798/day-2-building-a-core-feature-with-nestjs-the-user-module-82cd2c75624e
canonical_url
https://medium.com/@ajaymaurya6798/day-2-building-a-core-feature-with-nestjs-the-user-module-82cd2c75624e
author_url
https://medium.com/@ajaymaurya6798
status
ok
fetched_at
2026-08-24 15:44:55