【Node.js】Expressでmvc環境構築!!
はじめに
オンラインプログラミング学習サービス「Progate」のコースに Web開発パス(Node.js) ってのがあったので学習してみました。
ただ学習しただけで終わりにしたくはなかったので、自分のローカルに環境を作成してProgateで出来たことが問題なくできるのか確認してみました。
その際に色々と調べて学んだことをつらつらと書いていきます。
Expressとは
Node.jsのWebアプリケーションフレームワークであり、高速で軽量なのが売りです。
またNode.jsでWebアプリケーションを開発する場合はデファクトスタンダードであり、インターネット上にも情報が豊富に存在します。
バックエンドもjavascriptを使いたいと思う方は触れてみても良いかもしれません。
※筆者はフロントエンドの経験が浅く、javascriptをもっと理解しようと思い触れました。
mvcとは
Webアプリケーションのフレームワークの基本的な概念の1つで、開発する際に処理の役割を分けてソースコードを管理しやすくできます。
- モデル(Model):m
⇒DBとのやり取りをメインで担当 - ビュー(View):v
⇒表示させる内容、処理をメインで担当 - コントローラー(Controller):c
⇒ユーザーの入力に基づき、ModelとViewを制御する担当
Node.jsの環境について
この記事はあくまでExpressの実行環境を構築&開発を進める上でのインストール等々を記載します。Node.jsはインストール済みとして進めます。
筆者はdockerでNode.jsの環境を作成し、使用しています。
念のため以下のファイルの内容を載せておきます。
適当なディレクトリを作成し、
- docker-compose.yml
- Dockerfile
- opt(フォルダ)
を用意してdocker-composeコマンドを使用してビルド&アップすれば簡単にできます。
docker-compose.yml↓
version: '3'
services:
node:
build:
context: .
dockerfile: Dockerfile
volumes:
- ./opt:/usr/src/app # ローカルとコンテナ内の同期
ports:
- "3000:3000"
stdin_open: true
FROM node:14.5.0-alpine
WORKDIR /usr/src/app
※alpineはNode.jsの最小のイメージです。もしかすると規模によっては開発に影響が出るかも…
Expressの環境作成
Node.jsの実行環境が用意できたらnpm(Node Package Manager)コマンドが使えるようになっているはずです。
npmコマンドを使ってExpressを含め、様々なパッケージをインストールしてWebアプリケーションを作成していきます。
Expressの環境を構築する方法が大きく2つあります。
①ディレクトリから各ファイルまで自分で1から作成する
②パッケージを作って自動でフォルダ構成と必要なファイルを作成する。
どちらでもExpressでWebアプリケーションを作成できますが②の方法で記載していきます。
前準備
express-generatorのインストール
$ npm install express-generator -g
Expressの開発元が提供するジェネレーター。express用のディレクトリ構成を自動で作ってくれます。さらに必要なライブラリが記載済みのpackage.jsonファイルも作ってくれます。
※ここでの「-g」はグローバルインストール。
expressコマンドを使用できるようにするため。
Sequelize-cliのインストール
$ npm install sequelize-cli -g
Node.js用のORM(Object Relation Mapping)でマイグレーション操作のためのライブラリです。express-generatorではDB操作部分は作成されないのでこのライブラリで作成します。
プロジェクトを作ろう
任意のディレクトリ上で
$ express --view=[テンプレートエンジン] [プロジェクト名]
今回は以下で進めます。
- テンプレートエンジン:ejs
- プロジェクト名:login_app_ejs
$ express --view=ejs login_app_ejs
※どのテンプレートエンジンを指定できるかは「express -h」コマンドで確認できます。
コマンドを実行すると以下が表示されます。
create : login_app_ejs/
create : login_app_ejs/public/
create : login_app_ejs/public/javascripts/
create : login_app_ejs/public/images/
create : login_app_ejs/public/stylesheets/
create : login_app_ejs/public/stylesheets/style.css
create : login_app_ejs/routes/
create : login_app_ejs/routes/index.js
create : login_app_ejs/routes/users.js
create : login_app_ejs/views/
create : login_app_ejs/views/error.ejs
create : login_app_ejs/views/index.ejs
create : login_app_ejs/app.js
create : login_app_ejs/package.json
create : login_app_ejs/bin/
create : login_app_ejs/bin/www
change directory:
$ cd login_app_ejs
install dependencies:
$ npm install
run the app:
$ DEBUG=login-app-ejs:* npm start
ディレクトリが生成されていると思います。
login_app_ejs
├─app.js
├─package.json
├─bin
│ └─www
├─public
│ ├─images
│ ├─javascripts
│ └─stylesheets
│ └─style.css
├─routes
│ ├─index.js
│ └─users.js
└─views
├─error.ejs
└─index.ejs
ライブラリをインストールします。
$ cd login_app_ejs
$ npm install
この段階でWebアプリケーションとして最低限の構成ができたので実際に動かしてみましょう。
$ DEBUG=login-app-ejs:* npm start
※解除はCtrl + c
ブラウザで3000ポートを指定して以下の画面が表示されれば成功
ORM環境を追加しよう
※ここではDBはMySQLを使用する前提で記載します。
MySQLへの接続用ライブラリとsequelizeの本体をインストールします。
$ npm install mysql2 sequelize
sequelize-cliでORM用のディレクトリとファイルを生成
$ npx sequelize-cli init
この時点でディレクトリ構成は以下になります。
login_app_ejs
├─app.js
├─package-lock.json
├─package.json
├─bin
│ └─www
├─config ← できてる!
│ └─config.json
├─migrations ← できてる!
├─models ← できてる!
│ └─index.js
├─node_modules
├─public
│ ├─images
│ ├─javascripts
│ └─stylesheets
│ └─style.css
├─routes
│ ├─index.js
│ └─users.js
├─seeders ← できてる!
└─views
├─error.ejs
└─index.ejs
DBの接続情報は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"
}
}
ここでの「development」「test」「production」は開発環境、テスト環境、本番環境の意味です。それぞれの環境に適用する際に切り替えられるように接続情報をこのファイルに集めています。
※詳しくはprocess.envのNODE_ENVを調べてみてください。
マイグレーションをしてみよう
Userテーブルを作るまでをサンプルとして記載してみます。
〇Userテーブルの構成
物理名 | 型 |
---|---|
id | int(11) |
name | varchar(255) |
varchar(255) | |
password | varchar(255) |
rememberToken | varchar(255) |
createdAt | datetime |
updatedAt | datetime |
テーブルを作成
Userテーブルのモデルを作成します。
$ npx sequelize-cli model:generate --name User --attributes name:string,email:string,password:string,rememberToken:string
※--attributesの後に項目と型指定する
※id、CreatedAt、UpdatedAtのフィールドが自動作成される
- /models/user.js
- /migrations/xxxxxxxxxxxxxx-create-user.js
というファイルが生成される。
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class User extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate(models) {
// define association here
}
};
User.init({
name: DataTypes.STRING,
email: DataTypes.STRING,
password: DataTypes.STRING,
rememberToken: DataTypes.STRING
}, {
sequelize,
modelName: 'User',
});
return User;
};
'use strict';
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.createTable('Users', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
name: {
type: Sequelize.STRING
},
email: {
type: Sequelize.STRING
},
password: {
type: Sequelize.STRING
},
rememberToken: {
type: Sequelize.STRING
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: async (queryInterface, Sequelize) => {
await queryInterface.dropTable('Users');
}
};
マイグレーションファイルのみ作成
モデルを作らず、マイグレーションファイルのみ作成もできます。
$ npx sequelize-cli migration:generate --name User
Migrationの実行
$ npx sequelize-cli db:migrate
正常に処理が終わればDBにUserテーブルが生成される。
モデルも生成済みなのですぐにでもデータの操作ができるようになる。
Migrationを元に戻す
1つ前に戻す場合
$ npx sequelize-cli db:migrate:undo
すべてを戻し、最初から行う場合
$ npx sequelize-cli db:seed:undo:all
Seedも使ってデータを登録してみる
Seedファイルを生成します
$ npx sequelize-cli seed:generate --name test-user
- /seeders/xxxxxxxxxxxxxx-test-user.js
というファイルが生成される。
'use strict';
module.exports = {
up: async (queryInterface, Sequelize) => {
/**
* Add seed commands here.
*
* Example:
* await queryInterface.bulkInsert('People', [{
* name: 'John Doe',
* isBetaMember: false
* }], {});
*/
},
down: async (queryInterface, Sequelize) => {
/**
* Add commands to revert seed here.
*
* Example:
* await queryInterface.bulkDelete('People', null, {});
*/
}
};
↓
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
const now = new Date();
return queryInterface.bulkInsert('Users', [
{ name: 'テストA', email: 'aaa@example.com', password: 'aaa-password', createdAt: now, updatedAt: now},
{ name: 'テストB', email: 'bbb@example.com', password: 'bbb-password', createdAt: now, updatedAt: now},
{ name: 'テストC', email: 'ccc@example.com', password: 'ccc-password', createdAt: now, updatedAt: now},
{ name: 'テストD', email: 'ddd@example.com', password: 'ddd-password', createdAt: now, updatedAt: now},
{ name: 'テストE', email: 'eee@example.com', password: 'eee-password', createdAt: now, updatedAt: now},
], {});
},
down: (queryInterface, Sequelize) => {
return queryInterface.bulkDelete('Users', null, {});
}
};
Seedの実行
npx sequelize-cli db:seed:all
以下のようにテーブルにデータが登録される
id | name | password | rememberToken | createdAt | updatedAt | |
---|---|---|---|---|---|---|
1 | テストA | aaa@example.com | aaa-password | null | yyyy-MM-dd HH:mm:ss | yyyy-MM-dd HH:mm:ss |
2 | テストB | bbb@example.com | bbb-password | null | yyyy-MM-dd HH:mm:ss | yyyy-MM-dd HH:mm:ss |
3 | テストC | ccc@example.com | ccc-password | null | yyyy-MM-dd HH:mm:ss | yyyy-MM-dd HH:mm:ss |
4 | テストD | ddd@example.com | ddd-password | null | yyyy-MM-dd HH:mm:ss | yyyy-MM-dd HH:mm:ss |
5 | テストE | eee@example.com | eee-password | null | yyyy-MM-dd HH:mm:ss | yyyy-MM-dd HH:mm:ss |
Seedを元に戻す
すべてを戻し、最初から行う場合
$ npx sequelize-cli db:migrate:undo:all
まとめてやっちゃおう!
$ npx sequelize db:migrate:undo:all && sequelize db:migrate && sequelize db:seed:all
何かしらモデルの追加や変更、テストデータの追加等が発生した場合はこのコマンドでマイグレーション~Seedの追加まで行ってくれます。
※テーブルのデータは作り直されてしまうので注意
まとめ
ここまででmvcモデルの開発がある程度できる状態になりました。
Controllerは自分でディレクトリ、ファイルを作成しなければいけません。
しかし、ライブラリでディレクトリ構成とマイグレーションまではできたので一旦はOKでしょう。
mvcを使用してのコーディングの中身は所属する会社、チーム、個人で多少変わると思われるので周りに合わせる形で綺麗なコーディングができるとよいですね。
Discussion
情報をまとめてくださってありがとうございました!
2点修正のお願いです!
①テーブルを作成する箇所
テーブル項目の「rememberToken」が抜けてましたので、下記修正をお願いしたいです!
■誤:$ npx sequelize-cli model:generate --name User --attributes name:string,email:string,password:string
■正:$ npx sequelize-cli model:generate --name User --attributes name:string,email:string,password:string,rememberToken:string
②Seedの箇所
コマンドのところがseedではなくmigrateになっているので下記修正をお願いしたいです!
■誤:$ npx sequelize-cli db:migrate:undo:all
■正:$ npx sequelize-cli db:seed:undo:all
丁寧なご指摘ありがとうございます!
該当箇所を修正させていただきました!