Express.js の使い方【1】セットアップからルーティング

express2-2.png

第1回

1 Expressとは
2 セットアップ
3 Expressの構造
4 ルーティング

第2回

5 データベース

第3回

6 MVCアーキテクチャー

— 以降は準備中です —
第4回以降

7 Request、Response オブジェクト
8 Vue.jsと連携
9 cookie
10 session
11 環境変数の利用
12 エラーハンドリング
13 セキュリティ
14 HTTPS
15 プロセスマネージャー (PM2)

1. Expressとは

ExpressはNode.js上で稼働するサーバーサイドのWEBアプリケーションフレームワークです。公式サイトの言葉を借りると、ExpressはFast(高速)で、Unopinionated(自説に固執しない)で、Minimalist(ミニマリスト)な、Node.js用Webフレームワークです。

Screen Shot 2019-06-20 at 22.09.17.png
https://expressjs.com/

この言葉にあるように、ExpressはNodeの特徴でもある高速性を重視しているため、Express本体は最小限で最軽量な構成になっています。ORM(DBのインターフェース)もなければ、テンプレートエンジンもない状態です。これらの機能に関しては必要に応じてパッケージを加えていくことになりますが、「どのような構成がよいか?」ということに関してExpressのスタンスはUnopinionatedなので、そこはプログラマの意思に委ねられているというわけです。このようなExpressの設計思想は、下図のようにRuby on RailsやLaravelと比較すると解りやすいかもしれません。

Screen Shot 2019-06-20 at 23.12.16.png

2018年にNode.js Foundationが行ったユーザー調査「2018 Node.js User Survey Report」では、Expressが人気フレームワークの1位になっています。

Screen Shot 2019-06-24 at 17.24.50.png

https://nodejs.org/en/user-survey-report#Tools-Technologies-Used

1.1 Express ジェネレータとは

express-generatorはアプリケーション・スケルトンを作成するためのツールです。スケルトンは、他のフレームワークではScaffold(足場)とよばれることもあります。
express-generatorは、npm パッケージとしてExpress本体とは別にインストールします。

1.2 今回作成するもの

第1回〜3回のレッスンでは、Expressジェネレータを使ったWEBアプリの実装方法をざっくり把握することを目的とし、「データベースに保存されたユーザーのリストを画面に表示する」という機能を作成します。この機能に特に実用性はありませんが、以下のようなポイントを把握できると思います。

  • express-generator (スケルトン生成)
  • ルーティング
  • MVC (Model View Controller)
  • ORM (Object-Rerational Mapping)
  • RDB (Rerational Database)
  • テンプレートエンジン

2 セットアップ

ExpressのHello Worldには2段階あります。

1つ目は、Express ジェネレータを使わないで素のExpressだけで表示するHello Worldです。この実装方法に関しては、公式ページに解りやすいマニュアルがありまし、スキップすることもできるので、ここでは特に触れないことにします。
https://expressjs.com/ja/starter/installing.html
https://expressjs.com/ja/starter/hello-world.html

2つ目は、Express ジェネレータでスケルトンを作成して表示するHello Worldです。
今回はここから進めていきます。

2.1 Express ジェネレータをインストールする

nodeはインストール済みという前提で、Expressジェネレータのインストールから始めます。以下のコマンドを実行してexpress-generatorをインストールします。

1
$ npm install express-generator -g

インストールが成功したことを確認するために、ヘルプ情報を表示してみます。

1
$ express -h

ヘルプ情報が表示されれば成功です。

2.2 スケルトンを生成

それではスケルトンを作成します。(スケルトンはScaffold(足場)と呼ばれることもあります。)スケルトンの作成にはexpressコマンドを使います。コマンドの引数に、テンプレートエンジンの種類と、アプリケーション名を指定します。

1
$ express --view=[テンプレートエンジンの種類] [アプリケーション名]

今回はテンプレートエンジンにEJSを使うことにし、アプリケーション名を「myapp」にします。

1
$ express --view=ejs myapp

コマンドを実行すると、下図のようなスケルトンが生成されます。

スクリーンショット 2019-06-11 19.40.57.png

モジュールの依存情報がpackage.jsonに定義されていますので、モジュールをインストールしましょう。

2.3 Nodeモジュールをインストールする

次のコマンドを実行してモジュールをインストールします。

1
2
$ cd myapp
$ npm install

コマンドを実行するとnode_modulesディレクトリにモジュールがインストールされ、以下のようなフォルダ構成になります。

スクリーンショット 2019-06-11 19.44.55.png

2.4 アプリを起動してみる

1
$ npm start

ブラウザで以下のURLを開いてみましょう。

http://localhost:3000/

ExpressのWelcome画面が表示されれば成功です。

