エンティティを作成する
@Entity('users')で TypeORM によってusersテーブルが作成・参照される。
id には@PrimaryGeneratedColumn('uuid')を設定する。これをしないと SQL では主キーが数値型扱いになり実行時エラーが出る。
import {
Column,
CreateDateColumn,
Entity,
PrimaryGeneratedColumn,
UpdateDateColumn,
} from "typeorm";
@Entity("users")
export class User {
@PrimaryGeneratedColumn("uuid")
id: string;
@Column()
name: string;
@CreateDateColumn()
readonly createdAt: Date;
@UpdateDateColumn()
readonly updatedAt: Date;
}
AppModule に MySQL の接続情報を記載する
src/app.module.ts
import { Module } from "@nestjs/common";
import { TypeOrmModule } from "@nestjs/typeorm";
import { AppController } from "./app.controller";
import { AppService } from "./app.service";
import { Todo } from "./todos/entities/todo.entity";
import { TodosModule } from "./todos/todos.module";
@Module({
imports: [
// ★ ここから
TypeOrmModule.forRoot({
type: "mysql",
host: "localhost",
port: 3306,
username: "user",
password: "password",
database: "db",
entities: [User],
synchronize: true, // これを入れるとMySQLの既存のデータが消える。
}),
// ★ ここまで
TodosModule,
UsersModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {
constructor(private readonly usersService: UsersService) {}
async onModuleInit() {
console.log("onModuleInit");
const users = await this.usersService.findAll();
if (users.length <= 0) {
console.log("Create admin");
await this.usersService.create({ name: "admin" });
}
}
}
ちなみにonModuleInit()に NestJS アプリケーションの起動時の処理を書くことができる。awaitも実行可能なので Service のコンストラクタに初期処理を書くよりおすすめ。
import { Module } from "@nestjs/common";
import { TypeOrmModule } from "@nestjs/typeorm";
import { User } from "./entities/user.entity";
import { UsersController } from "./users.controller";
import { UsersService } from "./users.service";
@Module({
imports: [TypeOrmModule.forFeature([User])], // ★
controllers: [UsersController],
providers: [UsersService],
exports: [UsersService],
})
export class UsersModule {}
Service を実装する
src/users/users.service.ts
import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository } from "typeorm";
import { CreateUserDto } from "./dto/create-user.dto";
import { UpdateUserDto } from "./dto/update-user.dto";
import { User } from "./entities/user.entity";
import { UserNotFoundError } from "./errors/user-not-found-error";
@Injectable()
export class UsersService {
constructor(
@InjectRepository(User)
private readonly usersRepository: Repository<User>
) {}
async create(createUserDto: CreateUserDto): Promise<User> {
const id = crypto.randomUUID();
await this.usersRepository.save({
id,
name: createUserDto.name,
});
const user = await this.usersRepository.findOneBy({ id });
return user;
}
async findAll(): Promise<User[]> {
return await this.usersRepository.find({ order: { name: "ASC" } });
}
async findOne(id: string): Promise<User> {
const user = await this.usersRepository.findOneBy({ id });
if (!user) {
throw new UserNotFoundError();
}
return user;
}
async update(id: string, updateUserDto: UpdateUserDto) {
const user = await this.usersRepository.findOneBy({ id });
if (!user) {
throw new UserNotFoundError();
}
await this.usersRepository.update(id, { ...updateUserDto });
}
async remove(id: string) {
const user = await this.usersRepository.findOneBy({ id });
if (!user) {
throw new UserNotFoundError();
}
await this.usersRepository.delete(id);
}
}
Controller を実装する
src/users/users.controller.ts
import {
Body,
Controller,
Delete,
Get,
HttpCode,
HttpException,
Param,
Patch,
Post,
} from "@nestjs/common";
import { CreateUserDto } from "./dto/create-user.dto";
import { UpdateUserDto } from "./dto/update-user.dto";
import { User } from "./entities/user.entity";
import { UserNotFoundError } from "./errors/user-not-found-error";
import { UsersService } from "./users.service";
@Controller("users")
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Post()
async create(@Body() createUserDto: CreateUserDto): Promise<User> {
try {
return await this.usersService.create(createUserDto);
} catch (error: any) {
this.catchError(error);
}
}
@Get()
async findAll(): Promise<User[]> {
return await this.usersService.findAll();
}
@Get(":id")
async findOne(@Param("id") id: string): Promise<User> {
try {
return await this.usersService.findOne(id);
} catch (error: any) {
this.catchError(error);
}
}
@Patch(":id")
async update(
@Param("id") id: string,
@Body() updateUserDto: UpdateUserDto
): Promise<User> {
try {
await this.usersService.update(id, updateUserDto);
return await this.usersService.findOne(id);
} catch (error: any) {
this.catchError(error);
}
}
@Delete(":id")
@HttpCode(204)
async remove(@Param("id") id: string): Promise<void> {
try {
return await this.usersService.remove(id);
} catch (error: any) {
this.catchError(error);
}
}
private catchError(error: any) {
if (error instanceof UserNotFoundError) {
throw new HttpException("User not found", 404);
} else {
throw new HttpException("Internal server error", 500);
}
}
}