Node.js初心者が構築するはじめてのExpress httpサーバ

ExpressはNode.jsのWEBアプリケーションフレームワークでウェブアプリケーションやモバイルアプリケーションを構築するために必要となる機能を備えているため効率的にアプリケーションを構築することができます。
本文書では、Node.js初心者の方でもわかるようにExpressを使う人が知りたいであろう基本的な内容に絞って説明を行なっています。本文書ではExpressをWebサーバとして利用するための基本となる下記を学ぶことができます。
- Expressdサーバの初期設定
- htmlファイルの表示方法
- 画像ファイルの表示方法
- 入力フォームから送信されてくるデータの受け取り方法
動作確認は、macOS環境で行なっており、Node.jsを事前にインストールしておく必要があります。Node.jsのインストール方法は下記を参考に行なってください。
目次
Expressのインストール
Expressを使って作成する任意の名前のフォルダの作成を行い、そのフォルダに移動します。ここではmyappという名前のフォルダを作成しています。
$ mkdir myapp
$ cd myapp/
Expressで使用するJavaScriptのライブラリ管理を行うためnpm initコマンドでpackage.jsonファイルの作成を行います。
$ npm init
npm init実行後、対話モードでいくつか質問をされますが、すべてEnterボタンを押してください。npm init -yコマンドを実行することた対話モードがスキップされるのでnpm init -yコマンドを実行しても構いません。
Press ^C at any time to quit.
package name: (myapp)
version: (1.0.0)
description:
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC)
npm initを実行フォルダにはpackage.jsonファイルが作成されます。

package.jsonファイルを作成したら、Expressのインストールを行います。npm installコマンドでexpressのインストールを行ってください。
$ npm install express --save
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN myapp@1.0.0 No description
npm WARN myapp@1.0.0 No repository field.
+ express@4.17.1
added 50 packages from 37 contributors and audited 126 packages in 6.607s
found 0 vulnerabilities

