前ページで環境構築が終わったので、いよいよWebアプリの作成に入ります。
本章ではフロントエンドのReact、バックエンドのNode.js、データベースのMySQLの基本設定と構築を行い、3方を相互に接続するところまでが目標です。
具体的には、フロントエンドからバックエンドを通じてデータベースにアクセスし、取得したデータを表示することができるようにしていきます。
- バックエンドサーバーの構築(Node.js)
- APIエンドポイントの作成(Node.js)
- フロントエンドの構築(React)
- フロントエンドとバックエンドを接続(React+Node.js)
- バックエンドとデータベースを接続(Node.js+MySQL)
- フロントとバックとデータベースを接続(React+Node.js+MySQL)
※1~3については、Microsoftの公式ドキュメントを参照することで、より正確かつ詳しい説明を確認できます。
バックエンドサーバーの構築(Node.js)
最初にプロジェクトフォルダを作成し、作成したフォルダに移動します。フォルダ名は何でも構いませんが、僕は「memo-app」という名前にしました。
#フォルダ(ディレクトリ)を作成
mkdir memo-app
#作成したフォルダに移動
cd memo-app
続いて、npm init
を実行してpackage.jsonファイルを作成します。
ls
コマンドを実行すると、package.jsonファイルが作成されていることが分かります。
npm init -y
雑で申し訳ないですが、package.jsonやnpmについて深堀すると長くなりすぎるので、以下のサイトを参考に理解を深めてください。
今回は、Node.jsの最も一般的なフレームワークである「express」を使用してバックエンドサーバーを構築します。
よってまずは、expressのインストールを行います。
npm install express
次にbackendフォルダを作成し、その中にindex.jsファイルを作成します。
mkdir backend
cd backend
#index.jsファイルを作成
touch index.js
続いて、index.jsファイルにExpressサーバーを稼働させるために必要なコードを記述していきます。
//requireでexpressモジュールを読み込む
const express = require('express');
//expressモジュールを実体化して、定数appに代入
const app = express();
//ポート番号を指定
const port = 3000;
//'/'パスにGET要求があった際に実行する処理
app.get('/', (req, res) => {
res.send('Hello World!');
});
//3000ポートでlisten
app.listen(port, () => {
console.log(`listening on *:${port}`);
})
下記サイトでわかりやすく解説してあるので、興味のある方は見てみてください。
≫jsのimportとrequireの違い
下記サイトでは、expressのディレクトリ構成や記法などについて、初心者向けにわかりやすく解説しているので、一度目を通してみると良いでしょう。
≫expressは一体何をしとるんじゃ・・・
ここで一度ターミナルに戻り、cd
コマンドでmemo-appディレクトリに戻ります。
#一つ上(親)ディレクトリに移動する
cd ..
memo-appディレクトリに移動したら、そこでExpressサーバーを起動します。nodeコマンドの後ろでは、先ほど作成したbackendフォルダ内のindex.jsファイルを指定してください。
node backend/index.js
また、nodeと単体で実行するとREPLが実行される。
ターミナルにlistening on *:3000と表示されたら起動完了です。ブラウザでhttp://localhost:3000/
にアクセスすると、「Hello World」と表示されているはずです。
node backend/index.js
を実行することでサーバーを起動しましたが、毎回ファイル名を指定するのは面倒です。package.jsonファイルにscriptsを追加すれば、もっと手軽にサーバーを起動できるようになります。1.package.jsonファイルを開く
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start-node": "node backend/index.js"
},
2.追加後は、次のコマンドでExpressサーバーを起動できる
npm run start-node
APIエンドポイントの作成(Node.js)
フロントエンド(React)からバックエンド(Express.js)にアクセスする際の、アクセス先(エンドポイント)をExpressサーバー側に準備します。
index.jsを開いて、/api
パスにアクセスした際の処理を記述します。
const express = require('express');
const app = express();
const port = 3000;
app.get('/', (req, res) => {
res.send('Hello World');
}
//'/api'パスにGET要求があった際に実行する処理
app.get('/api', (req, res) => {
res.json({message: "Hello World"});
});
app.listen(port, () => {
console.log(`listening on *:${port}`);
})
試しにhttp://localhost:3000/api
にアクセスしてみて下さい。既述したjsonが表示されていれば成功です。
(うまくいかない場合は、Expressサーバーを再起動してからもう一度試してください)
しかし、都度手動で再起動するのは手間なので、nodemonというパッケージの利用をおススメします。nodemonは、ファイルの変更を検知すると自動でサーバーを再起動してくれるツールです。1.ターミナルで、
memo-app
ディレクトリに移動2.
npm install -g nodemon
を実行3.package.jsonを開く
4.以下のように記述を変更
#変更前
"start-node": "node backend/index.js"
#変更後
"start-node": "nodemon backend/index.js"
以上の手順を踏めば、今まで通りのnpm run start-node
コマンドでnodemonが立ち上がり、ファイル変更時には自動で再起動するようになります。
フロントエンドの構築(React)
次にフロントエンド(React)を構築していきます。
ターミナルにもどってmemo-appディレクトリに移動したら、npx
コマンドでcreate-react-app
を実行します。
フォルダ(ディレクトリ)名は、frontend
としています。
npx create-react-app frontend
処理が完了したらfrontendフォルダに移動して、npm start
コマンドでReactを起動してみてください。
cd frontend
npm start
すると次のようなエラーが表示されるはずです。
これは要するに「3000番ポートがNode.jsによって使用中だから、同じポートでReactを開けませんよ」というメッセージです。
? Something is already running on port 3000. Probably(以下略)
また、エラーメッセージの終わりでは「他のポートでReactを開きますか?」と聞かれています。Yを選択するとReactが3001番ポートで開かれるのですが、今回は3000番ポートでReactを、3001番ポートでNode.jsを開きたいのでNo(n)を選択してください。
Would you like to run the app on another port instead?(Y/n)
次に、backend/index.jsファイルを開いてポート番号を3001に変更します。
#変更前
const port = 3000;
#変更後
const port = 3001;
続いて、ターミナルに戻ってfrontendディレクトリに移動し、npm start
コマンドを実行するとReactを3000番ポートで起動できます。
npm start
最後にReactの初期画面を変更します。
frontend/src/App.jsを開いて次のように変更します。
import './App.css';
function App() {
return (
<div className="App">
<h1>フロントエンド</h1>
</div>
);
}
export default App;
Reactは非同期処理なので、変更を保存した瞬間に(ブラウザを更新しなくても)、変更が反映されて以下のような画面が表示されます。
バックエンドとフロントエンドを接続(React+Node.js)
続いては、フロントエンド(React)からバックエンド(Express)にアクセスしてデータを取得できるようにしていきます。
具体的には、React側からNode.js側のエンドポイント(localhost:3001/api)にアクセスして、当該ページが返しているJSONデータ({message: "Hello World"}
)を取得し、React側で表示します。
データの保持・取得にはReactのHookであるuseStateとuseEffect、およびfetchメソッドを利用します。
お察しの通り、本章のキーワードは「useState」「useEffect」「fetch」の3つですが、意味を知らない方がほとんどだと思います。がしかし、1つずつ掘り下げて解説すると長くなるのでそれぞれ別個で解説記事を用意する予定です。
よって本記事ではそれぞれの詳細な説明は省きますが、コードを追っていけば(コピペでも)アプリは完成しますし使い方もなんとなく分かると思いますので、このまま読み進めてOKです。
まず、初めにコードの完成系を見てください。frontend/srcディレクトリ内のApp.jsを次のように変更します。
import './App.css';
//1.useStateとuseEffectをインポート
import { useState,useEffect } from 'react';
function App() {
//useStateの初期値(空)を設定
const [message, setMessage] = useState('');
useEffect(() => {
//fetchでバックエンドExpressのサーバーを指定
fetch('http://localhost:3001/api')
//レスポンスをjsonとして受け取りjsオブジェクトを生成
.then((res) => res.json())
//生成したjsオブジェクトをdataに代入
//data.messageで取り出したデータをuseStateに保存
.then((data) => setMessage(data.message));
},[])
return (
<div className="App">
<h1>フロントエンド</h1>
//useStateに保存した値を表示
<p>{ message }</p>
</div>
);
}
export default App;
現時点では、変更を反映してもブラウザには何も表示されません。なぜなら、CORSポリシーによってlocalhost:300からlocalhost:3001/apiへのアクセス(fetch)がブロックされているからです。
F12ボタンを押してデベロッパーツールを確認してみると、お怒りメッセージが届いているはずです。
CORSポリシーとは、異なるオリジン(ドメイン、プロトコル、ポート番号)間でのHTTPリクエスト(情報の取得・送信など)を制限するための、ブラウザのセキュリティ機能の1つです。
より詳細かつわかりやすい説明は、以下のサイト・動画を見てみてください。
≫Mozilla.org|オリジン間リソース共有(CROS)
≫CORSの原理を知って正しく使おう|徳丸浩のウェブセキュリティ講座
今回はlocalhost:3000から、別オリジンであるlocalhost:3001へfetchしようとしたためCROSポリシーさんに怒られてしましました。
この問題を回避するために、/frontendディレクトリ直下のpackage.jsonファイルにproxyを設定します。
{
"name": "frontend",
"version": "0.1.0",
"private": true,
"proxy": "http://localhost:3001",
//以下略
proxyを設定したので、App.jsのfetchメソッドで指定しているURLもhttp:localhost:3001/api
から/api
に変更します。
useEffect(() => {
fetch('/api')
.then((res) => res.json())
.then((data) => setMessage(data.message));
},[])
再度ブラウザを読み込むと、「フロントエンド」の下に「Hello World」の文字が表示されているはずです。
※表示されない場合はReactサーバーを再起動(CTRL+C
で停止、npm run start
で起動)してみてください。
変更前、すなわちproxyを設定しない場合、ブラウザはApp.jsを読み込むと直接localhost:3001/api
へfetchしようとします。(実際fetch('http:localhost/api')
というコードを書いていた)
変更後、すなわちproxyを設定した場合、ブラウザはApp.jsを読み込むとlocalhost:3000/api
へfetchし、それを受け取ったlocalhost:3000/api
は、さらにlocalhost:30001/api
へfetchします。(fetch('http:localhost:3001/api')
をfetch('/api')
に変更したのは、ブラウザをlocalhost:3000/api
に誘導するため)
要するに、バックエンド(localhost:3001/api
)に直接アクセスせず、proxy(localhost:3000/api
)を中継することで、CORSを回避したというわけです。
CORSはブラウザレベルのセキュリティ機能であるため、ブラウザの外でどのようなデータ転送が行われても規制することはできません。
バックエンドとデータベースを接続(Node.js+MySQL)
続いてはバックエンド(express)からデータベース(MySQL)にアクセスして、データを取得・操作できるようにしていきます。
Node.jsからMySQLのデータを操作するには、専用のパッケージが必要になります。今回は最も有名な「mysql2」を利用します。
まずは、ターミナルにてmemo-appディレクトリに移動して、次のコマンドを実行します。
npm install mysql2
mysql2のインストールが終わったら、MySQLに接続できるようにbackendディレクトリのindex.jsファイルを次のように書き換えます。
const express = require('express');
//mysql2の読み込む
const mysql = require('mysql2');
const app = express();
const port = 3001;
//mysqlと接続するための設定
const connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'password',
database: 'memo_app'
});
app.get('/', (req,res) => {
res.send('Hello World');
})
app.get('/api', (req, res) => {
// /apiにアクセスした際に、MySQLに対して行う処理
connection.query(
//usersテーブルからデータを取得する処理
'SELECT * FROM users',
function(err, results, fields){
if(err){
console.log('接続エラー');
throw err;
}
res.json({message: results[0].name});
}
)
});
app.listen(port, () => {
console.log(`listening on *:${port}`);
})
「mysqlと接続するための設定」におけるpasswordは、前頁の「4.MySQLを導入する」にてご自身が設定したものと適宜置き換えてください。
以上で接続作業は完了です。http://localhost:3001/api
にアクセスすると、取得したデータが表示されるはずです。
フロントとバックとデータベースを接続(React+Node.js+MySQL)
続いては、フロントエンド(React)とバックエンド(express)とデータベース(MySQL)の接続確認を行います。
とはいえ特にやることはなく、http://localhost:3000
にアクセスして、「フロントエンド」の下にデータベースから取得したデータが表示されていれば完了です。
これで、データベースに保存されているデータを、バックエンドを介してフロントエンドから取得・表示することが出来ました!
小まとめ
以上でフロント(React)とバック(express)とデータベース(MySQL)の接続確認は完了です。
最後のページでは、簡易UIの作成と検索機能の実装を行います。