📕
NestJS×TypeORMを7ステップで。
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