ExpressでToDoアプリケーション(DBのCRUD実装)

はじめに

Expressについて学びました。

※Node.jsの記事が長くなったので分けました。

Node.jsのまとめ

✅ゴール
Node.jsとExpressの理解を深める

✅環境
Windows/XAMPP

✅参考教材
📚Node.js超入門

以下、超入門。

テンプレートエンジンにEJS活用。fetchメソッド使っていたり割とモダン。

以前はejs使うのでそこで抵抗感が出たけど悪くなさそう。Kindleで購入したのがミス。

後半はXAMPPでサーバー立ててMySQLを活用したExpressでの掲示板アプリ制作をする。

📚Nodeクックブック

以下、クックブック

サンプルコード

💻Progate

Express

✅Expressとは

Node.js独自の機能を組み込んだアプリケーションフレームワーク(アプリ作成の仕組みと機能をまとめたソフトウェア)。

特徴
ルーティングの設定が容易
JSのテンプレートエンジンを用いる(Node.jsも同じだが)

✅基本

①インストール

npm install -g express
npm install -g express-generator // あると便利。(アプリの基本部分の自動生成、モジュールを揃えてくれる。)

P227にファイル構成あり。

②プロジェクト生成

express sampleapp

③依存モジュールのインストール

npm install

④起動

npm start
node bin/www // 別パターン

⑤アクセス

http://localhost:3000/

http://localhost:3000/users ※最初から用意されている。

routes/users.jsを編集した際はnpm startで再起動しないと変更が反映されない。逆にviewsディレクトリ下の.jadeファイルはすぐ反映された

✅expressコマンドを使わずにExpressプロジェクトの作成

①package.jsonの作成

npm init

②編集

{
  "name": "nodejs_lesson",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "eslint": "eslint ./",
    "start": "nodemon ./app.js"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "ejs": "^2.6.1",
    "express": "^4.16.4"
  },
  "devDependencies": {
    "nodemon": "^1.18.10"
  }
}

※nodemanはソースを監視して、自動でサーバーを再起動してくれるツール。 参考

③インストール

npm i

④app.jsの作成

const express = require('express');
const app = express();

app.get('/', (req, res) => {
  res.send('Hello, Express');
});

app.listen(3000);

⑤実行

npm run start

http://localhost:3000/へアクセスして確認

🙄これだけでサーバー起動できるのはすごい!!

✅ルーティングの設定

※上記のexpressコマンドを使わずに作ったプロジェクトで以下を実施していきます。

ルーティングの設定はexpressのget()メソッドを使う。

get(url, (req, res) => {処理});

①app.jsを編集

const express = require('express');
const app = express();

app.get('/page', function(req,res){
  res.send('Hello, new page!!')
})

②確認

http://localhost:3000/page

🙄素のNodeだとpathモジュールやurlモジュールが隠蔽されているので楽ですね!

✅テンプレートやCSSの適用

・ビューファイルを表示させたい場合

①views/top.ejsを作成

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Express</title>
  </head>
  <body>
    views/top.ejs
  </body>
</html>

②app.jsに以下を追記

app.get('/top', function(req,res){
  res.render('top.ejs')
})

※上記のようにres.send()の部分でrender()メソッドに変更すればOK。

🙄自動でviewsディレクトリを参照するみたいです。

・CSSなどを適用させたい場合

①app.jsで以下を追記。CSSや画像ファイルの場所を指定してあげる。

app.use(express.static('public'));

※プロジェクト直下のpublicフォルダを読み込みたい場合。

②public/style.cssの作成

h1 {
  color: aqua;
}

③テンプレート側でパスを指定して読込。

<link rel="stylesheet" href="style.css">
<h1>views/top.ejs</h1>

④確認

✅テンプレート

デフォルトはPug(旧jade)

参考:Pug(Jade)って何だ?特徴や基本的な使い方の解説

初期設定だとテンプレートエンジンはviewディレクトリ下にありJade(現在はPugと呼ばれている)が使われている。これがHTMLに変換されて描画される。

Pugでプロジェクトを作る場合。

