📝
Nest.jsとPrismaをDockerで環境構築
どうも、フリーランスエンジニアのFUMIYAです!
Express.jsはよく触ってましたが、Nest.jsを触ったことがなかったのでローカルに立ち上げてみました。
本記事では、Nest.jsで開発をして学んだことをまとめていきます。
Nest.jsとは?
Nest.jsとは、フロントエンドからバックエンドまで一貫してTypeScriptでの開発を実現できるExpressをコアにして作られているフレームワークです。
目的
Nest.jsをdockerでローカルに立ち上げてAPIを開発することを目的とします。
1. Docker構築
- 下記コマンドをルートディレクトリで実行し、Dockerfileとdocker-compose.yml、.dockerignoreを作成。
- 中身を下記の通りにする。
touch Dockerfile docker-compose.yml .dockerignore
Dockerfile
FROM node:20
RUN npm i -g @nestjs/cli
WORKDIR /api
docker-compose.yml
version: '3.7'
services:
nest:
container_name: nest
build: .
tty: true
ports:
- '3000:3000'
volumes:
- type: bind
source: .
target: /api
.dockerignore
node_modules
- ビルドを実行して立ち上げる
docker compose up -d --build
- dockerが正しく立ち上がったか確認
docker compose ps
2. NestプロジェクトをDocker上に作成
- Nestプロジェクトを下記コマンドにて作成
docker compose exec nest nest new .
- package managerをnpmで選択
? Which package manager would you ❤️ to use? (Use arrow keys)
❯ npm
yarn
pnpm
- コマンドを実行してhttp://localhost:3000/にアクセスしてHello World!と表示されるか確認
docker compose exec nest npm run start:dev
Dockerfile
FROM node:20
RUN npm i -g @nestjs/cli
WORKDIR /api
+ COPY package*.json /api/
+ RUN npm i
+ CMD [ "npm", "run", "start:dev"]
3. MySQLを追加
- docker-compose.ymlを下記のように修正
docker-compose.yml
version: '3.7'
services:
nest:
container_name: nest
build: .
tty: true
ports:
- '3000:3000'
volumes:
- type: bind
source: .
target: /api
db:
platform: linux/x86_64
image: mysql:5.7
container_name: nest-prisma-sample-db
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: nest_prisma_sample
MYSQL_PASSWORD: root
TZ: 'Asia/Tokyo'
command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
volumes:
- ./docker/db/my.cnf:/etc/mysql/conf.d/my.cnf
ports:
- 3306:3306
phpmyadmin:
container_name: nest-prisma-sample-phpmyadmin
image: phpmyadmin/phpmyadmin
environment:
- PMA_ARBITRARY=1
- PMA_HOSTS=nest-prisma-sample-db
- PMA_USER=root
- PMA_PASSWORD=root
ports:
- 8080:80
- 下記コマンドを実行してdockerディレクトリ、dbディレクトリ、my.cnf、.envを作成。
mkdir docker
mkdir docker/db
touch docker/db/my.cnf
touch .env
- DB設定のmy.cnfを下記のように修正
my.cnf
[mysqld]
default-authentication-plugin=mysql_native_password
character-set-server=utf8mb4
[mysql]
default-character-set=utf8mb4
[client]
default-character-set=utf8mb4
- .envを下記のように修正
.env
DATABASE_URL="mysql://root:root@nestjs-demo-db:3306/nestjs_demo"
- 下記コマンドを実行してhttp://localhost:8080/にアクセスしてphpmyadminに「nest_prisma_sample」テーブルができているか確認
docker compose up
4. Prisma導入
- 下記コマンドを順に実行してPrismaのインストールと初期化
Prismaのインストール
docker compose run nest npm install --save-dev prisma
初期化
docker compose run nest npx prisma init
- DBをmysqlに変更とUserモデルを作成のためschema.prismaファイルを修正
prisma/schema.prisma
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
}
model User {
id Int @id @default(autoincrement())
name String
email String @unique
created DateTime @default(now())
updated_at DateTime @updatedAt
@@map("users")
}
- 下記コマンドを実行してマイグレート実行してprisma/migrationsにマイグレートファイルができたことを確認
docker compose run nest npx prisma migrate dev --name init
4. PrismaClientの導入
- 下記コマンドでPrismaClientインストール
docker compose run nest npm install @prisma/client
- 下記コマンドでPrisma Client service作成し修正
src/prisma/prisma.service.ts
import { INestApplication, Injectable, OnModuleInit } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
async onModuleInit() {
await this.$connect();
}
async enableShutdownHooks(app: INestApplication) {
process.on('beforeExit', async () => {
await app.close();
});
}
}
- 下記コマンドでUsers service作成し修正
docker-compose run nest nest generate service users
src/users/users.service.ts
import { Injectable } from '@nestjs/common';
import { PrismaService } from './../prisma/prisma.service';
import { User, Prisma } from '@prisma/client';
@Injectable()
export class UsersService {
constructor(private prisma: PrismaService) {}
async user(id: number): Promise<User | null> {
return this.prisma.user.findUnique({
where: { id },
});
}
async users(): Promise<User[]> {
return this.prisma.user.findMany();
}
async createUser(data: Prisma.UserCreateInput): Promise<User> {
return this.prisma.user.create({
data,
});
}
}
- 下記コマンドでUsersコントローラを作成し修正
docker-compose run nest nest g controller users
src/users/users.controller.ts
import { Controller, Get, Param, Post, Body } from '@nestjs/common';
import { UsersService } from './users.service';
import { User } from '@prisma/client';
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get(':id')
async findUserById(@Param('id') id: string): Promise<User> {
return this.usersService.user(Number(id));
}
@Get()
async users(): Promise<User[]> {
return this.usersService.users();
}
@Post()
async createUser(
@Body() userData: { name: string; email: string; password: string },
): Promise<User> {
return this.usersService.createUser(userData);
}
}
- 下記コマンドでUsersモジュールを作成し修正
docker-compose run nest nest g module users
src/users/users.module.ts
import { Module } from '@nestjs/common';
import { UsersService } from './users.service';
import { UsersController } from './users.controller';
import { PrismaService } from './../prisma/prisma.service';
@Module({
controllers: [UsersController],
providers: [UsersService, PrismaService],
})
export class UsersModule {}
- 動作確認
createUser実行
curl -H "content-type: application/json" -X POST -d'{"name":"test", "email":"test@sample.com"}' http://localhost:3000/users
findUserById実行
curl -X GET http://localhost:3000/users/1
users実行
curl -X GET http://localhost:3000/users
Discussion