ExpressでCRUDアプリ（メモアプリ）を作る

Expressで基本的なCRUDアプリを作成する際の手順をまとめました。
DBにはMySQLを使います。

## 対象読者
初めてExpressを触る方

## 使用したバージョン
macOS Catalina 10.15.4
node:v12.14.0
MySQL:v8.0.19
Express:v4.17.1

## MySQLを使う準備
自前のMacにMySQLが入っていない場合、MySQLをhomebrew経由でインストールする。
```brew install mysql```

// 起動
```mysql.server start```

// 停止
```mysql.server stop```

//ステータス確認
```mysql.server status```

// バージョン確認
```mysqld --version```

＊MySQLのバージョンが8以上の場合、node.jsからMySQLへの接続時エラーが出るため以下のページを参考にすると良いです。
[Express.js(node.js)からMySQLへの接続とCRUD操作 | アールエフェクト] (https://reffect.co.jp/node-js/express-js-connect-mysql#MySQL)

## プロジェクト作成〜Hello Worldまで
適当なディレクトリを作って```npm init -y```でプロジェクトを作成。
```npm install express```でexpressインストール
```npm install mysql```でmysqlインストール
```npm install ejs```でejsインストール
###DB作成
create-database.jsを作成し、以下を記述します。

```javascript:create-database.js
const mysql = require('mysql');

const connection = mysql.createConnection({
  host: 'localhost',
  user: 'root',//mysqlと合わせる
  password: '',//mysqlと合わせる
});

//mysqlに接続してデータベース作成(成功するとconsoleに'database created'と出る)
connection.connect(function(err) {
    if (err) throw err;
    console.log('Connected');
    connection.query('CREATE DATABASE express_db', function (err, result) {
    if (err) throw err; 
      console.log('database created');
    });
});
```
※mysqlは```mysql.server start```のコマンドで立ち上げておきます。
```node create-database.js```を実行するとDBが作成されます。

###テーブル作成
create-table.jsを作成し、以下を記述します。

```javascript:create-table.js
const mysql = require('mysql');

const connection = mysql.createConnection({
  host: 'localhost',
  user: 'root',//mysqlと合わせる
  password: '',//mysqlと合わせる
  database: 'express_db' //先ほど作成したDBの名前
});

//テーブルの作成
connection.connect(function(err) {
    if (err) throw err;
    console.log('Connected');
    const sql = 'CREATE TABLE items (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, title VARCHAR(255) NOT NULL, text VARCHAR(255) NOT NULL)';
    connection.query(sql, function (err, result) {  
    if (err) throw err;  
    console.log('table created');  
    });
});
```
```node create-table.js```を実行するとitemsテーブルが作成されます。

###ローカルサーバーの設定


app.jsを作成し、以下を記述します。

```javascript:app.js
const express = require('express');
const mysql = require('mysql');
const app = express();

app.use(express.static('public'));//静的配信のフォルダを指定
app.use(express.urlencoded({extended: false}));

const connection = mysql.createConnection({
  host: 'localhost',
  user: 'root',//mysqlと合わせる
  password: '',//mysqlと合わせる
  database: 'express_db' //先ほど作成したDBの名前
});

//viewsディレクトリ以下のejsファイル認識させる
app.set('views', './views');
app.set('view engine', 'ejs');

//hello world
app.get("/", (req,res) => {
    res.send("Hello World");
});

app.listen(3000);//3000ポートでローカルサーバーたつ
```
```node app.js```を実行するとローカルでサーバが立ちます。
localhost:3000にアクセスすると'Hello World'と表示されます。

## CRUD
app.jsを編集し、基本的なCRUD機能を実装していきます。
※変更を加えた際は、ブラウザで確認する前に一度ctrl+Cでサーバーを停止させてから再度```node app.js```を実行してください。
### 作成(create)
```app.js
const express = require('express');
const mysql = require('mysql');
const app = express();

app.use(express.static('public'));
app.use(express.urlencoded({extended: false}));

const connection = mysql.createConnection({
  host: 'localhost',
  user: 'root',
  password: '',
  database: 'express_db' 
});

//viewsディレクトリ以下のejsファイル認識させる
app.set('views', './views');
app.set('view engine', 'ejs');

//hello-world
app.get("/", (req,res) => {
    res.send("Hello World");
});

/* ============ここから追加============ */
//新規作成画面のルーティング
app.get('/new', (req, res) => {
    res.render('new.ejs');
});
//新規作成アクション
app.post('/create', (req, res) => {
connection.query(
    'INSERT INTO items (title, text) VALUES (?, ?)',
    [req.body.itemTitle, req.body.itemText],
    (error, results) => {
    res.redirect('/')//methodがpostのときはredirectを使う
    }
);
});
/* ============ここまで追加============ */

app.listen(3000);
```
```html:views/new.ejs
<form action="/create" method="post">
    <input type="text" name="itemTitle">
    <input type="text" name="itemText">
    <input type="submit" value="作成する">
</form>
```
localhost:3000/newにアクセスすると、フォームが表示されるようになります。
「作成する」をクリックすると、DBにデータが保存されます。

### 一覧(read)
Hello Worldと表示させていた部分を投稿したデータが一覧表示されるようにします。app.jsを修正し、index.ejsを新規作成します。

```app.js
const express = require('express');
const mysql = require('mysql');
const app = express();

app.use(express.static('public'));
app.use(express.urlencoded({extended: false}));

const connection = mysql.createConnection({
  host: 'localhost',
  user: 'root',
  password: '',
  database: 'express_db' 
});

//viewsディレクトリ以下のejsファイル認識させる
app.set('views', './views');
app.set('view engine', 'ejs');

/* ============ここから変更============ */
//一覧画面のルーティング
app.get('/', (req, res) => {
    connection.query(
      'SELECT * FROM items',
      (error, results) => {
        res.render('index.ejs', {items: results});//itemというキーでviewにデータベースの中身を渡せる
      }
    );
  });
/* ============ここまで変更============ */

//新規作成画面のルーティング
app.get('/new', (req, res) => {
    res.render('new.ejs');
});
//新規作成アクション
app.post('/create', (req, res) => {
connection.query(
    'INSERT INTO items (title, text) VALUES (?, ?)',
    [req.body.itemTitle, req.body.itemText],
    (error, results) => {
    res.redirect('/')
    });
});

app.listen(3000);
```

```html:views/index.ejs
<% items.forEach((item) => { %>
 <li>
  <div>
   <span><%= item.title %></span>
   <span><%= item.text %></span>
  </div>
 </li>
<% }) %>
```
### 編集(update)
一覧画面から、それぞれの記事の編集画面に飛べるようにapp.jsとindex.ejsを修正し、edit.ejsを新規作成します。

```app.js
/* ~~省略~~ */

//新規作成画面のルーティング
app.get('/new', (req, res) => {
    res.render('new.ejs');
});
//新規作成アクション
app.post('/create', (req, res) => {
connection.query(
    'INSERT INTO items (title, text) VALUES (?, ?)',
    [req.body.itemTitle, req.body.itemText],
    (error, results) => {
    res.redirect('/')
    });
});

/* ============ここから追加============ */
//編集画面へのルーティング
app.get('/edit/:id', (req, res) => {
    connection.query(
      'SELECT * FROM items WHERE id = ?',
      [req.params.id],
      (error, results) => {
        res.render('edit.ejs', {item: results[0]});
      }
    );
});

//更新アクション
app.post('/update/:id', (req, res) => {
    connection.query(
    'UPDATE items SET title = ?, text = ? WHERE id = ?',[req.body.itemTitle, req.body.itemText, req.params.id],(error,results)=>{
      res.redirect('/');
    })
});
/* ============ここまで追加============ */

app.listen(3000);
```

```html:views/index.ejs
<% items.forEach((item) => { %>
    <li>
      <div>
        <span><%= item.title %></span>
        <span><%= item.text %></span>
      </div>
    </li>
<!-- ============ここから追加============ -->
    <a href="/edit/<%= item.id %>">編集</a>
<!-- ============ここまで追加============ -->
<% }) %>
```


```html:views/edit.ejs
<form action="/update/<%= item.id %>" method="post">
 <input type="text" name="itemTitle" value="<%= item.title %>">
 <input type="text" name="itemText" value="<%= item.text %>">
 <input type="submit" value="更新する">
</form>
```
### 削除(delete)
一覧画面から、それぞれの記事を削除できるようにapp.jsとindex.ejsを修正します。

```app.js
/* ~~省略~~ */

//編集画面へのルーティング
app.get('/edit/:id', (req, res) => {
    connection.query(
      'SELECT * FROM items WHERE id = ?',
      [req.params.id],
      (error, results) => {
        res.render('edit.ejs', {item: results[0]});
      }
    );
});

//更新アクション
app.post('/update/:id', (req, res) => {
    connection.query(
    'UPDATE items SET title = ?, text = ? WHERE id = ?',[req.body.itemTitle, req.body.itemText, req.params.id],(error,results)=>{
      res.redirect('/');
    })
});

/* ============ここから追加============ */
//削除
app.post('/delete/:id', (req, res) => {
    connection.query(
      'DELETE FROM items WHERE id = ?',
      [req.params.id],
      (error, results) => {
        res.redirect('/');
      }
    );
});
/* ============ここまで追加============ */

app.listen(3000);
```
```html:views/index.ejs
<% items.forEach((item) => { %>
    <li>
      <div>
        <span><%= item.title %></span>
        <span><%= item.text %></span>
      </div>
    </li>
    <a href="/edit/<%= item.id %>">編集</a>
<!-- ============ここから追加============ -->
    <form action="/delete/<%= item.id %>" method="post">
      <input type="submit" value="削除">
    </form>
<!-- ============ここまで追加============ -->
<% }) %>
```

以上でCRUD機能の実装は完了です！

##完成形
[GitHub](https://github.com/yuikoAkiyoshi/expressCRUDapp)に完成形のコードを上げてます。ご参考まで。


##参考
//mysqlのインストール（記事の前半部分）
https://reffect.co.jp/laravel/mysql-laravel-in-mac

//データベースの作成、テーブルの作成など
https://reffect.co.jp/node-js/express-js-connect-mysql