開発者はもう観察しているように、バックエンドウェブ開発のためのExpress.JSというフレームワークが少しずつ人気になっています。それに加えて、Express.JSはMongoose ORMと共に、一般的にREST APIの作成に使います。しかし、MySQL、PostgreSQL、SQLiteなどのような他のDatabase Schemaを使いたい開発者の場合に、どうするのか?SQLに関するデータベース言語のための探せるORMがどこかにありますか?ありがたいことに、そんなことがあります。こういうことはSequelizeというORMです。前の書いた記事とは違って、この記事にExpress.JSにデータベースを統合するという話が書いてあります。これから、Express.JSをSequelizeで使用して開始する方法を紹介します。
こんにちは!マルクス(Twitter Account: @markusveeyola)と申します。現在、奥多摩日本語学校の学生で、同時に、IT開発者としてアルバイトをしています。宜しくお願い致します!
それでは、始めましょうか。
##ORMとは
Object Relation Mappingというモデルはオブジェクトとリレーショナルデータベースの接続を手順としています。手動でSQLステートメントを書く必要性を排除するために使用されますが、むしろ、オブジェクトを通して、はるかに速くそしてより読みやすいQuery操作をすることができます。
##Sequelizeとは
Sequelizeは、Node.js用のpromised-basedのORMです。それは習得が容易で、Synchronization、Associationのような機能を持っています。Sequelizeで PostgreSQL、MySQL、MariaDB、SQLite、MSSQLはサポートされています。
前提条件
後は、申請をするとき、我々の手順が正しく機能するようにするために、これらは必要な条件です。
- Node.jsとNPMはインストールした必要があります。
- Node Package Manager「NPM」の基本的な知識
- Node.jsの基本的な知識
- Postman: HTTP Requestをテストするものを責任としています。
- 設定したSQLデータベース
##開発時間
プロジェクトを初期化するために、先ずはアプリを作りたい場所のフォルダに行ってください。そのフォルダーから、ターミナルに行って、「mkdir」コマンドラインを使って、プロジェクトの名前として「SequelizeCRUD」に付けて、入力してください。新しいフォルダーは作られるはずです。その後はそのフォルダーに行くため、「cd」コマンドラインと「SequelizeCRUD」を付けて、入力してください。
例:
D:\Programming\Testing\> mkdir SequelizeCRUD
D:\Programming\Testing\> cd SequelizeCRUD
D:\Programming\Testing\SequelizeCRUD\>
「SequelizeCRUD」フォルダーはもう作られたら、とうとうプロジェクトを始めるために、ターミナルからこのNPMのコードを入力してください。普通に、各々のコマンドライン実行の中には時間がかかるかもしれないので、しばらくお待ちください。
(ターミナルから作ったフォルダに行く必要です。)
npm init -y
npm install -g nodemon sequelize-cli
npm install -s express mysql2 sequelize body-parser
それでは、何が起こったんでしょうか。上のコードを見られるように、NPMの「init」を使って、プロジェクトを初期化するようになりました。初期化できた後、NPMの「install」でグローバルライブラリパッケージとしてsequelize-cliとnodemonをインストールするようになりました。sequelize-cliの目的は、アプリにORMコマンドを使用させるためです。次のインストールしたライブラリはREST APIアプリにデータベースを統合するものを目的としています。
必要なNPMパッケージはもうインストールされたので、今回は操作のコードを書き始めます!
最初は好んだコードエディタを開けてください。私にはVisual Studio Codeを使っています。エディタからSequelizeCRUDのフォルダーを開けてください。生成した「node_modules、package.json、package-lock.json」ファイル以外に、下のストラクチャーを基に他のフォルダとapp.jsを作ってください。
SequelizeCRUD
> config/
> controllers/
> migrations/
> models/
> routes/
> app.js
> node_modules/
> package.json
> package-lock.json
今回は、コードを書く時間です!「app.js」ファイルに行ってください。後で、下のコードを全て入れてください。
const express = require('express');
const bodyParser = require('body-parser');
const http = require('http');
const app = express();
const port = 8000;
app.set('port', port);
app.use(bodyParser.json());
const server = http.createServer(app);
server.listen(port);
module.exports = app;
このファイルはウェブサービスを作るために、全てを縛るメインファイルです。だから、折々このファイルに戻ります。コードに見られたように、サーバーを設定するためのブラリとして、expressとbody-parserとhttpがインポートされました。そして、PORTとしては8000を使って、サーバーが確立されます。
次に、configというフォルダに行って、config.jsonを名前としてファイルを作ってください。また、提供したコードを入ってください。
{
"development": {
"username": "root",
"password": "mysql",
"database": "sequelize",
"host": "192.168.0.112",
"dialect": "mysql"
}
}
このファイルはデータベースの接続を設定するものを目的としています。あなたの好んだSQLに応じて、dialectというプロパティの価値になります。SQLデータベースに対応する必要なプロパティを変更してください。
さて、データベースのモデルを作り始める前に、モデルのフォルダにindex.jsを作るべきです。次の見せるコードをいれてください。
'use strict';
const fs = require('fs');
const path = require('path');
const Sequelize = require('sequelize');
const basename = path.basename(__filename);
const env = process.env.NODE_ENV || 'development';
const config = require(__dirname + '/../config/config.json')[env];
const db = {};
let sequelize;
if (config.use_env_variable) {
sequelize = new Sequelize(process.env[config.use_env_variable], config);
} else {
sequelize = new Sequelize(config.database, config.username, config.password, config);
}
fs
.readdirSync(__dirname)
.filter(file => {
return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js');
})
.forEach(file => {
const model = sequelize['import'](path.join(__dirname, file));
db[model.name] = model;
});
Object.keys(db).forEach(modelName => {
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
db.sequelize = sequelize;
db.Sequelize = Sequelize;
module.exports = db;
なぜ、こういうコードが必要なのか?理由は全てのモデルファイルを一つずつインポートするというより、むしろこのファイルがインポートの手順を自動化します。それに加えて、Sequelize ORMの接続をインスタンスするために、このところにconfig.jsonファイルから、先の設定した環境を使います。このため、SequelizeでデータベースのQueryを簡単に使えるようになります。
後は、これからモデルの作成に進めます。EmployeeとCompanyのモデルを作ります。この2つの間にそれぞれのEmployeeが1つのCompanyで働いてて、逆でそれぞれのCompanyがたくさんEmployeeを持てるという関係になります。だから、後に、SequelizeでbelongsToがOne-is-to-One
を表し、hasManyがOne-is-to-Many
を表すというassocationを使うと、テーブル関係を確立できるようになります。
ターミナルから、モデルを作るために、下の部分に書いてあるように、こうやって入力する:
// Employee
sequelize model:generate --name Employee --attributes name:string,salary:integer
// Company
sequelize model:generate --name Company --attributes name:string
「 sequelize-cliというライブラリはもうインストールされたから、こういうことができます。」
上のコマンドを正しく入力すれば、4つのファイルが生成されるはずです。このファイルは2つに分けられて、MigrationsとModelsを一部としています。
Migrations: Company & Employee
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Companies', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
name: {
type: Sequelize.STRING
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('Companies');
}
};
CompanyのMigrationファイルが見られるように、idとcreatedAtとupdatedAtと共に、nameフィールドがすでに設定されています。
一方でEmployeeというMigrationにはnameとsalaryの両方フィールドがあります。しかし、EmployeeはCompany次第なので、手動で、FKフィールドはcompanyIdを名前として、追加するべきです。参照として、すでに下のコードでどのように書かれているかを見るはずです。
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Employees', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
name: {
type: Sequelize.STRING
},
salary: {
type: Sequelize.INTEGER
},
companyId: {
type: Sequelize.INTEGER,
onDelete: 'CASCADE',
references: {
model: 'Companies',
key: 'id',
}
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('Employees');
}
};
今回は、データーベースのAssocationを設定するために、モデルに行きましょう。AssociationというSequelize特徴はQueryを簡単に作る上で、使う必要なのです。なぜなら、こういう特徴を使って、FKでお互いに接続されているテーブルにQueryを直接に作れます。
Models: Company & Employee
CompanyというモデルはOne-is-to-Many
のCardinalityを持っているので、次に示すコードのようにHasManyというAssociationが使用されます。
'use strict';
module.exports = (sequelize, DataTypes) => {
const Company = sequelize.define('Company', {
name: DataTypes.STRING
}, {});
Company.associate = function(models) {
// associations can be defined here
Company.hasMany(models.Employee, {
foreignKey: 'companyId',
as: 'employees',
})
};
return Company;
};
次に、Employeeの場合に、One-is-to-ManyのCardinalityを持ってて、Company次第なので、BelongsToというAssocationを使います。
'use strict';
module.exports = (sequelize, DataTypes) => {
const Employee = sequelize.define('Employee', {
name: DataTypes.STRING,
salary: DataTypes.INTEGER
}, {});
Employee.associate = function(models) {
// associations can be defined here
Employee.belongsTo(models.Company, {
foreignKey: 'companyId',
onDelete: 'CASCADE',
})
};
return Employee;
};
Model Synchronization
今、Associationをちゃんと作動してもらうものを目的として、モデルのメインファイルにシンクロナイズします。そうするために、app.jsに戻って、下の書いてあるコードと同じように、そういうコードをいれてください。Employeeモデルのウェブメソッドだけを作るので、Companyのデーターを直接にイニシャライズします。
このコードに表示しているように、モデル変数としてindex.jsをインポートしました。そういう変数を使ってCompanyのモデルを使えます。
const express = require('express');
const bodyParser = require('body-parser');
const http = require('http');
const models = require('./models/index.js');
const Company = models.Company;
const app = express();
const port = 8000;
app.set('port', port);
app.use(bodyParser.json());
models.sequelize.sync().then(() => {
initial();
console.log('Seems like the backend is running fine...');
}).catch((err) => {
console.log(err, 'Something went wrong with the operation');
});
require('./routes/employee.route')(app);
function initial(){
Company.create({
name: "ABC Company"
});
Company.create({
name: "DEF Company"
});
Company.create({
name: "GHI Company"
});
}
const server = http.createServer(app);
server.listen(port);
module.exports = app;
この後は、ターミナルに、設定したモデルをテーブルにするために、このようなコードを入力してください。
sequelize db:migrate
Controller: Employee
const db = require('../models/index.js');
const Employee = db.Employee;
const Company = db.Company;
module.exports = {
create(req, res) {
Employee.create({
name: req.body.name,
salary: req.body.salary,
companyId: req.body.companyId,
}).then(employee => {
res.send(employee);
});
},
findAll(req, res) {
Employee.findAll({
include: [{ model: Company }]
}).then(companies => {
res.send(companies);
});
},
findOne(req, res) {
Employee.findOne({
where: {
id: req.params.id
},
include: [{ model: Company }]
})
.then(company => {
res.send(company);
})
},
update(req, res) {
Employee.update(
{
name: req.body.name,
salary: req.body.salary
}, {
where: { id: req.params.id }
}
).then(() => {
res.status(200).send("Successfully updated a Employee ID: " + req.params.id);
});
},
delete(req, res) {
Employee.destroy({
where: { id: req.params.id }
}).then(() => {
res.status(200).send("Successfully deleted a Employee ID: " + req.params.id);
});
}
}
上に見せられるように、データベースにEmployeeとCompanyのテーブルが生成されたので、Controllerを作る時間になりました。Controllerフォルダに行って、employee.controller.jsを名前として、新しいファイルを作ります。このところにウェブメソッドを作っていきます。Sequelize接続をアクセスするために、モデルフォルダのindex.jsファイルをインポートして、EmployeeとCompanyのモデルを変数に入ります。
SequelizeはORMなので、手動でQueryを作らなくていいです。create
、findAll
、findOne
、update
、destroy
のような定義済み関数を使うだけです。また、一目瞭然の関数名前なので、使い方はすぐ分かります。SequelizeのQueryがpromise-basedの関数だから、callback
とerror
は管理しやすいです。
このコードのハイライトはそのfindOne
とfindAll
というメソッドです。なぜなら、SequelizeのAssociationで、EmployeeのデーターをQueryでもらうと、include
のタッグを使ってCompanyのデーターも直接にもらえます。とても便利ですよね!
Route: Employee
自分でこのアプリをテストする前に、Routeフォルダに行って、最後の新しいファイルを作って、employee.route.jsを名前としていくべきです。
module.exports = function(app) {
const employeesController = require('../controllers/employee.controller');
const employeesAPI = '/api/employees'
// Create a new Employee
app.post(employeesAPI, employeesController.create);
// Retrieve all Employees
app.get(employeesAPI, employeesController.findAll);
// Retrieve a Employee by ID
app.get(employeesAPI + '/:id', employeesController.findOne);
// Update a Employee by ID
app.patch(employeesAPI + '/:id', employeesController.update);
// Delete a Employee by ID
app.delete(employeesAPI + '/:id', employeesController.delete);
};
コードに見られるように、先の作ったcontrollerをインポートして、controllerのエンドポイントを変数に保存しました。そして、それぞれの作ったメソッドにrouteがセットされました。
最終的に、app.jsファイルに戻って、その作ったrouteをインポートして、とうとうテストがもうできます。そうするために、ターミナルに行って、次に見せられるように、このコマンドように書きます:
nodemon app.js
もう今、PostmanのHTTP Clientで、テストできますよ!
##終わり
全部の手順を正確にすれば、作動しているExpressとSequelizeを統合されたNode.js REST APIのアプリをもう書くようにできました!やったね!日本語勉強中なので、この記事は内容が分かりにくいかもしれなくても、読んで頑張ってありがとうございました!
じゃあまたね!