Meet NestJS

A translation of the article was prepared ahead of the launch of the Node.js Developer course .




Modern developers have many alternatives when it comes to creating web services and other server applications. Node has become an extremely popular choice, however, many programmers prefer a more robust language than JavaScript, especially those who come from modern object-oriented languages, such as C #, C ++ or Java. If TypeScript just suits NodeJS just fine , then the NestJS framework takes it to a whole new level, providing modern tools for the backend developer to create durable and high-performance applications using components, providers, modules, and other useful high-level abstractions.

In this article, we will look at the process of creating a simple API server on NestJS to process the basic application scenario: creating, storing and retrieving a list of supermarket products.
If you want to familiarize yourself with the source code of the project, you can find it here .

Project creation


To work with Nest, you need a Node environment. If you donโ€™t have it yet, go to their website and download it.

Installing the framework is quite simple:

$ npm i -g @nestjs/cli

This project was created using the Nest CLI after running the following command:

$ nest new nest-js-example

Such a team will create a completely new Nest project with the necessary configuration files, folder structure and server template.

Application entry point


The main file that configures and starts the server is src/main.ts:

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
	
    const app = await NestFactory.create(AppModule);
    await app.listen(3000);
}

bootstrap();

This file imports the NestFactory class , which is used to create the application, and the main AppModule file (which we will soon meet), and then downloads the application, instantiating it, and listens on port 3000.

App module


The file in which the application components are declared is called src/app.module.ts:

import { Module } from '@nestjs/common';
import { ItemsController } from './items/items.controller';
import { ItemsService } from './items/items.service';

@Module({
    imports: [],
    controllers: [ ItemsController ],
    providers: [ ItemsService ],
})

export class AppModule {}

This is the file where the other components are imported and declared in the Module, which is imported in the previous file ( main.ts ). The Nest CLI tools will automatically update this file as needed when instructed to create a new component. Here, the controller and service for items are imported and added to the module.

Items Controller


The next file that we will review is src/items/items.controller.ts:

import { Controller, Req, Get, Post, Body } from '@nestjs/common'
import { CreateItemDto } from './dto/create-item.dto'
import { ItemsService } from './items.service'
import { Item } from './items.interface'

@Controller('items')
export class ItemsController {

    constructor(private readonly itemsService: ItemsService) {}

    @Post()
    create(@Body() data: CreateItemDto): Object {
        return this.itemsService.create(data)
    }

    @Get()
    findAll(): Array<Item> {
        return this.itemsService.findAll()
    }
}

This file defines the controller for creating items and getting a list of previously created ones. Several key components are imported here:

  • CreateItemDto : A Data-Transfer object that defines how item data will be sent over the network (i.e. this is a JSON data structure);
  • ItemsService: Provider that handles the manipulation or storage of Item data ;
  • Item : An interface that defines the internal data structure for Item ;

The decorator @Controller('items')tells the framework that this class will serve the REST / items endpoint , and the ItemsController constructor takes an instance of ItemsService , which is used internally to serve two HTTP methods:

  • POST / items (creates a new item from a JSON request);
  • GET / items (getting a list of previously created items).

Requests for these two methods are handled by the create and FindAll methods, which are bound to the corresponding HTTP methods using the @Post()and decorators @Get(). Additional methods can also be supported by decorators in a similar way, for example, @Put()or @Delete(), etc.

Item Object Interfaces


Next, weโ€™ll deal with two files that define interfaces for storing item , one for internal use, such as type checking at compile time ( Item ), and an external interface for determining the expected structure of incoming JSON ( CreateItemDto):

export interface Item {
	
    name: string,
    description: string,
    price: number
}

export class CreateItemDto {

    @IsNotEmpty()
    readonly name: string;

    @IsNotEmpty()
    readonly description: string;

    @IsNotEmpty()
    readonly price: number;
}

The Item interface defines three properties of a regular store product: name, description and price. This ensures that there is no confusion in the application architecture regarding what an item is and what properties it has.

The CreateItemDto class reflects Item properties , decorating each property @IsNotEmpty()to ensure that all of these properties are requested by the REST API endpoint.

All properties of both classes are strongly typed, which is one of the main advantages of TypeScript (hence the name). At first glance, this increases the level of understanding of the context, and significantly reduces development time if used correctly with code analysis tools (such as IntelliSense in VSCode). This is especially true for large projects with hundreds or even thousands of different classes and interfaces. For those who do not have perfect photographic memory with an infinite capacity (for example, for me), it is much easier than trying to remember thousands of specific details.

Items Service


The most recent is a service for creating and receiving items: items.service.dart:

import { Injectable } from '@nestjs/common'
import { Item } from './items.interface'

@Injectable()
export class ItemsService {

    private items: Array<Item> = []

    create(item: Item): Object {

        this.items.push(item) 
        return { id: this.items.length.toString() }
    }

    findAll(): Array<Item> {

        return this.items;
    }
}

The ItemsService class defines a simple array of Item objects that will serve as the in-memory data store for our sample project. Two methods that write and read from this repository are:

  • create (saves Item to the list and returns its id);
  • findAll (returns a list of previously created Item objects ).

Testing


To start the server, use the standard npm run start command . When the application is launched, it can be tested by sending HTTP requests via CURL :

$ curl -X POST localhost:3000/items -d '{"name":"trinket", "description":"whatever", "price": 42.0}'

Executing this command will return a JSON response with the id generated by item . To show a list of items that have already been created, use:

$ curl localhost:3000/items

The GET request to / items above will return a JSON response with information about the items that are already in memory. The answer should look something like this:

[{"{\"name\":\"trinket\", \"description\":\"whatever\", \"price\": 42.0}":""}]

Conclusion


NestJS is a relatively new solution in the field of backend development, with a large set of functions for quickly building and deploying corporate services that meet the requirements of modern application clients and adhere to the principles of SOLID and the application of twelve factors .

To learn more, visit the NestJS website .
Thank you for reading my article. Happy coding!

All Articles