Screen Shot 2019-06-21 at 15.13.23.png

スケルトンにはもうひとつ/users/というページが存在しています。この後のレッスンで使いますので、以下のURLも開いてみましょう。

http://localhost:3000/users/

respond with a resourceという文字が表示されれば成功です。

Screen Shot 2019-06-25 at 12.01.50.png

確認ができたらCtrl+cで終了しておきましょう。

3. Expressの構造

3.1 スケルトンの初期状態

Expressジェネレータが生成したスケルトンは、下図のような構造で動作しています。

Screen Shot 2019-06-25 at 10.41.37.png
  • HTTPリクエストを3000番ポートでListenします。
  • HTTPリクエストの情報は、reqという名前のオブジェクトにセットされます。
  • ルーティング機能が、URLのパスに応じて、処理のルートを振り分けます。
  • TOPページの表示には、Viewエンジン(今回はEJS)が使われています。
  • 静的ファイルへのリクエストは、/publicフォルダにルーティングされます。
  • HTTPレスポンスは、resという名前のオブジェクトを使って返します。

この先は、このスケルトンを出発点として、いろいろな機能を肉付けしていくことになります。

3.2 アプリ起動からルーティングまでの流れ

アプリの起動からルーティング処理までの流れを見てみます。ターミナルから起動コマンド$ npm startを実行すると、package.jsonのstartに登録されているnode ./bin/wwwが実行されます。

1
2
3
4
5
...
"scripts": {
"start": "node ./bin/www"
},
...

/bin/wwwはHTTPサーバーを実行し、メインスクリプトのapp.jsと結びつけます。その後は、HTTPリクエストが発生する度に、URLのパスに対応したルーティングのハンドラが実行されます。

Screen Shot 2019-06-24 at 13.49.03.png

Expressでページを追加するときは、そのページのルーティングを設定し、ページの機能やビューと結びつけるといううことを行っていきます。

4. ルーティング

4.1 ルーティングとは

Expressアプリは、HTTPリクエストを受けとってレスポンスを返します。ルーティングとは、受け取ったURLのパスに対して、アプリでどんな処理をするのかという処理の流れを実装することです。例えば、エンドユーザーがアプリケーションに対して、http://localhost/users/というURLでアクセスしたとします。そのとき、/users/というパスに対してどのようなレスポンスを返すのか、アプリケーションで実装します。

Screen Shot 2019-06-21 at 7.26.23.png

Node.jsでWebアプリを作るのが初めての方にとっては、ルーティングを実装するという感覚が新鮮かもしれません。Node.js以外の言語を使う場合、ルーティング処理はApacheなどのWebサーバーが担当します。

Screen Shot 2019-06-21 at 7.40.26.png

また、Apacheなどの場合は、URLのパスとドキュメントルート以下の物理ファイルのパスは密接に関係していますが、Node.jsの場合は物理ファイルのパスを対応させることも、対応させないこともどちらも可能です。

Screen Shot 2019-06-21 at 8.14.54.png

Expressジェネレータが生成するスケルトンでは、静的なファイルに関してはpublicフォルダ以下に対応付けされており、プログラマが意識しなくても自動的にルーティングされます。動的な処理をするパスに関しては、プログラマがコードでルーティング処理を実装します。動的なルーティングの実装は、主にroutesディレクトリ以下に配置していきます。

Screen Shot 2019-06-21 at 8.58.28.png

4.2 静的ページのルーティング

静的ファイルに関しては/public/フォルダに割り当てられていますので、ここに簡単なHTMLページを配置してみます。ファイル名をhello.htmlとします。

Screen Shot 2019-06-26 at 8.59.36.png

1
2
3
4
5
6
7
8
9
<!DOCTYPE html>
<html>
<head>
<title>Hello</title>
</head>
<body>
<h2>Hello!</h2>
</body>
</html>

アプリを起動して表示してみます。

1
$ npm start

ブラウザで以下のURLを開きます。

http://localhost:3000/hello.html

Hello!が表示されれば成功です。

Ctrl+cでアプリを終了します。

Screen Shot 2019-06-26 at 9.10.17.png

4.2 ルーティングを実装する

それでは動的なページに関して、実際にどのようにルーティングを実装するのか見ていきましょう。ルーティングは、URLのパスに対するハンドラfunctionという形で実装します。例えば http://localhost/users/ というURLに対するルーティングは、/users/ というパスと、それに対応するハンドラ function を対応させるように書きます。

スクリーンショット 2019-06-16 12.50.08.png

4.3 ルーティングの実装方法

ルーティングの定義

1
app.METHOD(PATH, HANDLER)
  • app : express のインスタンス
  • METHOD : get/post など
  • PATH : URLのパス部分
  • HANDLER : パスが一致したときに実行されるfunction

