Table of contents
INTRODUCTION
In today's digital world, web application development is becoming increasingly vital. It allows firms to reach a larger audience while also streamlining their processes. As a result, an increasing number of businesses are investing in custom web apps to satisfy their unique requirements.
What Is Nest JS
NestJS is a growing framework for making server-side applications using NodeJS. By default it makes use of ExpressJS platform and can be configured to make use of Fastify, it combines features of both object-oriented programming and functional programming. It uses TypeScript during initialization, but it may easily be configured to utilize plain JavaScript. It has a similar structure and organization to AngularJS.
NestJS is a really good tool for building projects with scalability in mind. It helps you start your project quickly and it's also easy to understand because it's organized in a way that makes sense.
Overview of NestJS architecture and modules
The framework is designed using a modular architecture, which means it is made up of smaller, reusable pieces known as modules. These modules interact to provide the functionality necessary for the development of a complete application. Think of the modules in NestJS as lego blocks. When you put these blocks together, they make a big structure, like a house or a bridge. In NestJS, we use different modules to make a web application. You can easily add or remove modules to change what your application can do. It's like playing with lego toys, but instead of making a toy, you make a web application!
You might ask what exactly do these modules contain, well in nestjs modular architecture they may include things like the;
Controller
in a NestJS module helps to handle requests from a user and send back the right response. It acts like a middleman between the client and the server. A Controller has different places to go to, called endpoints, each with a unique address and way to communicate like GET
, POST
, PUT
, and DELETE
which are referred to as HTTP
Methods.
Service
is like a helper that handles business logic and helps the Controller do its job. The Controller talks to the customers, but the Service helps it do the work by doing things like talking to the computer database and making sure everything runs smoothly. Services can be used by different parts of the program, making it easier to manage and take care of the code.
Provider
allows you to connect to other systems such as a database or external systems. Consider it a unique employee who assists you in obtaining information from outside your program so that you may utilize it to improve your online application.
These components work in unison to create a fully working web application.
Prerequisite
Knowledge of JavaScript and a Basic Understanding of TypeScript.
Node Installed.
Understanding of Object-Oriented Programming and different Data Types.
Setting up a development environment for NestJS
Setting up a NestJS application for development is simple. NestJS has a special command line that helps you create your project quickly using just a few simple commands. This makes starting your project and getting your ideas off the ground even easier.
To get started, if you are making use of a windows system open Command Prompt or Windows PowerShell and enter this command below.
npm i -g @nestjs/cli
if you are making use of a Linux Distribution, open your Terminal
and run this command below.
sudo npm i -g @nestjs/cli
Wait for the installation to complete.
Verify that the NestJS CLI has been installed by running this command below. When it outputs the version then you know you have successfully installed the Nestjs Command-Line to your system.
nest --version
Creating your first NestJS application
Now that you have installed and set up NestJs on your system, let's go on to create a Simple REST API with NestJs NestJs has some special CLI
commands that can help you quickly bootstrap your project, to get started on your terminal you will enter this command below.
nest new task-api
A selection field will appear for you to select the package manager to be used, either one of NPM
, YARN
or PNPM
.
You can select the package manager of your choice, I recommend NPM for this article, and then installation of the packages for the project build-up continues.
After completion, a skeleton project is generated that includes some configuration files, an example of a GET request, and test cases for it. You then navigate to the folder created by this command.
cd task-api
The folder structure should appear like this when you open this project folder in your editor (vs code).
The NestJs CLI
includes a special command to rapidly spin up a REST api project using the nest create resource
as you are constructing a task project, so you input the command in your terminal now as you go on to produce the resource such as services, controllers, Entities, Modules, DTOs, etc.
nest generate resource task
Some choice fields will display on the desired transport layer, which is REST API
, and if you wish to produce CRUD
entry points.
In your editor, you will see the task folder has been added with some subfolders and files and also that it has updated the root appModule appropriately.
For this project, you will use SQLite
database with TypeOrm to connect to it. You will then install these packages using this below.
npm install --save @nestjs/typeorm typeorm sqlite3 class-validator
After it has been installed you then open your editor and make changes to your codes by importing the TypeOrmModule into the root AppModule.
Adding a data source with TypeORM and creating entities
Also adding the entity to the taskModule file through TypeOrmModule.
Then next you define the columns or items that should make up your task list in the entity file like this below.
And you also define the columns for validation in your DTO
file.
Creating a simple REST API
The database repository is then added to the task service by importing InjectRepository
and Repository
in a constructor.
You then proceed to create the first method needed for your project which is an Instance of a POST
request.
createTask(createTaskDto: CreateTaskDto): Promise<Tasks> {
const data = new Tasks();
data.task = createTaskDto.task;
data.duration = createTaskDto.duration;
return this.taskRepository.save(data);
}
This method creates a task, it takes in an object named CreateTaskDto
as a parameter. This object includes the information needed to make the task. The method then creates the task using the data from CreateTaskDto
and saves it to our database.
You then create a route for it in our task.controller.ts
file.
@Post()
async create(@Body() createTaskDto: CreateTaskDto, @Res() res, @Next() next) {
try {
const task = await this.taskService.createTask(createTaskDto);
return res.status(HttpStatus.OK).json({
success: true,
data: task,
message: 'Task Created',
});
} catch (error) {
next(error);
}
}
You first add in the @POST
decorator to ensure it uses the HTTPS
Method, function begins by trying to create a task with the taskService.createTask method and the createTaskDto argument. If the task is successfully generated, the function returns to the client with a success status, a message, and the newly formed task's data.
Then you go on to create the findOne
which queries our database and returns a single task via it's ID
.
async findOne(id: string): Promise<Tasks> {
const data = await this.taskRepository.findOne({ where: { id } });
if (data) {
return data;
}
throw new NotFoundException('Task Not Found');
}
Then you create the corresponding route in your controller for this service method.
@Get(':id')
async findOne(@Param('id') id: string, @Res() res, @Next() next) {
try {
const task = await this.taskService.findOne(id);
return res.status(HttpStatus.OK).json({
success: true,
data: task,
message: 'Task Available',
});
} catch (error) {
next(error);
}
this.taskService.findOne(id);
}
Here you create a function in the Controller that will handle a GET request to the route "tasks/:id"
. The @Get
decorator tells NestJS to expect a GET
request and the ':id'
part is a placeholder for a specific task ID.
You then proceed to create a findAll
method in our service to be able to fetch all tasks saved to our SQLite
database.
async findAll(): Promise<Tasks[]> {
const datas = this.taskRepository.find();
if (datas) {
return datas;
}
throw new NotFoundException('Tasks Not Found')
}
You then create a controller function
that implements this service.
@Get()
async findAll(@Res() res, @Next() next) {
try {
const tasks = await this.taskService.findAll();
return res.status(HttpStatus.OK).json({
success: true,
data: tasks,
message: 'List Of Task Available',
});
} catch (error) {
next(error);
}
}
It is similar to the findOne
function, but it does not require an ID
to be provided in and it does not limit the number of tasks it retrieves. To implement the update
function in our service, you supply two arguments: the id
to find the specific task and the updateTaskDto
, which acts as the body that modifies the task, followed by a return. The promise of an updateResult
.
async update(id: string, updateTaskDto: UpdateTaskDto): Promise<UpdateResult> {
const data = await this.taskRepository.update(id, updateTaskDto);
if (data.affected === 0) {
throw new NotFoundException('Task Not Found');
}
return data;
}
You then also make a route for it in your controller
file below.
@Patch(':id')
async update(
@Param('id') id: string,
@Body() updateTaskDto: UpdateTaskDto,
@Res() res,
@Next() next,
) {
try {
await this.taskService.update(id, updateTaskDto);
const updatedTask = await this.taskService.findOne(id)
return res.status(HttpStatus.OK).json({
success: true,
data: updatedTask,
message: 'Task Updated',
});
} catch (error) {
next(error);
}
}
Here the method updates a task with information supplied in the updateTaskDto
. If successful, it receives the updated task data by executing the findOne
method on taskService and supplying the id
. Finally, it sends a response back to the client with a status of "OK" and a JSON
object that contains information on the success of the operation, the updated task data, and a message that states "Task Updated". In case of failures throughout the procedure, the technique includes error handling by utilizing the try-catch
statement and the next
function.
Then finally you create the delete
method in the task service, here you pass in the ID
as the argument, that enables the method to query the database and find a particular task that is to be deleted, if it's not found it throws an error.
async delete(id: string): Promise<{ success: boolean }> {
const data = await this.taskRepository.delete(id);
if (data.affected) {
return { success: true };
} else {
throw new NotFoundException('Task Not Found');
}
}
You create the route for this in the controller file below.
@Delete(':id')
async remove(@Param('id') id: string, @Res() res, @Next() next) {
try {
const task = await this.taskService.delete(id);
return res.status(HttpStatus.OK).json({
success: true,
data: task,
message: 'Task Deleted',
});
} catch (error) {
next(error);
}
}
The @Delete
decorator provides the endpoint responsible for handling deletion requests. The endpoint gives the task's ID
as an argument to the delete method.
The taskService
is used by the remove function to delete the task with the provided ID. If the deletion is successful, the method produces a JSON
response with the "success" field set to true and the message "Task Deleted" set to true.
Testing the REST API using Postman
Great! you've implemented a REST
API, now head over to Postman and test out these endpoints to see how they work.
You then select a method, to create you will make use of POST
then you provide the route, in the image below it is 127.0.0.1:3000
but it can also be localhost:3000
, In body
you select raw
and choose JSON
then you give a JSON
input in the box, here the body requests for a task
and duration
key and the value
should be in a string.
Then you will get back a response with status 200
, the entry has been saved to the SQLite
database, To test the findOne
endpoint, you switch the method to a GET
.
Then you try out the findAll
next, it's also a GET
request,
you can see that it brought out more than one response, and it doesn't need an ID
parameter to fetch these data.
Next, you try the update
the route, here it needs an Id
to be provided to query the database and also new JSON
data as the body that updates the fetched data.
Then now finally test the delete
route, it requires you passing in an ID
as a parameter and setting the HTTP
method to delete.
You set up error handlers so that you can always appropriately detect any error that arises while sending requests using the various HTTP protocols.
Conclusion
Finally, Nest.js is a robust and flexible framework for creating scalable and effective server-side applications. It is built on top of well-known technologies like Node.js and TypeScript and offers a strong basis for creating RESTful APIs.
We've now covered the fundamentals of using TypeScript and NestJS to build a simple task project. We have spoken about utilizing the NestJS framework to construct various CRUD operations and handle errors. Separation of concerns is ensured and the management of the program is made simpler by the use of dependency injection and the modular pattern. With the information from this tutorial, you may create more reliable and scalable apps and continue to learn TypeScript and the NestJS framework.
I hope this article has been a valuable introduction to Nest.js for beginners. If you have found it helpful and would like to stay up to date with my future writing, be sure to subscribe or follow me [Okoye Chukwuebuka Victor] for more exciting articles. Thank you for your time and I look forward to bringing you more great content in the future!.