express --pug expressapp-pug

EJSを使う場合

※超入門ではこちらを用いている。

EJSを用いる際はプロジェクト生成時に以下のように付け足してあげればOK。

express --ejs expressapp-ejs

参考:JavaScriptテンプレートエンジンのPug(Jade)とEJSの比較

参考:アンチPug派がPugのことを褒めちぎる

参考:jadeがpugになって変わった所のメモ

EJSはHTMLとほぼ同じ。Pugは閉じタグがなく、階層をインデントで表現するみたいです。効率よく書きたいならPugかな~

ToDoアプリ制作(EJSを使ってみる)

※上記に続けてプロジェクトを使っていきます。

EJSはHTMLとJSの両方を記述することができる。

JavaScriptのコードを記述したい場合、<% %>または<%= %>で囲む。
<% %>で囲んだ場合はブラウザに何も表示されないため、変数の定義などに用いる。
変数の値などをブラウザに表示したい場合は<%= %>を用いる。

①EJSのインストール

npm i -g ejs

②index.ejsを編集

※試しにforEachを使ってみました

<h1>Hello, index page!!</h1>
<%
 const items = [
    {id:1, name:"sato" },
    {id:2, name:"saito" },
    {id:3, name:"suzuki" },
  ];%>
<% items.forEach((item)=>{ %>
   <%= item.id %>
   <%= item.name %>
<% }); %>

③確認

✅リンクを作成

aタグを使えばOK

①top.ejsを編集

<h1>Hello, Express!!</h1>
<a href="/index">一覧を見る</a>

②確認。クリックするとindex.ejsが表示されます。

DB活用

今回はXAMPP上のmysqlを使ってみます。

✅DB作成

①Express用のmysqlモジュールをインストール

npm i mysql

②app.jsを編集して接続

createConnectionメソッドを使うことで接続できる。

const client = mysql.createConnection({
  host: 'localhost', // なくてもOK
  user: 'root',
  password: '',
  // database: 'express-app' // DBを指定したい場合
  port: 3306
});

③クエリの実行を記載

queryメソッドを使うことで実行できる。

client.query('クエリ', クエリ実行後の処理);

DB作成

client.query('CREATE DATABASE quotes');

④実行

node app.js

http://localhost/phpmyadmin/へアクセスして作成できていることを確認◎

※DB接続

client.useDatabase('quotes');

※テーブル作成

client.query('CREATE TABLE quotes.items ('+
    'id INT NOT NULL AUTO_INCREMENT,' +
    'name VARCHAR(128) NOT NULL'+
    ')'
  );

※クエリで取得したデータをテンプレートに渡す

✅DBの取得

※あらかじめDBにテーブルとデータを作成しています。

①app.jsを編集

const express = require('express');
const app = express();
const mysql = require('mysql');

app.use(express.static('public'));

const client = mysql.createConnection({
  user: 'root',
  password: '',
  database: 'quotes',
  port: 3306
});

app.get('/', (req, res) => {
  res.render('top.ejs');
});

app.get('/index', (req, res) => {
  client.query(
    'SELECT * FROM items',
    (error, results) => {
      console.log(results);
      res.render('index.ejs', {items: results});
    }
  );
});

app.listen(3000);

※renderメソッドの第2引数で{プロパティ:値}と書くことでEJS側に値を渡すことが可能。

②実行。コンソールでデータが取得できていることがわかる。

> node app.js
[
  RowDataPacket { id: 1, name: 'sato' },
  RowDataPacket { id: 2, name: 'saito' },
  RowDataPacket { id: 3, name: 'suzuki' }
]

③取得した値の表示

index.jsを編集

※テンプレート側で定義した定数itemsを削除して表示されるか確認してみました。

<!-- <% const items = [
  {id:1, name:"sato" },
  {id:2, name:"saito" },
  {id:3, name:"suzuki" }, ];
%> -->
MySQL(XAMPP)のデータを参照
 <% items.forEach((item)=>{ %>
<%= item.id %>
<%= item.name %>
<% }); %>