ルーティングの実装方法には、app.jsに直接書く方法と、モジュール化する方法の2種類あります。

(1) app.jsに直接書く方法
1
2
3
4
5
6
var express = require('express');
var app = express();
....
app.get('/', function (req, res) {
res.send('Hello World!');
});

このようにapp.jsに直接ルーティングを書くことができるのですが、ルーティングが増えるにしたがって、app.jsのコードが肥大化してしまうという問題が起こります。そこで、次のようにルーティング機能をモジュール化する方法がサポートされています。

(2) モジュール化する方法

Express Routerという機能を使ってハンドラの部分を別ファイルに切り出すことができます。

Screen Shot 2019-06-21 at 12.51.37.png

Expressジェネレータが生成したスケルトンには、./routes/user.jsというファイルがあり、このような内容になっています。

1
2
3
4
5
6
7
8
9
var express = require('express');
var router = express.Router();

/* GET users listing. */
router.get('/', function(req, res, next) {
res.send('respond with a resource');
});

module.exports = router;

app.js側では、外出しにしたルータモジュール(users.js)をrequireしておき、リクエストURLの’/user’というパスに対応づけられています。

1
2
3
var usersRouter = require('./routes/users');
//...
app.use('/users', usersRouter);

4.4 ルーティングを追加してみる

./routes/user.jsを編集して、次のようなURLに対するルーティングを追加してみましょう。

http://localhost/users/123

Expressは、URLのパス部分のマッチング処理にPath-to-RegExpを使っており、ルーティングに正規表現を使うことができます。

Screen Shot 2019-06-25 at 12.22.26.png

https://www.npmjs.com/package/path-to-regexp

パターン マッチング例
‘/ab+cd’ abcd、abbcd、abbbcd など
‘/ab*cd’ abcd、abxcd、abRABDOMcd、ab123cd など
/a/ ルート名に「a」が含まれるすべてのもの
/.*fly$/ butterfly、 dragonflyなど

また、URL中の可変パラメータは、コロン記号を使って”/:userId”のように定義できます。

1
/:userId

捕捉された値はreq.paramsオブジェクトにセットされます。

1
req.params: { "userId": "123" }

それでは、./router/user.jsを開いて以下のようなハンドラを追加してみます。

1
2
3
4
5
6
7
8
//
// ユーザーIDを指定できるルート
//
router.get('/:userId', function(req, res, next) {
var userId = req.params.userId; // パラメータの値を取得
console.log('ユーザーID '+userId+ ' が指定されました。'); // ログで確認
res.send('ok'); // 必ず何らかのResponseを返す必要がある
});

このコードを、./router/user.jsに追加すると、user.js全体は以下のようになります。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var express = require('express');
var router = express.Router();

/* GET users listing. */
router.get('/', function(req, res, next) {
res.send('respond with a resource');
});

//
// ユーザーIDを指定できるルート
//
router.get('/:userId', function(req, res, next) {
var userId = req.params.userId; // パラメータの値を取得
console.log('ユーザーID '+userId+ ' が指定されました。'); // ログで確認
res.send('ok'); // 必ず何らかのResponseを返す必要がある
});

module.exports = router;
4.5 アプリを起動して確認する
1
$ npm start

プラウザで以下のURLにアクセスしてみましょう。

http://localhost:3000/users/123

okと表示されれば成功です。

Screen Shot 2019-06-21 at 15.21.52.png

また、アプリの起動コマンド$ npm startを実行したターミナルで、「ユーザーID123が指定されました」が表示されていれば、パラメータが正しく渡っています。

Screen Shot 2019-06-21 at 15.22.05.png

以上でチュートリアルの第1回は終わりです。

第1回のまとめ

インストールから起動までのコマンド

1
2
3
4
5
$ npm install express-generator -g
$ express --view=ejs myapp
$ cd myapp
$ npm install
$ npm start

確認URL

http://localhost:3000/

ルーティングを追加

1
2
3
4
5
router.get('/:userId', function(req, res, next) {
var userId = req.params.userId; // パラメータの値を取得
console.log('ユーザーID '+userId+ ' が指定されました。'); // ログで確認
res.send('ok'); // 必ず何らかのResponseを返す必要がある
});

確認URL

http://localhost/users/123

第2回目はデータベース接続について学びます。

writer | 太田直毅
株式会社OTAシステム開発。フルスタックエンジニア。 仙台市生まれ。大学卒業後に米国系通信会社にエンジニアとして就職。 1998年に独立し、WEBアプリケーションの開発を中心に活動。2児の父。趣味は家族キャンプ。
この記事をシェアする