Express + Docker環境構築から、SequelizeインストールとDB接続まで

# この記事で達成したいこと

- Express + Dockerの環境構築
- 上記環境にSequelizeをインストール
- SequelizeでDBに接続する

# Express + Dockerの環境構築

タイトルと若干乖離しているが、
本記事の目的は、
**Sequelizeの使い勝手を試してみるということにある。**

ただ、試すといっても、
土台の環境がないと難しい。

そこでまずは、Expressで簡単なAPIサーバーを立てるとこから始める。
環境によって動かないみたいなことをなくしたいので、
Dockerはやはり必須だ。

まずは、こんな感じのディレクトリ構成を作る。

```
-docker-compose.yml
-express
|--Dockerfile
|--package.json
|--src
    |--index.ts
```

docker-compose.ymlと同階層にDockerfileを作成してもいいが、
後々フロントにReactとかVueを入れることなども想定すると、
フロントとバックそれぞれでDockerfileが必要になるので、
このようにバックエンドのディレクトリ直下に入れたほうが、
後にディレクトリ構造を変更しなくて済む場合が多い。
(まあ本記事ではReactとかは入れないので、余計な配慮かもしれないが)


さて、Dockerfileとdocker-compose.ymlはとりあえず、
下記のようにしてみる。


```:express/Dockerfile
FROM node:16.13.1-alpine
WORKDIR /usr/src/app

COPY ./package* ./
RUN apk update && \
    apk add mysql-client

RUN npm install @types/express
RUN npm install
COPY . .

EXPOSE 3002

CMD npm start
```

```:docker-compose.yml
version: '3'
services:
  express:
    build: ./express
    volumes:
      - ./express:/usr/src/app
      - /usr/src/app/node_modules
    command: npm start
    depends_on:
      - "mysql"
    ports:
      - "3002:3002"
    networks:
      - db-net
  mysql:
    image: "mysql:5.7.40-debian"
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    ports:
      - "3306:3306"
    networks:
      - db-net
    environment:
      MYSQL_ROOT_PASSWORD: "admin"
      MYSQL_USER: "user"
      MYSQL_PASSWORD: "password"
      MYSQL_DATABASE: "db"
    platform: linux/x86_64
networks:
  db-net:
    driver: bridge
```


上記のDockerfileでpackage.jsonのCopy命令を出しているので、
package.jsonも作成する必要がある。

copy命令を出さないで、
コンテナ内に入って、npm installとかをして、
package.jsonを作る方法でもいいのだが、
gitでcloneとかしてきたときは、
docker compose build, upだけで
環境構築が完了するやり方のほうが、
いいと思うので、ここでは予めpackage.jsonを用意するパターンにする。

とりあえず、package.jsonにはexpressが入っていれば問題ないが、
一旦こんな感じにしてみる。

```:package.json
{
   "dependencies": {
      "express": "^4.17.2",
      "mysql": "^2.14.1"
   },
   "devDependencies": {
      "@types/node": "^16.11.10",
      "jest": "^29.3.1",
      "ts-node": "^10.9.1",
      "typescript": "4.5.2"
   },
   "scripts": {
      "start": "ts-node src/index.ts",
      "test": "jest"
   }
}
```

上記のdocker-compose.ymlの中で、
expressのcommandがnpm startになっていた。

```:docker-compose.yml
services:
  express:
    省略
    command: npm start
```

すなわち、docker compose upするときに、
上記のnpm startが対象コンテナに対して実行されるということだが、
肝心のpackage.jsonのstartコマンドを見てみると、

```:package.json 
   "scripts": {
      "start": "ts-node src/index.ts",
      "test": "jest"
   }
```

src/index.tsに対して実行していることがわかる。

そのため、このindex.tsも作成する必要がある。
そして、このファイルはexpressのサーバーを立ち上げるファイルなので、
とりあえず、expressの公式のコードを参考にこんな感じにしてみる。

```src/index.ts

import express, { Request, Response } from "express";

const app = express();
const port = 3002;

app.get("/", (req: Request, res: Response) => {
  res.send("Hello World");
});

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`);
});
```
TypeScriptなので、Request型とResponse型をimportしていること以外は、
基本jsファイルのときと変わらない。

さて、これで動くはずだ。

```:terminal
docker compose build
docker compose up
```

コンテナが立ち上がって、
localhost:3002にアクセスして、
![Screenshot 2022-12-04 at 14.50.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1290117/a3e3956e-645d-6392-39e5-0b5176b84128.png)

Hello Worldが返ってくれば、
サーバーが立ち上がっている。

# Sequelizeをインストール

sequelizeを動かす土台はできたので、
早速本題のsequelizeのインストールを行う。

ドキュメントだと微妙に分かりづらい箇所に書かれているが、
Railsのようにcliでの操作が色々できるようだ。

https://sequelize.org/docs/v6/other-topics/migrations/

まずは、先程作ったのexpressのコンテナの中に入る。

```:terminal
 d compose exec express /bin/ash
