paint-brush
NestJS and Best Practicesby@renanb
1,833 reads
1,833 reads

NestJS and Best Practices

by Renan BotasseJuly 8th, 2024
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

NestJS is a Node.js framework that utilizes TypeScript for backend development. Domain-Driven Design (DDD) is a methodology for organizing application structure, enhancing maintainability, and facilitating scalability. This text explains how DDD principles are applied within NestJS, adhering to best practices.
featured image - NestJS and Best Practices
Renan Botasse HackerNoon profile picture


Introduction

NestJS is a Node.js framework that utilizes TypeScript for backend development. Domain-Driven Design (DDD) is a methodology for organizing application structure, enhancing maintainability, and facilitating scalability. This text explains how DDD principles are applied within NestJS, adhering to best practices that streamline development and ensuring fluidity, security, and organization.


Best Practices in NestJS Folder Structure

One of the initial considerations when starting a project is where to place files and how they will relate to each other. A well-organized folder structure is crucial for maintaining and scaling an application. Here are some key concepts to follow for standardizing folder organization:


1. Features and Folders

The project should be divided into unique folders for each feature. This approach enhances code location and standardization. All functionalities related to users, for instance, should reside within a users folder.

Additionally, file names should reflect their functionalities, further aiding in easy location. Files handling the same functionality should be within the same folder, ensuring all necessary components are consolidated.

Here's an example that illustrates this concept:

src/
├── users/
│   ├── controllers/
│   │   └── users.controller.ts
│   ├── services/
│   │   └── users.service.ts
│   ├── dtos/
│   │   └── create-user.dto.ts
│   ├── entities/
│   │   └── user.entity.ts
│   ├── repositories/
│   │   └── users.repository.ts
│   ├── users.module.ts
├── auth/
│   ├── controllers/
│   │   └── auth.controller.ts
│   ├── services/
│   │   └── auth.service.ts
│   ├── dtos/
│   │   └── login.dto.ts
│   ├── entities/
│   │   └── auth.entity.ts
│   ├── repositories/
│   │   └── auth.repository.ts
│   ├── auth.module.ts
├── products/
│   ├── controllers/
│   │   └── products.controller.ts
│   ├── services/
│   │   └── products.service.ts
│   ├── dtos/
│   │   └── create-product.dto.ts
│   ├── entities/
│   │   └── product.entity.ts
│   ├── repositories/
│   │   └── products.repository.ts
│   ├── products.module.ts
├── app.module.ts
├── main.ts


2. Modules, Controllers, and Services

Modules

Modules act as the glue between components, services, and controllers. They are defined using the @Module() decorator, encapsulating specific functionalities and able to import other modules as needed.

Controllers

Controllers handle HTTP requests and are responsible for API endpoints. They utilize services to execute business logic and return specific information to users.

Controllers should not contain business logic; instead, the logic should reside within the Service layer, limiting the controller to handling requests and delegating business logic applications to services.

Services

Services are crucial files within the application containing business logic. They are used by controllers to perform complex operations such as database interactions, validations, and data manipulation.

Defined using the @Injectable() decorator, services can be injected into controllers or other services.


3. DTO - Data Transfer between Layers

Data Transfer Objects (DTOs) are objects used to transfer data between different parts of the application. They ensure data validity checks, consistency, and organization.

An example of their use is when constructing an application where users can register. Here’s how it looks:


  1. DTO Definition:

Define a DTO to represent the data transferred between the user creation route. The DTO may contain specific properties required for creating a new user, such as name, email, and password:

class CreateUserDTO {
    constructor(public name: string, public email: string, public password: string) {}
}

export default CreateUserDTO;
  • CreateUserDTO: Used to encapsulate the necessary data for creating a new user.
  • Controller: Utilizes the DTO to receive data from the registration form, validate the data (like email format), and then pass it to the user service (userService) for additional processing, such as saving to the database.


Folder Functionality

Folder structures should align with the functionality of each folder type:

  • /src: Contains application code.
    • /app: Core application files.
    • /controllers: Handles HTTP requests.
    • /modules: Groups related functionalities.
    • /services: Business logic and data access.
    • /config: Configuration files.
    • /dto: Data transfer objects.
    • /middlewares: Custom middleware functions.
    • /test: Unit and integration tests.
    • /utils: Utility functions and helper classes.
  • main.ts: Entry point of the application.
  • .env: Environment variables and configurations.