82
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

開発者はもう観察しているように、バックエンドウェブ開発のための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開発者としてアルバイトをしています。宜しくお願い致します!

それでは、始めましょうか。

1__SmZzhgGpZ5tHeUM8toUWQ.jpeg

ORMとは

Object Relation Mappingというモデルはオブジェクトとリレーショナルデータベースの接続を手順としています。手動でSQLステートメントを書く必要性を排除するために使用されますが、むしろ、オブジェクトを通して、はるかに速くそしてより読みやすいQuery操作をすることができます。

Sequelizeとは

Sequelizeは、Node.js用のpromised-basedのORMです。それは習得が容易で、SynchronizationAssociationのような機能を持っています。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-clinodemonをインストールするようになりました。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;

このファイルはウェブサービスを作るために、全てを縛るメインファイルです。だから、折々このファイルに戻ります。コードに見られたように、サーバーを設定するためのブラリとして、expressbody-parserhttpがインポートされました。そして、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を簡単に使えるようになります。

後は、これからモデルの作成に進めます。EmployeeCompanyのモデルを作ります。この2つの間にそれぞれのEmployeeが1つのCompanyで働いてて、逆でそれぞれのCompanyがたくさんEmployeeを持てるという関係になります。だから、後に、SequelizeでbelongsToOne-is-to-Oneを表し、hasManyOne-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つに分けられて、MigrationsModelsを一部としています。

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

CompanyMigrationファイルが見られるように、idcreatedAtupdatedAtと共に、nameフィールドがすでに設定されています。

一方でEmployeeというMigrationにはnamesalaryの両方フィールドがあります。しかし、EmployeeCompany次第なので、手動で、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-ManyCardinalityを持っているので、次に示すコードのように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);
    });
  }
}

上に見せられるように、データベースにEmployeeCompanyのテーブルが生成されたので、Controllerを作る時間になりました。Controllerフォルダに行って、employee.controller.jsを名前として、新しいファイルを作ります。このところにウェブメソッドを作っていきます。Sequelize接続をアクセスするために、モデルフォルダのindex.jsファイルをインポートして、EmployeeCompanyのモデルを変数に入ります。

SequelizeはORMなので、手動でQueryを作らなくていいです。createfindAllfindOneupdatedestroyのような定義済み関数を使うだけです。また、一目瞭然の関数名前なので、使い方はすぐ分かります。SequelizeのQuerypromise-basedの関数だから、callbackerrorは管理しやすいです。

このコードのハイライトはそのfindOnefindAllというメソッドです。なぜなら、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

もう今、PostmanHTTP Clientで、テストできますよ!

終わり

全部の手順を正確にすれば、作動しているExpressSequelizeを統合されたNode.js REST APIのアプリをもう書くようにできました!やったね!日本語勉強中なので、この記事は内容が分かりにくいかもしれなくても、読んで頑張ってありがとうございました! 

じゃあまたね!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
82
Help us understand the problem. What are the problem?