④確認

✅DBの追加

①フォーム送信②DBへ追加処理③一覧画面で取得

app.jsの編集

app.use(express.urlencoded({extended: false})); // add
~~~~
app.get('/new', (req, res) => {
  res.render('new.ejs');
});

app.post('/create', (req, res) => {
  // formのreq.body.itenName(名前属性値)に入力値が入っている
  client.query(
    // idはAUTO_INCREMENTを指定しているので指定不要
    'INSERT INTO items (name) VALUES (?)',
    [req.body.item],
    (error, results) => {
      // 一覧画面にリダイレクト
      res.redirect('/index');
    }
  );
});

new.ejsの作成

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Express</title>
    <link rel="stylesheet" href="css/style.css">
  </head>
  <body>
    <h1>新規投稿</h1>
    <form action="/create" method="POST">
      <input type="text" name="item">
      <input type="submit" value="作成">
    </form>
    <a href="/">トップ</a>
    <a href="/index">一覧を見る</a>
  </body>
</html>

👇以下ポイント

input要素にname属性を指定すると、オブジェクトの形で情報がサーバーに送信される。
よってサーバー側ではreq.body.name属性の値でフォームの値を取得できる。

req:{
  body: {
    item: "インプット入力値"
  }
}

フォームの値を受け取るための定型文

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

フォームからの値をクエリに使うときは、VALUESに「?」を含め、「connection.query()」の第2引数に渡したい配列を指定。
この配列の要素が「?」の部分に入り、実行される。

また、リダイレクトで別ページに遷移する処理を実装することでリロード時のデータの再追加を防ぐことができる。

res.redirect(‘URL’)で実装可能。

✅削除機能の実装

app.jsの編集

app.post('/delete/:id', (req, res) => {
  client.query(
    'DELETE FROM items WHERE id=?',
    [req.params.id],
    (error, results) => {
      res.redirect('/index');
    }
  );
});

index.ejsの編集

<li>
  <span><%= item.id %></span>
  <span><%= item.name %></span>
  <form action="/delete/<%=item.id%>" method="POST">
    <input type="submit" value="削除">
  </form>
</li>

👇以下ポイント

POST送信の場合は入力項目がなくてもformタグを使う。

削除項目を指定したいのでルートパラメータ(delete/:id)を用いる。

ルートパラメータの取得はreq.params.ルートパラメータを用いる。

✅更新機能の実装

①リンクでidを送信②DBから指定のデータを取得③編集画面で更新

app.jsの編集

app.get('/edit/:id', (req, res) => {
  client.query(
    'SELECT * FROM items WHERE id = ?',
    [req.params.id],
    (error, results)=> {
      // 取得結果の1件目を配列から取り出し
      res.render('edit.ejs', {item: results[0]});
    }
  );
});

app.post('/update/:id', (req, res) => {
  client.query(
    'UPDATE items SET name=? WHERE id=?',
    [req.body.item,req.params.id],
    (error, results) => {
      res.redirect('/index');
    }
  );
});

index.ejsの編集

  </form>
  <a href="/edit/<%=item.id%>"><button>編集</button></a> // add
</li>

edit.ejsの作成

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Express</title>
    <link rel="stylesheet" href="css/style.css">
  </head>
  <body>
    <h1>編集</h1>
    <form action="/update/<%=item.id%>" method="POST">
      <input value="<%=item.name%>" type="text" name="item">
      <input type="submit" value="作成">
    </form>
    <a href="/">トップ</a>
    <a href="/index">一覧を見る</a>
  </body>
</html>

👇以下ポイント

編集ページへルートパラメータを指定してアクセス。

ルートパラメータからデータを取得してその値を編集画面のインプットにvalue属性で初期値として表示。

更新にはidとフォームの値2つが必要になるので、queryメソッドの第1引数で?2つ、第2引数で配列にして2つの値を渡す。

🙄render()メソッドの第2引数でデータの受け渡しをしているのが印象的だった。

ToDoアプリ完成

・トップ画面

・一覧画面

・新規投稿画面

・更新画面

