How To Get Started From Express To NestJS: Complete Guide
Tags: programming, beginners, nestjs, javascript
Published: 2024-02-05 12:01:36

## Introduction:

Backend Developers like myself in the Node.js space looking to transition from Express.js a flexible and often straight forward framework to Nest.js a more structured and organized architecture to enhance the maintainability and scalability of your application. In this guide, we'll explore the key concepts of Nest.js, providing detailed examples and code snippets along the way.

## Advantages of NestJS over Express:

NestJS offers several benefits that makes it an appealing alternative choice for developers:

* **Modularity**: NestJS is built with modularity in mind, allowing you to organize your code into manageable modules.
    
* **Dependency Injection**: NestJS also comes with built-in dependency which simplifies code organization and promotes testability.
    
* **Decorators and Metadata**: NestJS use of decorators and metadata simplifies the creation of controllers, services, and modules.
    
* **Typescript and Microservices**: NestJS is built with [Typescript](https://hashnode.com/post/getting-started-with-typescript-ckpa0jge00u7gvws1cwajd5j5) and [Microservices](https://medium.com/widle-studio/mastering-microservices-in-nest-js-eb143a6b9639) in mind, providing strong typing and enhanced developer experience in using microservices like RabbitMQ, Kafka.
    

### Resources

* [Node.js Documentation](https://nodejs.org/en/docs)
    
* [Nest.js Documentation](https://nestjs.com/)
    
* [Express.js Documentation](https://expressjs.com/)
    

## NestJS Project Setup


![NestJS welcome page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wzaabinvsj82pdsko58c.png)

### Installing the NestJS CLI

To get started, install the NestJS CLI globally:

```basic
npm install -g @nestjs/cli
```

The NestJS CLI simplies nest project creation and component generation, providing a seamless development experience.

### NestJS Project Creation

Next, we create a new NestJS project named "my-nest-app":

```bash
nest new my-nest-app
```

After this command is executed on your CLI you get a prompt asking your preferred package manager:

```bash
⚡  We will scaffold your app in a few seconds..

? Which package manager would you ❤️  to use? (Use arrow keys)
> npm
  yarn
  pnpm
```

Now once your preference has been selected, the project structure and necessary dependencies installs. Navigate to the project directory:

```bash
cd my-nest-app
```

## Application Structures: NestJS vs. Express

Let's compare the directory structures of NestJS and Express: **NestJS Project Structure**

```plaintext
src/
|-- controllers/
|   |-- app.controller.ts
|-- modules/
|   |-- app.module.ts
|-- services/
|   |-- app.service.ts
|-- main.ts
```

Express Project Structure

```plaintext
routes/
|-- appRoutes.js
|-- userRoutes.js
|-- ...
models/
|-- userModel.js
|-- ...
app.js
```

In NestJS, we organize our code into modules, controllers, and services, promoting a modular and scalable architecture.

## Controllers in NestJS vs. Routes in Express
![Controllers flow](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fxgb7nm1td1v6rej46lc.png)

### Introduction to Controllers

In NestJS, controllers play a crucial role in handling incoming requests and shaping the application's behavior. They're similar to Express routes but provide additional features.

### Comparing Controllers to Routes

Let's consider a CRUD example to illustrate the differences between controllers in NestJS and routes in Express.

**NestJS Controller**

```typescript
import { Controller, Get, Post, Body } from '@nestjs/common';
import { CatsService } from './cats.service';
import { Cat } from './interfaces/cat.interface';

@Controller('cats')
export class CatsController {
  constructor(private readonly catsService: CatsService) {}

  @Get()
  findAll(): Cat[] {
    return this.catsService.findAll();
  }

  @Post()
  create(@Body() createCatDto: any): string {
    return `This action adds a new cat: ${createCatDto.name}`;
  }
}
```

The `@Controller` decorator specifies the base route for all the routes defined within the controller.

**Express Routes**

```typescript
const express = require('express');
const router = express.Router();
const catsService = require('../services/cats.service');

router.get('/', (req, res) => {
  const allCats = catsService.findAll();
  res.json(allCats);
});

router.post('/', (req, res) => {
  const newCat = req.body;
  res.send(`This action adds a new cat: ${newCat.name}`);
});

module.exports = router;
```

In Express, routes are defined using the `express.Router()` and then exported.

## Dependency Injection and Services


![Service Injection](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l2ka9w2yqptyfit7nwzk.png)

### Understanding Dependency Injection in NestJS

NestJS embraces the [concept of dependency injection (DI) for managing and injecting dependencies into components](https://www.freecodecamp.org/news/a-quick-intro-to-dependency-injection-what-it-is-and-when-to-use-it-7578c84fa88f/#:~:text=In%20software%20engineering%2C%20dependency%20injection,be%20used%20(a%20service).). In contrast to Express, which often relies on singleton patterns, NestJS promotes the use of injectable services.

Transitioning from Singleton Patterns to Injectable Services Let's refactor a simple Express service to a NestJS injectable service.

**Express Singleton Service**

```typescript
class CatService {
  constructor() {
    this.cats = [];
  }

  findAll() {
    return this.cats;
  }
}

module.exports = new CatService();
```

In this example, the service is a singleton instance exported for global use.

**NestJS Injectable Service**

```typescript
import { Injectable } from '@nestjs/common';

@Injectable()
export class CatsService {
  private cats = [];

  findAll(): any[] {
    return this.cats;
  }
}
```

By using the @Injectable decorator, we define a service that can be injected into controllers or other services.

## ORM in NestJS

### Setting Up TypeORM Entity

NestJS supports various [Object-Relational Mapping (ORM) and Object-Document Mapping (ODM) libraries](https://medium.com/@julianam.tyler/what-is-the-difference-between-odm-and-orm-267bbb7778b0). Let's set up a `TypeORM` entity for PostgreSQL:

**Install**`TypeORM` and PostgreSQL Package

```bash
npm install --save @nestjs/typeorm typeorm pg
```

Configure the module in app.module.ts:

```typescript
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { CatsModule } from './cats/cats.module';

@Module({
  imports: [
    CatsModule,
    TypeOrmModule.forRoot({
      type: 'postgres',
      host: 'localhost',
      port: 5432,
      username: 'nestuser',
      password: 'nestpassword',
      database: 'nestjs',
      synchronize: true,
      entities: [__dirname + '/**/*.entity{.ts,.js}'],
    }),
  ],
})
export class AppModule {}
```

**Define a TypeORM entity in cats/cat.entity.ts**:

```typescript
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';

@Entity()
export class Cat {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  name: string;

  @Column()
  age: number;

  @Column()
  breed: string;
}
```

This example sets up a PostgreSQL database with TypeORM and defines a Cat entity.

## Data Validation and Validation Pipes

![Active Validation Error Catch](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z18ydzqzcekvp5j9tr2e.png)

### Class Validators and Global Validation Pipe

NestJS simplifies data validation using class validators and global validation pipes. Let's explore how to use these features.

**Using Class Validators** Create a DTO (Data Transfer Object) in `cats/dto/create-cat.dto.ts`:

```typescript
import { IsString, IsInt } from 'class-validator';

export class CreateCatDto {
  @IsString()
  readonly name: string;

  @IsInt()
  readonly age: number;

  @IsString()
  readonly breed: string;
}
```

**In the corresponding controller, use the DTO with class validation**:

```typescript
import { Controller, Post, Body, UsePipes, ValidationPipe } from '@nestjs/common';
import { CreateCatDto } from './dto/create-cat.dto';
import { CatsService } from './cats.service';

@Controller('cats')
export class CatsController {
  constructor(private readonly catsService: CatsService) {}

  @Post()
  @UsePipes(new ValidationPipe({ transform: true }))
  create(@Body() createCatDto: CreateCatDto): string {
    this.catsService.create(createCatDto);
    return `Cat ${createCatDto.name} created successfully`;
  }
}
```

Here, the @UsePipes(new ValidationPipe({ transform: true })) decorator applies the global validation pipe to the create route, validating incoming data against the CreateCatDto schema. The transform: true option automatically transforms incoming payload data into instances of the DTO.

### Global Validation Pipe Configuration

**Configure the global validation pipe in main.ts**:

```javascript
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(new ValidationPipe({ transform: true }));
  await app.listen(3000);
}
bootstrap();
```

In this configuration, useGlobalPipes applies the validation pipe globally for all routes, ensuring that data is validated and transformed consistently across the application.

Now, every incoming request to your NestJS application will undergo validation against the defined DTO schemas, providing a robust and centralized approach to data validation.

## Testing in NestJS

### Writing Tests for NestJS Applications

NestJS includes built-in testing utilities that make it easy to write unit and integration tests for your application. Let's explore testing approaches using Jest in NestJS compared to testing in Express.

### Setting Up Jest  
NestJS Jest is a popular testing framework that works seamlessly with NestJS. **Install the required packages**:

```bash
npm install --save-dev @nestjs/testing jest @nestjs/schematics
```

**Configure Jest in**`jest.config.js`:

```typescript
module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
};
```

### Writing a Basic Unit Test

Let's write a simple unit test for a service in `cats/cats.service.spec.ts`:

```typescript
import { Test, TestingModule } from '@nestjs/testing';
import { CatsService } from './cats.service';

describe('CatsService', () => {
  let service: CatsService;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [CatsService],
    }).compile();

    service = module.get<CatsService>(CatsService);
  });

  it('should be defined', () => {
    expect(service).toBeDefined();
  });

  it('should return an array of cats', () => {
    const cats = service.findAll();
    expect(Array.isArray(cats)).toBe(true);
  });
});
```

In this example, we're testing the CatsService to ensure it returns an array of cats.

### Running Tests

**Execute the tests with the following command**:

```bash
npm run test
```

Jest will run the tests and provide feedback on their success or failure.

## Conclusion

Migrating from Express to NestJS might be overwhelming at first, but the benefits of a structured and modular architecture will greatly enhance your maintainability and scalability of your application.

Here’s a link to my main blog site: [Bliss Articles](https://blissfelix.info)

[![Buy Me A Coffee](https://cdn.buymeacoffee.com/buttons/default-black.png)](https://www.buymeacoffee.com/BlissFelix)

I appreciate you taking the time to read this😁. Please think about giving it a ❤️ if you found it useful and instructive and bookmarking✅ for later use. Please post your queries and remarks in the comments box if you have any. I'm eager to hear your thoughts. Up until then!