LoginSignup
5

Dockerを利用してNestJS+Prisma+MySQLの環境構築をしてテーブル作成をしてみる

Last updated at Posted at 2022-08-10

はじめに

この記事では、NestJsを使ってAPI開発したいという方に向けて記事を作成しています。
ソースを載せておくのでご自由にお使いください。

目次

1.ディレクトリイメージ
2.Dockerfileとdocker-compose.ymlの作成
3.Nestプロジェクトをdockerコンテナのワーキングディレクトリに作成
4.MySQLイメージ追加
5.Prismaを利用してMySQLと接続する

1. ディレクトリイメージ

project-path
    |- docker-compose.yml
    |- Dockerfile
    |- .dockerignore
    |- nestのmodule達

2. Dockerfileとdocker-compose.ymlの作成

Dockerfile
FROM node:14.17

RUN npm i -g @nestjs/cli

WORKDIR /api

docker-compose.yml

version: '3.7'
services:
  nest:
    container_name: nestjs_demo
    build: .
    tty: true
    ports:
      - '3000:3000'
    volumes:
      - type: bind
        source: .
        target: /api
.dockerignore
node_modules

nodeイメージをベースにして、@nestjs/cliをインストール

ビルド

% docker compose up -d --build
% docker compose ps

3. Nestプロジェクトをdockerコンテナのワーキングディレクトリに作成

% docker compose exec nest nest new .

? Which package manager would you ❤️  to use? (Use arrow keys)
❯ npm
  yarn
  pnpm

と聞かれるので、今回はnpmを選択します。

% docker compose exec nest npm run start:dev

http://localhost:3000/
にアクセスして、Hello World!と表示されたら、起動成功です。

このコマンドを毎回打つのは面倒なのでnestコンテナに
このコマンドを追加してビルドし直します。

Dockerfile
FROM node:14.17

RUN npm i -g @nestjs/cli

WORKDIR /api
# ここから追加
COPY package*.json /api/ 

RUN npm i
CMD [ "npm", "run", "start:dev"]
# ここまで追加

docker compose up -d --build

4. MySQLイメージ追加

docker-compose.ymlに追記して、MySQLコンテナを立ち上げる

docker-compose.yml

version: '3.7'
services:
  nest:
    container_name: nest
    build: .
    tty: true
    ports:
      - '3000:3000'
    volumes:
      - type: bind
        source: .
        target: /api
    depends_on: # 追加
      - db

  db:
    platform: linux/x86_64
    image: mysql:5.7
    container_name: nestjs-demo-db
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: nestjs_demo
      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: nestjs-demo-phpmyadmin
    image: phpmyadmin/phpmyadmin
    environment:
      - PMA_ARBITRARY=1
      - PMA_HOSTS=nestjs-demo-db
      - PMA_USER=root
      - PMA_PASSWORD=root
    ports:
      - 8080:80

DB設定のためのmy.cnfを作成

ルートディレクトにdockerディレクトリ、その中にdbディレクトリを作成してその中に作成します。
これが、docker volumeマウントされます

docker/db/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"

DBが作成されているか確認

% docker compose up

MySQLの管理ツールphpmyadminのimageを入れたので
http://localhost:8080/
にアクセスすればDBの確認ができます。
【環境構築#2DockerPrisma+MySQLで土台構築】.jpeg
「nestjs_demo」というDBができていれば成功です。

5. Prismaを利用してMySQLと接続する

続いて、Prismaを利用するためのセットアップを行います。

Prismaのパッケージをインストール
 % docker compose run nest npm install --save-dev prisma
Prismaの初期化
 % docker compose run nest npx prisma init

この時点で、prismaというフォルダが作成されます。
prismaフォルダの中にschema.prismaがあり、
それを編集していくことで、DBのモデルを作成していきます。

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
  password      String
  registered_at DateTime @default(now())
  updated_at    DateTime @updatedAt

  roles AdminAccountRole[]

  @@map("users")
}

mysqlを使うのでpostgresqlから変更
usersという名前でmysqlのデータベースに作成

prismaスキーマファイルのマイグレート

 % docker compose run nest npx prisma migrate dev --name init
prisma/migrations/2022XXXXXXXXXXX_init/migration.sql]
-- CreateTable
CREATE TABLE `users` (
    `id` INTEGER NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(191) NOT NULL,
    `email` VARCHAR(191) NOT NULL,
    `password` VARCHAR(191) NOT NULL,
    `registered_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
    `updated_at` DATETIME(3) NOT NULL,

    UNIQUE INDEX `users_email_key`(`email`),
    PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

生成されたマイグレーションファイル

PrismaClientのインストール

% docker compose run nest npm install @prisma/client

Prisma Clientは、Prismaのモデル定義から生成されるタイプセーフのデータベースクライアントです。
インストール時に、Prismaは自動的にprisma generateコマンドを呼び出します。
なので、次回以降Prismaモデルを変更するたびにこのコマンドを実行し、生成されたPrismaクライアントを更新する必要があります。

Prisma Client service作成

docker-compose run nest nest generate service Prisma

PrismaClientのインスタンス化とデータベースへの接続を行うPrismaService
srcディレクトリ内にprisma.service.tsというファイルを新規に作成し、下記のコードを追加します。

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) {
    this.$on('beforeExit', async () => {
      await app.close();
    });
  }
}

Users service作成

docker-compose run nest nest generate service users

Prismaスキーマから、先程作成したUserモデルのデータベースを呼び出すために使用するUsersServiceを作成します。
srcディレクトリの中にusersディレクトリとusers.service.tsというファイルを新規に作成し、下記のコードを追加します。

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,
    });
  }
}

ルーティングとコントローラを追加

% docker-compose run nest nest g controller users

続いて、先程作成したサービスを使用して、ルーティングとコントローラを定義します。
usersディレクトリの中にusers.controller.tsというファイルを新規に作成し、下記のコードを追加します。

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

最後にUsersModuleを作成し、AppModuleに追加します。
users配下にusers.module.tsというファイルを作成し、下記コードを追加します。

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 {}

app.module.tsにUsersモジュールをimport

※基本generateコマンドでファイルを生成した場合はその時点で自動的にここに追加されます

src/app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { PrismaService } from './prisma/prisma.service';
import { UsersService } from './users/users.service';
import { UsersController } from './users/users.controller';
import { UsersModule } from './users/users.module';

@Module({
  imports: [UsersModule], // 追加
  controllers: [AppController, UsersController],
  providers: [AppService, PrismaService, UsersService],
})
export class AppModule {}

これでNest.jsにPrismaを導入し、アプリケーションからDBを操作できるようになりました

curl コマンドでAPIの動作確認

% curl -H "content-type: application/json" -X POST -d'{"name":"test", "email":"test@sample.com", "password":"12345678"}' http://localhost:3000/users
→usersコントローラcreateUserアクション実行

% curl -X GET http://localhost:3000/users/1
→usersコントローラfindUserByIdアクション実行

% curl -X GET http://localhost:3000/users
→usersコントローラusersアクション実行

POST後のデータ確認時はMySQLの管理ツールphpmyadminでも確認できます。
http://localhost:8080/

以上です

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5