Node.js+MySQL+ExpressでWebアプリをつくる その1【MySQLにデータベースを作成して、それを表示する】

前提

・Node.jsのインストール

package.jsonの生成

好きな場所に「pj」フォルダを作り、package.jsonを生成する

cd pj
npm init --yes

※package.jsonとは

インストールしたnpmパッケージの一覧を記述したjsonファイル

※npmとは

Node Package Managerの略。Nodeにおけるパッケージ(=拡張機能)を管理するためのツール

npmパッケージのインストール

今回は2つのパッケージをインストールする

ejs

Embedded JavaScriptの略

HTMLのコードの中にJavascriptを埋め込むことができるようになるnpmパッケージ

express

テンプレートエンジンと呼ばれるもの

Staticなテンプレートファイルを基に、そのファイル内の変数などを置き換えてHTMLファイルを作成してクライアント(ブラウザ)に返す機能をもっている

npm install ejs
npm install express

ファイルの新規作成

pjフォルダ直下にapp.jsを作成し、次のコードを記述する

// expressの読み込みと使用準備
const express = require('express');
const app = express();

// expressにおけるルーティング
app.get('/', (req, res) => {
  res.render('index.ejs');
});

// サーバーをローカルホストのどこで立ち上げるか指定する
app.listen(3000);

pjフォルダ直下にviewsフォルダを作成し、その中にindex.ejsを新規作成してh1タグを記述する

<h1>Hello!</h1>

CSSの適用

CSSや画像ファイルはpublicディレクトリに置くこと

publicディレクトリを新規作成し、その中にcssディレクトリをつくり、その中にstyle.cssをつくる

このままではCSSが適用されないので、app.jsに

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

と書き、publicディレクトリ内のファイルを読み込めるようにしておくこと

あとはindex.ejsにlinkタグを設置するだけ

<link rel='stylesheet' href='/css/style.css'> // publicフォルダを起点としたパス

画像を使う

画像もpublicディレクトリ内に置くこと

publicディレクトリ内にimageディレクトリをつくり、その中にtop.pngを置く

index.ejsには

<img src='/image/top.png'> // publicフォルダを起点としたパス

サーバーの起動

サーバーを起動して「localhost:3000」というURLにアクセスする

node app.js

Error Failed to lookup view “hello.ejs” in views directory

アプリケーションディレクトリーの直下にviewsディレクトリがないときに発生するエラー

viewsディレクトリを作成し、その中にindex.ejsを置くこと

nodemon のインストール

このままだとjsファイルを更新した際にはサーバーを再起動しないと反映されない

Ctrl+Cでサーバーを停止した後に、node app.jsでサーバーを再起動しないといけない

毎回サーバーを再起動するのがメンドウな場合は、

ファイル更新時に自動でサーバーを再起動させてくるnpmパッケージ「nodemon」をインストールする

npm install -g nodemon

nodemonでサーバーを起動する場合は

nodemon app.js