※h1にスタイルが適用されていませんが一旦スルーします。。。

EJSからPugに置き換え

既に繰り返し構文を書くのに<%= %>を書くのがめんどくさいなと思ってしまっていたので試してみました。

参考:

💻[Node.js][Express]pugを使う

構築方法はコチラの記事が参考になる。

💻pug入門

記法についてはこちら

💻アンチPug派がPugのことを褒めちぎる

extends でテンプレートの継承ができるのがめちゃ便利ですね!!

✅使ってみる

pugをインストール

npm install --save pug

上記記事を参考にviews/top.pugを作成

div.hoge
  h2.hoge-title タイトル
  div.hoge-button
      a(href="#", target="_blank") リンク
  p.hoge-text テキスト

app.jsに追記

app.get('/pug', (req, res) => {
  res.render('top.pug');
});

http://localhost:3000/pugへアクセスして確認

🙄ExpressではPugをそのまま表示してくれるぽい。便利。

app.setでview engineにpugを指定する。するとrenderメソッドで指定している拡張子を記載しないで表示してくれるようになる。

app.set('view engine', 'pug');

※同様にpugの部分をejsにすることも可能。

※例えば上記でpug指定していた場合でも、index.ejsのように拡張子まで指定すれば共存することも可能だった。

curlコマンドでHTMLの表示を確認することもできます。

> curl http://localhost:3000/pug

StatusCode : 200
StatusDescription : OK
Content : <div class="hoge"><h2 class="hoge-title">タイトル</h2><div class="hoge-button"><a href="#" target="_blank">リンク</a></div><p class="hoge-tex
t">テキスト</p></div>
RawContent : HTTP/1.1 200 OK
~~以下省略

🙄記法を覚えればかなり戦力になってくれそう。

✅継承を試す

_layout.pugを作成

doctype html
html
  head
    block title
      title ページタイトル
  body
    p ここは共通部分です。以下はページごとに変わる部分です
    block content
    script(src="/js/common.js" defer)
    block script

top.pugを編集

extends _layout.pug

block title
  title 1ページ目

block content
  h1 これは1ページ目です

http://localhost:3000/pugへアクセスして確認

✅繰り返し構文

参考:Pugで条件分岐やループを使ってみる

以下を上記top.pugに追記。

  - for (var x = 0; x < 3; x++)
    li item#{x}

以下のようになる。

🙄楽ですね。

最後にゆくゆく参考にしたいサイト:Pug(Jade)記法でHTMLのテンプレート的なの

👆これは実際に使う必要に迫られてからだろうな~

デプロイに関して

✅Herokuでのデプロイ

参考:Express チュートリアル Part 7: プロダクションへのデプロイ

Node.js(Expressフレームワーク)アプリをHerokuにデプロイする方法

Getting Started on Heroku with Node.js(公式)

実施はしていませんが、いくつか記事を見ていると、基本的にHerokuのチュートリアルが多い印象。公式もあるし。

git経由でデプロイ側のサーバーからSSH接続なりしてソースコードを取得。パッケージのインストールで環境構築。

✅Reactとの組み合わせ

参考:React+Expressで本番環境へデプロイ

上記記事ではReactでビルドしたファイルをExpressの公開フォルダ(public)に配置。

expressのルーティングをつかさどるget()メソッドの引数に関数として通常定義されるrenderメソッドをsendfileメソッドに変更し、ファイルを指定する。

参考:Node.js, Express, sequelize, React で始めるモダン WEB アプリケーション入門(Express/sequelize編)

参考:Node.js, Express, sequelize, React で始めるモダン WEB アプリケーション入門(React編)

おわりに

Expressで簡易的なCRUD実装アプリを作ることができた。

サーバー側の実装もNode.jsから学んだことでフルスタックでイメージできるようになったのでいい勉強になった。

デプロイに関しては、例えばXserverのMySQLなど使う場合はパスワードを隠蔽すべしだからSSH接続して本番環境側で編集すれば良さそう。

以前、Node.jsはインストールしているので試してみようかな。

コメントを残す