📕

NestJS×TypeORMを7ステップで。

2023/07/17に公開

0. 技術解説

NestJSとは?

  • バックエンドの開発に使う
  • Node.jsのフレームワーク
  • 効率よくコードを書ける
  • 他のライブラリを使用できるので拡張性が高い

TypeORMとは?

  • DBのテーブル操作に使う
  • TypeScriptで書かれたORMライブラリ
  • SQLを書く必要がない
  • テーブルの作成や各種操作(CRUD)が可能
  • MySQLやPostgreSQLなど様々なDBに対応

1. NestJSのセットアップ

プロジェクト作成

ターミナル
nest new project_name

プロジェクトを開く

お好みのエディタでプロジェクトを開く。
以降の作業は、プロジェクト(project_name)をカレントディレクトリとする。

2. TypeORMのセットアップ

ライブラリのインストール

ターミナル
npm i @nestjs/typeorm typeorm
npm i mysql
npm i dotenv

.envの記述

.env
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=db_name
DB_USERNAME=username
DB_PASSWORD=password

TypeORMの接続先設定

typeorm.config.ts
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
import { config } from 'dotenv';
import { join } from 'path';

config({ path: '.env' });

export const typeormConfig: TypeOrmModuleOptions = {
  type: 'mysql',
  host: process.env.DB_HOST,
  port: parseInt(process.env.DB_PORT),
  database: process.env.DB_DATABASE,
  username: process.env.DB_USERNAME,
  password: process.env.DB_PASSWORD,
  entities: [join(__dirname, '../**/*.entity{.ts,.js}')],
  synchronize: true,
  logging: false,
};

Appモジュールの記述

app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { typeormConfig } from './config/typeorm.config';

@Module({
  imports: [
    TypeOrmModule.forRoot(typeormConfig),
  ],
  /* ... */
})
export class AppModule {}

3. バリデーションのセットアップ

ライブラリのインストール

ターミナル
npm i class-validator class-transformer

ValidationPipe有効化

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

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

4. EntityおよびDTOの記述

Entity定義

users.entity.ts
import {
  BaseEntity,
  Column,
  CreateDateColumn,
  Entity,
  PrimaryGeneratedColumn,
  UpdateDateColumn,
} from 'typeorm';

@Entity('users')
export class UsersEntity extends BaseEntity {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Column({ type: 'varchar' })
  name: string;

  @CreateDateColumn()
  created_at: Date;

  @UpdateDateColumn()
  updated_at: Date;
}

DTO定義

users.dto.ts
import { IsNotEmpty, IsOptional, IsString } from 'class-validator';

export class CreateUserDTO {
  @IsString()
  @IsNotEmpty()
  name: string;
}

export class UpdateUserDTO {
  @IsString()
  @IsNotEmpty()
  id: string;

  @IsString()
  @IsOptional()
  name: string;
}

5. Serviceの記述

users.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { CreateUserDTO, UpdateUserDTO } from '../dto/user.dto';
import { UsersEntity } from '../entities/users.entity';

@Injectable()
export class UsersService {
  constructor(
    @InjectRepository(UsersEntity)
    private readonly usersRepository: Repository<UsersEntity>,
  ) {}

  async createOne(dto: CreateUserDTO): Promise<UsersEntity> {
    return await this.usersRepository.save(dto);
  }

  async readOne(id: string): Promise<UsersEntity> {
    return await this.usersRepository.findOneBy({ id: id });
  }

  async updateOne(user: UsersEntity, dto: UpdateUserDTO): Promise<UsersEntity> {
    return await this.usersRepository.save({ ...user, ...dto });
  }

  async deleteOne(user: UsersEntity): Promise<UsersEntity> {
    return await user.remove();
  }
}

6. Controllerの記述

users.controller.ts
import {
  Body,
  Controller,
  Delete,
  Get,
  HttpException,
  HttpStatus,
  NotFoundException,
  Param,
  Post,
  Put,
} from '@nestjs/common';
import { CreateUserDTO, UpdateUserDTO } from '../dto/user.dto';
import { UsersEntity } from '../entities/users.entity';
import { UsersService } from '../services/users.service';

@Controller('users')
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Post()
  async createOne(@Body() dto: CreateUserDTO): Promise<UsersEntity> {
    try {
      return await this.usersService.createOne(dto);
    } catch (err) {
      throw new HttpException('Internal server error', HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

  @Get(':id')
  async readOne(@Param('id') id: string): Promise<UsersEntity> {
    const selected = await this.usersService.readOne(id);
    if (!selected) {
      throw new NotFoundException({ message: 'データがありません' });
    }
    return selected;
  }

  @Put()
  async updateOne(@Body() dto: UpdateUserDTO): Promise<UsersEntity> {
    const selected = await this.usersService.readOne(dto.id);
    if (!selected) {
      throw new NotFoundException({ message: 'データがありません' });
    }
    try {
      return await this.usersService.updateOne(selected, dto);
    } catch (err) {
      throw new HttpException('Internal server error', HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

  @Delete(':id')
  async deleteOne(@Param('id') id: string): Promise<UsersEntity> {
    const selected = await this.usersService.readOne(id);
    if (!selected) {
      throw new NotFoundException({ message: 'データがありません' });
    }
    try {
      return await this.usersService.deleteOne(selected);
    } catch (err) {
      throw new HttpException('Internal server error', HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }
}

7. Moduleの記述

users.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UsersController } from '../controllers/users.controller';
import { UsersEntity } from '../entities/users.entity';
import { UsersService } from '../services/users.service';

@Module({
  imports: [TypeOrmModule.forFeature([UsersEntity])],
  controllers: [UsersController],
  providers: [UsersService],
})
export class UsersModule {}
app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { typeormConfig } from './config/typeorm.config';
+import { UsersModule } from './modules/users.module';

@Module({
  imports: [
    TypeOrmModule.forRoot(typeormConfig),
+    UsersModule,
  ],
  /* ... */
})
export class AppModule {}

実行

ターミナル
npm run start:dev

最終ディレクトリ

project_name/
├── src/
│   ├── config/
│   │   └── typeorm.config.ts
│   ├── controllers/
│   │   └── users.controller.ts
│   ├── dto/
│   │   └── users.dto.ts
│   ├── entities/
│   │   └── users.entity.ts
│   ├── modules/
│   │   └── users.module.ts
│   ├── services/
│   │   └── users.service.ts
│   ├── app.module.ts
│   └── main.ts
├── test/
├── .env
├── .eslintrc.js
├── .gitignore
├── .prettierrc.json
├── nest-cli.json
├── package-lock.json
├── package.json
├── README.md
├── tsconfig.build.json
└── tsconfig.json

Discussion