```

本体、mysql2とcliをインストールする
```:terminal
npm install --save sequelize
npm install --save mysql2
npm install --save-dev sequelize-cli
```

インストールできたら、
次のコマンドで新規プロジェクトを立ち上げることができる。
Railsでいう、rails newにあたると思われる。

```:terminal
npx sequelize-cli init
```

config/config.jsonなどのファイルが作成される。
最初は、こんな風に記述されているだろう。

```:config/config.json
{
  "development": {
    "username": "root",
    "password": null,
    "database": "database_development",
    "host": "127.0.0.1",
    "dialect": "mysql"
  },
  "test": {
    "username": "root",
    "password": null,
    "database": "database_test",
    "host": "127.0.0.1",
    "dialect": "mysql"
  },
  "production": {
    "username": "root",
    "password": null,
    "database": "database_production",
    "host": "127.0.0.1",
    "dialect": "mysql"
  }
}
```

こちらをdocker-compose.ymlで定義したmysqlのコンテナと
情報を合うように修正する。


DBを作成する前に、一旦DBのコンテナに入って中身を確認してみる。

```:terminal
docker compose exec mysql /bin/bash
```


![Screenshot 2022-12-04 at 17.55.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1290117/b6e9ae2f-3fc9-dec9-b9f7-b0ad66642656.png)

mysqlにログインして、現在あるDBを確認したところ、
information_schemaしかなく、
config.jsonで設定したDBはつくられていないことがわかる。


上記のdocker-compose.ymlのDB設定と合わせて、
config.jsonを設定すると、
こんな感じになる。

```:config.json
{
  "development": {
    "username": "user",
    "password": "password",
    "database": "db",
    "host": "mysql",
    "dialect": "mysql"
  },
  "test": {
    "username": "root",
    "password": null,
    "database": "database_test",
    "host": "127.0.0.1",
    "dialect": "mysql"
  },
  "production": {
    "username": "root",
    "password": null,
    "database": "database_production",
    "host": "127.0.0.1",
    "dialect": "mysql"
  }
}
```

※testとproductionの設定はいじっていない。


そのため、SequelizeでDBを作成したら、
上記のdbという名前のDBが作成されていたら、
dockerのdbとSequelizeが疎通できていることが確認できる。

早速、データベースを作成して試してみる。
※express側のコンテナに入ってから下記コマンドを実行してください

```:terminal
npx sequelize-cli db:create
```

作成したらもう一度dbのコンテナに入って作成されているか確認してみる。

```:terminal
docker compose exec mysql /bin/bash
```

![Screenshot 2022-12-04 at 18.01.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1290117/47edca14-02b5-b19f-2d63-f14377b0c7cb.png)

ちゃんとdbというデータベースが作成されていることが確認できた。


# Modelを作成してみる

さて、以上の流れで一応DBとの接続は確認できたが、
せっかくなので適当にモデルを作ってmigrationまでやってしまいたい。

ドキュメントに従って、
無難にUserモデルを作ってみる。

```:terminal
npx sequelize-cli model:generate --name User --attributes firstName:string,lastName:string,email:string
```


どうやら上記のコマンドはRailsに似ており、
上記コマンドでmigrationファイルが作成されるようである。
(上記コマンド実行時点ではDB上にテーブルは作成されない)

となれば、次にやることは決まっている。
そうmigrationだ。

```:terminal
npx sequelize-cli db:migrate
```

![Screenshot 2022-12-04 at 18.12.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1290117/d3e692b8-239d-17ff-a8d5-d765e447372a.png)


Userテーブルが作成され、
モデル作成コマンドの際に指定したカラム構成になっていることが確認できた。


# Sequelizeを使ってみた印象

個人的にはかなりRailsライクで使いやすかったと思う。
本記事では試さなかったが、seedなどもあり、
TypeORMなどと比べると、
かなりRailsエンジニアに優しい感じだった。

もちろん、まだ細かい検証とかしていないので、
残りは実際になんか適当なアプリを作成してみて、
もっと詳しい使い勝手を探求してみたい。