Introduction
NestJS is a progressive Node.js framework for building efficient, reliable, and scalable server-side applications. In this guide, we'll walk through creating a RESTful API using NestJS, highlighting its key features and best practices.
Prerequisites
- Node.js (v14 or later)
- npm or yarn
- Basic TypeScript knowledge
- Understanding of REST principles
Setting Up the Project
First, let's install the NestJS CLI and create a new project:
npm i -g @nestjs/cli
nest new nestjs-api
cd nestjs-api
Project Structure
After initialization, you'll have a basic project structure:
src/
├── app.controller.ts
├── app.module.ts
├── app.service.ts
└── main.ts
Creating a Basic REST API
Let's create a simple API for managing books. We'll implement CRUD operations (Create, Read, Update, Delete).
1. Generate Resources
nest generate resource books
This command creates all necessary files for the books module.
2. Define the Book Entity
Create src/books/entities/book.entity.ts
:
export class Book {
id: number;
title: string;
author: string;
published: Date;
price: number;
}
3. Create DTOs
In src/books/dto/create-book.dto.ts
:
import { IsNotEmpty, IsNumber, IsString, IsDate } from 'class-validator';
export class CreateBookDto {
@IsNotEmpty()
@IsString()
title: string;
@IsNotEmpty()
@IsString()
author: string;
@IsDate()
published: Date;
@IsNumber()
price: number;
}
4. Implement the Controller
Update src/books/books.controller.ts
:
import { Controller, Get, Post, Body, Put, Param, Delete } from '@nestjs/common';
import { BooksService } from './books.service';
import { CreateBookDto } from './dto/create-book.dto';
import { UpdateBookDto } from './dto/update-book.dto';
@Controller('books')
export class BooksController {
constructor(private readonly booksService: BooksService) {}
@Post()
create(@Body() createBookDto: CreateBookDto) {
return this.booksService.create(createBookDto);
}
@Get()
findAll() {
return this.booksService.findAll();
}
@Get(':id')
findOne(@Param('id') id: string) {
return this.booksService.findOne(+id);
}
@Put(':id')
update(@Param('id') id: string, @Body() updateBookDto: UpdateBookDto) {
return this.booksService.update(+id, updateBookDto);
}
@Delete(':id')
remove(@Param('id') id: string) {
return this.booksService.remove(+id);
}
}
5. Implement the Service
Update src/books/books.service.ts
:
import { Injectable, NotFoundException } from '@nestjs/common';
import { CreateBookDto } from './dto/create-book.dto';
import { UpdateBookDto } from './dto/update-book.dto';
import { Book } from './entities/book.entity';
@Injectable()
export class BooksService {
private books: Book[] = [];
create(createBookDto: CreateBookDto) {
const book = {
id: this.books.length + 1,
...createBookDto,
};
this.books.push(book);
return book;
}
findAll() {
return this.books;
}
findOne(id: number) {
const book = this.books.find(book => book.id === id);
if (!book) {
throw new NotFoundException(`Book #${id} not found`);
}
return book;
}
update(id: number, updateBookDto: UpdateBookDto) {
const bookIndex = this.books.findIndex(book => book.id === id);
if (bookIndex === -1) {
throw new NotFoundException(`Book #${id} not found`);
}
this.books[bookIndex] = {
...this.books[bookIndex],
...updateBookDto,
};
return this.books[bookIndex];
}
remove(id: number) {
const bookIndex = this.books.findIndex(book => book.id === id);
if (bookIndex === -1) {
throw new NotFoundException(`Book #${id} not found`);
}
this.books.splice(bookIndex, 1);
return { message: `Book #${id} deleted` };
}
}
Adding Validation
To implement validation, install required packages:
npm install class-validator class-transformer
Update main.ts
:
import { NestFactory } from '@nestjs/core';
import { ValidationPipe } from '@nestjs/common';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe());
await app.listen(3000);
}
bootstrap();
Testing the API
You can test your API using tools like Postman or curl:
Create a Book
curl -X POST http://localhost:3000/books \
-H "Content-Type: application/json" \
-d '{"title":"The Great Gatsby","author":"F. Scott Fitzgerald","published":"1925-04-10","price":9.99}'
Get All Books
curl http://localhost:3000/books
Get One Book
curl http://localhost:3000/books/1
Update a Book
curl -X PUT http://localhost:3000/books/1 \
-H "Content-Type: application/json" \
-d '{"price":14.99}'
Delete a Book
curl -X DELETE http://localhost:3000/books/1
Error Handling
NestJS provides built-in exception filters. Here's how to create a custom exception filter:
import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common';
import { Response } from 'express';
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const status = exception.getStatus();
const error = exception.getResponse();
response
.status(status)
.json({
statusCode: status,
timestamp: new Date().toISOString(),
error: error
});
}
}
Conclusion
This guide covered the basics of creating a RESTful API with NestJS. You've learned how to:
- Set up a NestJS project
- Create CRUD operations
- Implement validation
- Handle errors
- Test the API
To expand this application, consider adding:
- Database integration (TypeORM/Mongoose)
- Authentication/Authorization
- Swagger documentation
- Unit tests
- Environment configuration
- Logging middleware
NestJS provides a robust foundation for building scalable Node.js applications. Its modular architecture and TypeScript support make it an excellent choice for enterprise-grade applications.
Related Posts
5 min read
APIs (Application Programming Interfaces) are the backbone of modern digital applications. They allow different software systems to communicate, exchange data, and collaborate seamlessly. As businesse...