Getting Started with Nest.js and MySQL Database Connection Using TypeORM

Nest.js is a progressive Node.js framework used for building efficient, scalable, and reliable server-side applications. It is built with modern JavaScript and uses TypeScript, which enables type-checking and helps in better code maintainability. TypeORM is a powerful object-relational mapping library that allows developers to easily map their database schemas to TypeScript classes. In this guide, we will learn how to get started with Nest.js and connect a MySQL database to it using TypeORM.

Step 1: Install Nest.js CLI

To get started with Nest.js, you first need to install its CLI tool globally on your machine. Open a command prompt or terminal and run the following command:

sh
npm install -g @nestjs/cli

Step 2: Create a new Nest.js project

Once the CLI tool is installed, you can create a new Nest.js project by running the following command:

sh
nest new project-name

Replace `project-name` with your desired project name. This will create a new Nest.js project with all the required boilerplate code.

Step 3: Install required dependencies

In order to use TypeORM and connect to a MySQL database, we need to install a few additional dependencies. Run the following command in your project directory to install them:

sh
npm install --save @nestjs/typeorm typeorm mysql2

The `@nestjs/typeorm` package provides integration with Nest.js, Typeform is the TypeORM library itself, and `mysql2` is the MySQL driver for TypeORM.

Step 4: Configure database connection

Next, we need to configure the connection to our MySQL database. Open the `app.module.ts` file in your project root directory and add the following configuration:

json
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'mysql',
      host: 'localhost',
      port: 3306,
      username: 'root',
      password: 'root',
      database: 'test',
      entities: [],
      synchronize: true,
    }),
  ],
})
export class AppModule {}

Replace the values for `username`, `password`, and `database`-name with your MySQL server details. The entities property specifies the location of our entity files and `synchronize` will synchronize the database schema with our entities on every application launch.

Step 5: Create a TypeORM entity

We now need to create a TypeORM entity that will represent our database table. To do this, we'll use the nest schematics and run the following script:

sh
nest generate resource user

The `nest generate resource` command is used to generate a complete set of files and folders for a new resource in your application, including a `user.controller.ts`, a `user.service.ts`, a `user.module.ts`, and a data transfer object (DTO) class. This command can help speed up the development process by creating the basic scaffolding for a new resource, allowing developers to focus on implementing the business logic for the new feature.

It will also create a file called `user.entity.ts`. Navigate to the entity-file and replace the code with the following code:

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

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

  @Column()
  firstName: string;

  @Column()
  lastName: string;

  @Column()
  email: string;

  @Column()
  password: string;
}

This will create a `User` entity with four columns: `id`, `firstName`, `lastName`, `email`, and `password`. The `@PrimaryGeneratedColumn()` ensures that the field is an auto-incremented integer value.

Step 6: Add the User as a feature in the UsersModule

In order for us to set up the created feature, we need to import `TypeOrmModule.forFeature([User])` in the imports of the auto-generated `UserModule`. The code should now look like this:

typescript
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UserController } from './user.controller';
import { UserService } from './user.service';
import { User } from './user.entity';

@Module({
  imports: [TypeOrmModule.forFeature([User])],
  controllers: [UserController],
  providers: [UserService],
})
export class UserModule {}

This module imports `TypeOrmModule` and uses it to specify that it will be managing the `User` entity. It also imports a `UserController` and a `UserService`, which we will create in the next steps.

Step 7: Navigate to the User-controller file

If you decided to generate the resource as an REST API, and to include CRUD logic the `user.controller.ts` should in this step have CRUD logic calling the `userService` file:

typescript
import { Controller, Get } from '@nestjs/common';
import { UserService } from './user.service';

@Controller('users')
export class UserController {
  constructor(private readonly userService: UserService) {}

  @Get()
  findAll() {
    return this.userService.findAll();
  }

  ...
}

This controller defines a route `/users` that will return all the users from the database using the `UserService`.

Step 8: Query from the database with the repository

Now navigate the generated `user.service.ts` file, and ensure that you add the `@InjectRepository` in the constructor.

typescript
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(User)
    private readonly userRepository: Repository<User>,
  ) {}

  findAll(): Promise<User[]> {
    return this.userRepository.find();
  }

  ...
}

This service uses the `@InjectRepository` decorator from `@nestjs/typeorm` to inject the `User` repository and provides a `findAll()` method that will return all the users from the database.

Step 9: Update the main.ts file

Finally, we need to update the `main.ts` file in the `src` directory to register the `ValidationPipe` globally. in NestJS, `ValidationPipe` is a built-in middleware that helps to validate incoming request payloads against a defined class-validator schema.

When a request is received, ValidationPipe automatically applies the validation rules to the request payload according to the specified class-validator schema. If any validation errors occur, the pipe throws a BadRequestException with the details of the validation errors, which can then be handled by a custom exception filter.

Here is an example of how to add the ValidationPipe globally for all controllers:

typescript
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());
  await app.listen(3000);
}
bootstrap();

This will create a new Nest.js application using the `AppModule`, use a `ValidationPipe` for input validation, and listen on port 3000.

Step 10: Test the application

To test the application, run the following command in your project directory:

sh
npm run start

This will start the Nest.js application and connect to the MySQL database. You should see a message indicating that the application is running on port 3000. You can then navigate to `http://localhost:3000/users` in your browser to see a list of all the users in the database.

Congratulations, you have now successfully created a Nest.js application and connected it to a MySQL database using TypeORM!