Introduction
NestJS, a progressive Node.js framework for building efficient and scalable server-side applications, pairs well with MongoDB for managing data. This tutorial will walk you through setting up a simple CRUD application using NestJS with MongoDB.
Setting Up Your Project
First, ensure you have Node.js installed. Then, install the Nest CLI:
npm i -g @nestjs/cli
Create a new NestJS project:
nest new nestjs-mongodb-crud
Once the installation is complete, change into your new project directory:
cd nestjs-mongodb-crud
Installing Dependencies
Install necessary packages for MongoDB:
npm install --save @nestjs/mongoose mongoose
Connecting to MongoDB
In your app.module.ts
, import MongooseModule and set up the connection:
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
@Module({
imports: [
MongooseModule.forRoot('mongodb://localhost/nest'),
],
controllers: [],
providers: [],
})
export class AppModule {}
Replace the connection string with your MongoDB URI if necessary.
Creating a Schema
Create a schema that reflects the structure of the data in MongoDB. For instance, if you’re managing a list of tasks, here’s how a task schema might look.
import * as mongoose from 'mongoose';
export const TaskSchema = new mongoose.Schema({
title: String,
description: String,
completed: Boolean,
});
Defining a Model
With the schema ready, let’s define the model in a service file:
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { Task, TaskDocument } from './schemas/task.schema';
@Injectable()
export class TasksService {
constructor(@InjectModel(Task.name) private taskModel: Model<TaskDocument>) {}
// CRUD methods to be added here
}
Implementing CRUD Operations
Let’s implement the typical CRUD operations: Create, Read (one and all), Update, and Delete for a tasks resource.
Create Operation
async create(createTaskDto: CreateTaskDto): Promise<Task> {
const createdTask = new this.taskModel(createTaskDto);
return createdTask.save();
}
Read Operations
async findAll(): Promise<Task[]> {
return this.taskModel.find().exec();
}
async findOne(id: string): Promise<Task> {
return this.taskModel.findById(id).exec();
}
Update Operation
async update(id: string, updateTaskDto: UpdateTaskDto): Promise<Task> {
return this.taskModel.findByIdAndUpdate(
id,
updateTaskDto,
{ new: true }
).exec();
}
Delete Operation
async delete(id: string): Promise<any> {
return this.taskModel.findByIdAndRemove(id).exec();
}
Creating the Controller
Controllers handle incoming HTTP requests and invoke the correct service method. Below is an example of a controller with all the CRUD endpoints:
import { Controller, Get, Post, Put, Delete, Body, Param } from '@nestjs/common';
import { TasksService } from './tasks.service';
import { CreateTaskDto, UpdateTaskDto } from './dto';
@Controller('tasks')
export class TasksController {
constructor(private tasksService: TasksService) {}
@Post()
create(@Body() createTaskDto: CreateTaskDto) {
return this.tasksService.create(createTaskDto);
}
@Get()
findAll() {
return this.tasksService.findAll();
}
@Get(':id')
findOne(@Param('id') id: string) {
return this.tasksService.findOne(id);
}
@Put(':id')
update(@Param('id') id: string, @Body() updateTaskDto: UpdateTaskDto) {
return this.tasksService.update(id, updateTaskDto);
}
@Delete(':id')
delete(@Param('id') id: string) {
return this.tasksService.delete(id);
}
}
Error Handling and Validation
Use pipes for data validation and proper error handling. The ValidationPipe
can be used out-of-the-box to validate DTOs against defined class-validator decorators.
import { BadRequestException, PipeTransform, Injectable } from '@nestjs/common';
import { ObjectSchema } from 'joi';
@Injectable()
export class JoiValidationPipe implements PipeTransform {
constructor(private schema: ObjectSchema) {}
transform(value: any) {
const { error } = this.schema.validate(value);
if (error) {
throw new BadRequestException('Validation failed');
}
return value;
}
}
Conclusion
You now have a simple CRUD API using NestJS and MongoDB. This tutorial covered everything from setting up the project, connecting to MongoDB, defining schemas and models, to implementing CRUD operations and basic validation. Keep exploring and expanding on this foundation for more complex applications.