インストール完了後は、node_modulesフォルダとpackage-lock.jsonファイルが作成されます。ファイル構成は以下のようになります。
$ ls
node_modules package-lock.json package.json
Hello Worldをブラウザに表示
Expressのインストールが完了したので、Expressを使ってブラウザにHello Worldを表示させます。5行のコードでHello Worldを表示させることができます。
myappフォルダにindex.jsファイルを作成して以下のコードを記述します。
const express = require('express')
const app = express()
const port = 3000
app.get('/', (request, response) => response.send('Hello World!'))
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
JavaScriptのアロー関数に慣れていない人もいると思うので、アロー関数を使わない場合の記述も載せておきます。
app.get('/', function(request, response){
response.send('Hello World!')
}
app.listen(port, function(){
console.log(`Example app listening on port ${port}!`)
}
上記のコードは3つの部分に分割できるので各部分について説明を行なっていきます。
const express = require('express')
const app = express()
- Expressアプリケーションの作成
- ポートの設定
- ルーティングの設定
expressモジュールをrequireで読み込んでExpressアプリケーションを作成し変数appに設定を行っています。このappがExpressのコアになる部分で、appを通してさまざまな設定を行なっていきます。
const port = 3000
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
ブラウザからアクセスするためのポートを3000に設定し、そのポートをリスニングする設定を行なっています。ブラウザからアクセスする際はURLにhttp://localhost:3000を指定します。console.logの中身は後ほど説明するExpressサーバの起動時に実行したターミナルに表示されます。Expressにアクセスしてきたブラウザに表示されるものではありません。
app.get('/', (request, response) => response.send('Hello World!'))
上記ではルーティングの設定を行なっています。”/”ルートにアクセスが行われるとresponseのsendメソッドでHello World!を返します。requestはRequest(リクエスト)を表し、postリクエストなどの外側から入ってくるデータを保持しています。responseはResponse(レスポンス)を表しており、アクセスしてきたユーザに戻すデータ持っています。またgetはGETメソッドのことを表しています。つまり、ルート(/)にブラウザからアクセスがきたらHello Worldをブラウザに戻すことを意味します。
index.jsファイルを設定したらExpressサーバを起動する必要があります。起動のコマンドはnode index.jsです。index.jsファイルの中の設定でポート3000に設定しているのでブウラザからポート3000経由でExpressサーバにアクセスすることが可能になります。
$ node index.js
Example app listening on port 3000!
3000ポートでサーバが起動しているので、ブラウザでそのポートに対してアクセスを行うと画面にHello Worldが表示されます。

まだ”/”ルートしかルーティングの設定を行なっていないので、例えば”/”ルート以外の場所である/test等にアクセスを行うとブラウザ上にCannot GET /testとエラーメッセージが表示されます。メッセージの/testの部分はアクセスした場所によって変わります。

ルーティングの基本
ルーティングとは
例えば/userという場所(URL)をExpressの設定に追加した場合、ブラウザからGETやPOSTメソッドを使って/userにアクセスがあった場合にどのような処理やレスポンスを返すのかを決めるのがルーティングです。/userという一つの場所であってもメソッド毎に複数の処理を設定することができます。

/userにGETメソッド、POSTメソッドの異なる方法でリクエストがあった場合は下記のようにappのgetメソッドとpostメソッドを使い、ブラウザに返す値やサーバで実行する処理を変えることができます。
/userにGETメソッドでリクエストがあった場合はappのgetメソッドにURLと処理を記述します。
app.get('/user', function (request, response) {
response.send('Hello World!')
})
/userにPOSTメソッドのリクエストがあった場合はappのpostメソッドにURLと処理を記述します。
app.post('/user', function (request, response) {
response.send('Got a POST request')
})
ルーティングを追加
新たに”/”にPOSTメソッドがあった場合のルーティングを追加します。先ほど説明した通り、POSTメソッドの場合はapp.postメソッドを利用します。
app.get('/', (request, response) => response.send('Hello World!'))
app.post('/', (request, response) => response.send('Hello World! by Post Request'))

同じ”/”ルートにGETとPOSTの設定を行なっていますが、ブラウザから通常のアクセスを行うとGETメソッドでのアクセスになるので、Hello World!が表示されます。
通常のWEBサイトでは入力フォームから入力した値をサーバに対して送信する際にPOSTメソッドで”/”にアクセスしますが、Expressサーバでの入力フォームの作成方法は後ほど確認するので代わりにcurlコマンドを利用します。-XオプションにPOSTを指定することでPOSTメソッドでのcurlコマンドを利用してExpressサーバにアクセスを行うことができます。
$ curl -X POST http://localhost:3000
Hello World! by Post Request
curlコマンドをPOSTからGETに変更するとGETメソッドでアクセスすることができます。
curlでアクセスする場所が同じ”/”ルートでもルーティングの設定を適切に行えば、GETメソッドとPOSTメソッドで戻される値が変わることが確認できました。
追加でindex.jsにルーティングを増やすことでブラウザからアクセスできる場所を増やすことが可能です。ルーティング毎に異なる処理を設定することができるので、ルーティングを増やすことでサーバ側でアクセスした場所によって異なる処理を実行することが可能となります。
app.get('/user', (request, response) => response.send('Hello John Doe'))
上記のコードにindex.jsファイルに追加することでhttp://localhost:3000/userにアクセスすれば、Hello John Doeが表示されます。

curlコマンドを利用してPOSTメソッドを利用してJSONデータを一緒に送りたい場合は下記のように行うことができます。
curl -d '{"id":"aaa"}' -X POST http://localhost:3000/test --header 'content-type: application/json'
nodemonインストール
index.jsのファイルを書き換えるとこれまでは書き換える度にnode index.jsを再実行しなければ変更したファイルの内容は反映されませんでした。ファイルの変更を監視し自動でnode index.jsを再実行してくれるnodemonパッケージのインストールを行います。
npm installコマンドでnodemonのインストールを行います。
$ npm install nodemon
インストール後は、下記のnpxコマンドを利用してExpressサーバの起動を行います。
$ npx nodemon index.js
[nodemon] 1.19.1
[nodemon] to restart at any time, enter `rs`
[nodemon] watching: *.*
[nodemon] starting `node index.js`
Example app listening on port 3000!
index.jsファイルの更新があるとnodemonがファイルの更新を検知してくれるためnode index.jsコマンドの再実行を自動で行ってくれます。ターミナルにも再スタートのメッセージが表示されます。
[nodemon] restarting due to changes...
[nodemon] starting `node app.js`
Example app listening on port 3000!
HTMLファイルの中身を表示させたい
ルーティングの設定によりブラウザから/userにアクセスがあると文字列を返すことができました。
htmlタグで文字列を囲むと戻り値を受け取ったブラウザはHTMLタグを解釈してくれるためh1タグをつけると文字は大きく表示されます。
app.get('/user', (request, response) => response.send('<h1>Hello John Doe!</h1>'))

sendメソッド内にhtmlタグを付与することでブラウザ上で付与したタグが認識できることが確認できましたが、sendメソッドの中にhtml文をすべて記述するのは非効率なので新たにhtmlファイルを作成し、htmlファイルの内容を表示させる方法を確認していきます。
静的ファイルの保存場所の設定
静的ファイルを扱うためには、ミドルウェアのexpress.staticを下記のように設定する必要があります。publicは任意の名前をつけることができます。
app.use(express.static(path.join(__dirname, 'public')))
pathモジュールを利用するため、const path = require(‘path’)が必要になります。
const path = require('path')
__dirnameによりindex.js”ファイルが存在するフォルダのパスがわかります。path.joinで結合することでindex.js”ファイルが保存されているフォルダの下のpublicフォルダを設定しています。
myappフォルダの中にpublicフォルダを作成してtest.htmlファイルを作成します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Express.js</title>
</head>
<body>
<h1>Hello World</h1>
<p>Express.jsを使ってtest.htmlファイルを表示しています。</p>
</body>
</html>
ブラウザからhttp://localhost:3000/test.htmlファイルに直接アクセスすると下記の画面が表示されます。express.staticを利用することでpublic以下に保存した静的ファイルに直接アクセスできることがわかります。

画像の設定方法
publicフォルダにimgフォルダを作成し画像を保存します。このファイルにtest.htmlからアクセスできるか確認します。srcのパスはimg/express.pngとしています。
<body>
<h1>Hello World</h1>
<p>Express.jsを使ってtest.htmlファイルを表示しています。</p>
<img src="img/express.png">
</body>
express.staticでpublicを設定しているので、その下のフォルダへはpublic以下のパスを記述するだけでアクセスできることがわかります。

ルーティングを利用した表示方法
次にルーティングを利用してhtmlファイルをブラウザに表示させるため、sendFileメソッドを利用します。この場合は、ファイルのパスはpublicからの相対パスではなく絶対パスを設定します。
app.get('/test', (request, response) => response.sendFile(path.join(__dirname, 'public/test.html')))
http://localhost:3000/testにアクセスすると先程と同じ内容が表示されます。

先ほどはURLがtest.htmlになっていましたが、今回はURLが/testになっています。
設定したミドルウェアのexpress.staticをコメントアウトするとsendFileメソッドでhtmlファイルのtest.htmlを指定しているので、test.htmlの中身は表示されますが、画像へのパスが未設定となり、下記のように画像が表示されません。sendFileメソッドでファイルを指定する場合は画像のパス設定に注意が必要です。

入力フォームからデータ取得したい
htmlファイルの表示方法がわかったので、入力フォームを作成しExpress側でデータを取得する方法を確認します。
入力フォームからデータを取得する場合はexpress.json()かbody-parserを利用して行うことができます。
express.json()の利用
以前は入力フォームから送られてくるトデータを取得する際にはbody-parserをインストールする必要がありましたがExpressのバージョンが4の場合はbody-parserではなくexporess.json()を利用することができます。その場合は下記を設定してください。
app.use(express.json())
app.use(express.urlencoded({ extended: true }));
body-parserの利用
express.jsonではなくbody-parserを使った場合の入力フォームから送られてくるデータの取得方法を確認します。
body-parserをnpmコマンドでインストールします。
$ npm install body-parser
インストール完了後にindex.jsファイルでbody-parserをrequireします。
const bodyParser = require('body-parser');
送られてくるデータのContent-Typeがapplication/x-www-form-urlencodedの場合body-parserのurlencoded()メソッドを利用します。これらの設定により、送られてくるデータはreq.bodyに保存されます。

app.use(bodyParser.urlencoded({ extended: true }));

入力フォームの作成
入力フォームは/testにブラウザがアクセスがあった場合に返すtest.htmlファイルの中に記述します。
app.get('/test', (request, response) => response.sendFile(path.join(__dirname, 'public/test.html')))
test.htmlに入力フォームを追加し、送信ボタンを押すと/testに入力したデータをPOSTします。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Express.js</title>
</head>
<body>
<h1>入力フォーム</h1>
<form action="/test" method="POST">
<input type="text" name="name">
<button type="submit">送信</button>
</form>
</body>
</html>
入力データの取得
作成したフォームにユーザ名を入力して、送信ボタンを押します。サーバ側のPOSTメソッドに対するルーティングが設定されていないので、Cannot POST /testエラーが表示されます。

サーバ側でルーティングの追加を行います。入力フォームから送信されてくるデータはPOSTリクエストで送られてくるのでapp.postメソッドを利用します。
送信したデータはbody-parserまたはexpress.json()により、req.bodyの中に保存されるので、req.body.nameで入力した値を取り出します。受け取ったデータの内容を確認するためにsendメソッドでブラウザに戻します。
app.post('/test', (request, response) => response.send('送信したユーザ名は' + request.body.name))
入力フォームに入れて送信ボタンを押すとExpress側でPOSTデータを受け取りbody-parserまたはexpress.json()で受け取ったデータを扱える形に変換して、その結果がブラウザに表示されます。

express.json()またはbody-parserを利用することでPOSTで送られてきたデータをExpress.jsで取得できることが確認できました。
HTMLの表示方法と入力フォームでのデータの取得方法がわかったのでExpressのWEBサーバとしての基本設定を理解することができました。