📝

Nest.jsとPrismaをDockerで環境構築

2024/10/15に公開

どうも、フリーランスエンジニアのFUMIYAです!
Express.jsはよく触ってましたが、Nest.jsを触ったことがなかったのでローカルに立ち上げてみました。

本記事では、Nest.jsで開発をして学んだことをまとめていきます。

Nest.jsとは?

Nest.jsとは、フロントエンドからバックエンドまで一貫してTypeScriptでの開発を実現できるExpressをコアにして作られているフレームワークです。

目的

Nest.jsをdockerでローカルに立ち上げてAPIを開発することを目的とします。

1. Docker構築

  1. 下記コマンドをルートディレクトリで実行し、Dockerfiledocker-compose.yml.dockerignoreを作成。
  2. 中身を下記の通りにする。
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
  1. ビルドを実行して立ち上げる
docker compose up -d --build
  1. dockerが正しく立ち上がったか確認
docker compose ps

2. NestプロジェクトをDocker上に作成

  1. Nestプロジェクトを下記コマンドにて作成
docker compose exec nest nest new .
  1. package managerをnpmで選択
? Which package manager would you ❤️  to use? (Use arrow keys)
❯ npm 
  yarn 
  pnpm
  1. コマンドを実行して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を追加

  1. 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
  1. 下記コマンドを実行してdockerディレクトリdbディレクトリmy.cnf.envを作成。
mkdir docker
mkdir docker/db
touch docker/db/my.cnf
touch .env
  1. 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
  1. .envを下記のように修正
.env
DATABASE_URL="mysql://root:root@nestjs-demo-db:3306/nestjs_demo"
  1. 下記コマンドを実行してhttp://localhost:8080/にアクセスしてphpmyadminに「nest_prisma_sample」テーブルができているか確認
docker compose up

4. Prisma導入

  1. 下記コマンドを順に実行してPrismaのインストールと初期化

Prismaのインストール

docker compose run nest npm install --save-dev prisma

初期化

docker compose run nest npx prisma init
  1. 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")
}
  1. 下記コマンドを実行してマイグレート実行してprisma/migrationsにマイグレートファイルができたことを確認
docker compose run nest npx prisma migrate dev --name init

4. PrismaClientの導入

  1. 下記コマンドでPrismaClientインストール
docker compose run nest npm install @prisma/client
  1. 下記コマンドで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();
    });
  }
}
  1. 下記コマンドで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,
    });
  }
}
  1. 下記コマンドで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);
  }
}
  1. 下記コマンドで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 {}
  1. 動作確認

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
GitHubで編集を提案

Discussion