Hands-On with NestJS: Building a Simple API

Building APIs with plain Node.js feels great at first, but as your project grows, so does the mess. NestJS is here to change that. It offers a structured, scalable, and TypeScript-first approach to backend development, inspired by Angular’s architecture.

In this hands-on guide, we will build a simple, clean REST API using NestJS. Whether you’re completely new to NestJS or you’ve peeked at it and got overwhelmed by the decorators, this guide will walk you through the process step by step.

What We Are Building

A basic User API that lets you:

  • Fetch all users
  • Fetch a specific user by ID
  • Create a new user

We will keep things minimal to focus on understanding the structure and workflow of a NestJS project.

Prerequisites

Before we begin, make sure you have:

  • Node.js (version 16 or higher recommended)
  • npm or yarn
  • Basic understanding of TypeScript (optional but helpful)

Setting Up the Project

1. Install NestJS CLI

npm i -g @nestjs/cli

2. Create a New Project

nest new user-api

Choose your preferred package manager when prompted.

3. Navigate to Project Folder

cd user-api

At this point, NestJS has already generated a boilerplate structure for you.

Project Structure Overview

NestJS generates a clean folder structure:

  • src/app.module.ts – Root module
  • src/main.ts – Application entry point
  • src/app.controller.ts – Example controller
  • src/app.service.ts – Example service

We will now create a dedicated User Module to keep things organized.

Creating the User Module, Controller, and Service

1. Generate User Module

nest generate module users

2. Generate User Controller

nest generate controller users

3. Generate User Service

nest generate service users

You now have:

  • users/users.module.ts
  • users/users.controller.ts
  • users/users.service.ts

Start Building Your NestJS API Today

Building the User Service

Open users.service.ts and add some dummy data:

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

@Injectable()
export class UsersService {
private users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
];

findAll() {
return this.users;
}

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

create(user: { id: number; name: string }) {
this.users.push(user);
return user;
}
}

Building the User Controller

Open users.controller.ts and wire up the routes:

import { Controller, Get, Param, Post, Body } from '@nestjs/common';
import { UsersService } from './users.service';

@Controller('users')
export class UsersController {
constructor(private usersService: UsersService) {}

@Get()
findAll() {
return this.usersService.findAll();
}

@Get(':id')
findOne(@Param('id') id: string) {
return this.usersService.findOne(Number(id));
}

@Post()
create(@Body() user: { id: number; name: string }) {
return this.usersService.create(user);
}
}

Register the Module

Make sure to import UsersModule in app.module.ts:

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UsersModule } from './users/users.module';

@Module({
imports: [UsersModule],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}

Testing the API

1. Run the Server

npm run start

2. Test the Endpoints

  • GET http://localhost:3000/users – Fetch all users
  • GET http://localhost:3000/users/1 – Fetch user with ID 1
  • POST http://localhost:3000/users – Create a new user (send JSON body with id and name)

Use Postman, cURL, or your browser for GET requests to verify the API works.

Key Takeaways

  • NestJS enforces modular, maintainable code structure by default
  • Controllers handle routes and request mapping
  • Services encapsulate business logic and data handling
  • The CLI simplifies scaffolding of new features
  • TypeScript and decorators may feel verbose but provide strong structure and clarity
coma

Final Thoughts

NestJS takes some getting used to, especially if you are new to TypeScript or Angular-like patterns. But once you understand the building blocks, it becomes a powerful, scalable tool for building robust backend APIs.

This simple API barely scratches the surface. With NestJS, you can easily add:

  • Data persistence with TypeORM or Prisma
  • Request validation with Pipes
  • Authorization with Guards
  • Exception handling with Filters
  • And even microservices or GraphQL support

NestJS isn’t just another framework. It’s a well-architected system designed for serious backend.

Keep Reading

Keep Reading

  • Let's create something together!