※これを実行して以下のエラーが発生した場合は(https://rainbow-engine.com/ps-script-execution-disabled/)を参照してください。

ーーーーー

nodemon : このシステムではスクリプトの実行が無効になっているため、ファイル C:\Users\xxxxx\AppData\Roaming\npm\nodemon.ps1 を読み込むことができません。

ーーーーー

MySQLのインストール

まず、MySQLがすでにインストールされていないか確認する

mysql --version

インストールされていない場合は(https://dev.mysql.com/downloads/mysql/)からダウンロードすること

※Progateではversion5.7をインスコしているけれど、2023年10月にサポート終了するので最新バージョンをインストールした

手順は(https://prog-8.com/docs/mysql-env-win)を参照

MySQLを起動してログインする

MySQLは起動しないとログインできないので注意

net start mysql57 // progateではバージョン5.7だが、最新版LTSは8.4なので注意
mysql --user=root --password

※これで接続できない場合は、MySQL Command Line Client から接続したほうがいい

データベースの作成

データベースを作成したらSHOWでデータベースの一覧を確認すること

※クエリの最後にセミコロン(;)を忘れずに

CREATE DATEBASE db1;
SHOW databases;

テーブルの作成

usersという名前のテーブルを作成する

USE db1;
SHOW tables; // 作ったばかりのデータベースなのでテーブルが存在しないことを示すEmpty setが表示される
CREATE TABLE users (id INT AUTO_INCREMENT, name TEXT, PRIMARY KEY(id)) DEFAULT CHARSET=utf8;
SHOW tables; // テーブルが作成されているか確認する
DESCRIBE users; // テーブル構造を確認する

※プライマリーキーとはレコードを識別するための制約で、設定したカラムには重複する値を挿入できなくなる

テーブルにデータを挿入する

SELECT * FROM users; // usersテーブルが空であることを確認
INSERT INTO users(name) VALUES ('山田太郎');
SELECT * FROM users;

※テーブルやデータベースの削除

// テーブルの削除
SHOW tables;
DROP TABLE users;

// データベースの削除
SHOW databases;
DROP DATABSE db2;

mysqlパッケージのインストール

アプリケーションフォルダの直下で下記コマンドを実行

npm install mysql

MySQLへの接続情報を記述する

app.jsに接続情報を記述する

// 最初にexpressのインスタンスを生成しておく
const express = require('express');
const app = express();

// インスタンスを生成
const mysql = require('mysql');

const connection = mysql.createConnection({
  host: 'localhost',
  user: 'root',
  password: '', // 初期値は空
  database: '' // データベース名(この記事ではdb1という名前でデータベースを作成した)
});

MySQLへ接続する

app.jsに下記コードを記述し、接続成功した場合にはconsole.logで出力する

app.get('/index', (req,res) => {

  connection.connect( (err) => {
    // 接続できない時はエラーを表示
    if(err) {
      console.log('エラー発生:' + err.stack);
      return;
    }
  
    // 接続成功した場合の処理を記述する
    console.log('接続成功');
  
    // クエリの実行&その後の処理
    connection.query(
      'SELECT * FROM users',
      (error, results) => {
        console.log(results);
        // usersテーブルの中身を{プロパティ:値}の形でindex.ejsに渡す
        res.render('index.ejs', {users: results});
      }
    );
  });

});

index.ejsで値を表示する

app.jsで受け取ったプロパティusersを使って、idやnameを表示する

<ul>
  <% users.forEach( (user) => { %>
  
    <li>
        <%= user.id %>
        <%= user.name %>
    </li>
    
  <% }); %>
</ul>

一旦サーバーを立ち上げてみる

エラー1「code: ‘MODULE_NOT_FOUND’」

code:–の前にError:Cannot find module ‘mysqwl’ って書いてある

mysqlの綴りを間違えてた

エラー2「Error: ER_NOT_SUPPORTED_AUTH_MODE: Client does not support authentication protocol requested by server;」

和訳すると「クライアントはサーバーから要求された認証プロトコルをサポートしていません」

MySQL5.7までとMySQL8.0以降でパスワードの認証形式(authentication protocol)が違うから起きるエラー

下記コマンドで認証パスワードを見てみよう

mysql> SELECT user, host, plugin FROM mysql.user;

MySQL5.7まではmysql_native_passwordというプラグインを使ってパスワードを暗号化していたが、MySQL8.0以降はcaching_sha2_passwordというプラグインを使ってパスワードを暗号化している

なので、下記コマンドで認証プラグインを変更するか、

mysql> ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password';

もしくはmysql2というnpmパッケージを使うこと

https://www.chuken-engineer.com/entry/2020/09/04/074216

npm install mysql2

mysql2 ならcaching_sha2_passwordの状態でも無事に接続できる

ただし、当然、app.jsファイル内では

const mysql = require('mysql2');

としなければならない

エラー3「index.ejsにてCannot read properties of undefined (reading ‘forEach’)」

和訳すると「undefinedのforEachというプロパティは読み込めませんよ」という意味

例えば、 <% users.forEach( (user) => {}); としているならusersがundefinedなのでforEachもundefinedになってしまう

エラー4「Access denied for user ‘root’@’localhost’ (using password: NO)」

和訳すると、パスワードがねえから開かねえぞ という意味。

password: passwordとしてみたら接続できた

エラー5「TypeError: req.next is not a function」

res.render(‘index.ejs’)を2回書いてた

MySQLを切断

connection.end();

参考サイト

https://prog-8.com/docs/nodejs-mysql

https://cs-tklab.na-inet.jp/nodejs/nodejs/express.html