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ファイルが作成されます。

npm init -yコマンドとnpm initの対話モードでEnterのみを押した場合に作成される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
npm 5.0+だと–saveをつけなくてもpackage.jsonのdependenciesにパッケージ情報が追加されるので、–saveは必須ではありません。

インストール完了後は、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('/', (req, res) => res.send('Hello World!'))

app.listen(port, () => console.log(`Example app listening on port ${port}!`))

上記のコードは3つの部分に分割できるので各部分について説明を行なっていきます。

  1. Expressアプリケーションの作成
  2. ポートの設定
  3. ルーティングの設定

const express = require('express')
const app = 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('/', (req, res) => res.send('Hello World!'))

上記ではルーティングの設定を行なっています。”/”ルートにアクセスが行われるとres(response)のsendメソッドでHello World!を返します。req(request)はRequest(リクエスト)を表し、postリクエストなどの外側から入ってくるデータを保持しています。res(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が表示されます。Express.jsを利用するとこんなにお手軽にWEBサーバを立てることができます。

Hello Worldがブラウザに表示
Hello Worldがブラウザに表示

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

ポートの3000以外(localhost:4000)を設定するとエラーが表示されアクセスすことはできません。もし異なるポートでアクセスしたい場合は、index.jsのポート番号を別の番号に変更する必要があります。3000を利用するアプリケーションがすでに稼働している場合もExpressサーバは起動することができません。

ルーティングの基本

ルーティングとは

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

ブラウザからページの閲覧だけを行いたい場合はGETメソッドを使ってページのデータを取得します。POSTメソッドは入力フォームなどでユーザが入力したデータをサーバに渡す際に利用します。その他に削除を行いたい場合のDELETEメソッド、更新を行いたい場合のPUT, PATCHリクエストなどがあります。

/userにGETメソッド、POSTメソッドの異なる方法でリクエストがあった場合はExpressサーバ側で下記のようにappのgetメソッドとpostメソッドを使い、ブラウザに返す値やサーバで実行する処理を変えることができます。

/userにGETメソッドでリクエストがあった場合はappのgetメソッドにURLと処理を記述します。


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

/userにPOSTメソッドのリクエストがあった場合はappのpostメソッドにURLと処理を記述します。


app.post('/user', function (req, res) {
  res.send('Got a POST request')
})

ルーティングを追加

新たに”/”にPOSTメソッドがあった場合のルーティングを追加します。先ほど説明した通り、POSTメソッドの場合はapp.postメソッドを利用します。


app.get('/', (req, res) => res.send('Hello World!'))
app.post('/', (req, res) => res.send('Hello World! by Post Request'))
index.jsファイルの更新を行ってもExpressサーバは自動でindex.jsファイルの更新を反映してくれないため、node index.jsコマンドを停止して更新後node index.jsを実行する必要があります。この作業は非効率のため、ファイルの更新を監視するnodemonを後ほどインストールします。

同じ”/”ルートに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コマンドから-X POSTを削除するとGETメソッドでアクセスすることができます。


$ curl http://localhost:3000
Hello World!

GETメソッド、POSTメソッドで同じURLにアクセスしているのにも関わらずサーバから異なる返答があることがわかります。

curlでアクセスする場所が同じ”/”ルートでもルーティングの設定を適切に行うことでGETメソッドとPOSTメソッドで異なる処理をサーバ側で行うことができます。

追加でindex.jsにルーティングを増やすことでブラウザからアクセスできる場所を増やすことが可能です。ルーティング毎に異なる処理を設定することができるので、ルーティングを増やすことでサーバ側ではアクセスした場所によって異なる処理を実行することが可能となります。アプリケーションが大きなればなるほどルーティングが数は増えていきます。本文書ではルーティングの数が少ないのでindex.jsファイルにルーティングをすべて記述しますがルーティングが増えた場合また増えると想定される場合はindex.jsとは別にルーティング専用のファイルを作成することができます。1つのファイルではなく複数のファイルも作成可能です。


app.get('/user', (req, res) => res.send('Hello John Doe'))

上記のコードにindex.jsファイルに追加することでhttp://localhost:3000/userにアクセスすれば、Hello John Doeが表示されます。

ファイル更新後は忘れずにnode app.jsコマンドを再実行する必要があります。

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 --save-dev nodemon

インストール後は、下記のnpxコマンドとnodemonを利用してExpressサーバの起動を行います。


$ npx nodemon index.js
[nodemon] 2.0.8
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
[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', (req, res) => res.send('<h1>Hello John Doe!</h1>'))
h1タグで文字が大きくなった
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以下に保存した静的ファイルにブラウザから直接アクセスできることがわかります。

test.htmlファイルでHello World
test.htmlファイルでHello World

画像の設定方法

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以下のパスを記述するだけでアクセスできることがわかります。

test.htmlから画像を読み込む
test.htmlから画像を読み込む

ルーティングを利用した表示方法

次にルーティングを利用してhtmlファイルをブラウザに表示させるため、sendFileメソッドを利用します。この場合は、ファイルのパスはpublicからの相対パスではなく絶対パスを設定します。


app.get('/test', (req, res) => response.sendFile(path.join(__dirname, 'public/test.html')))

http://localhost:3000/testにアクセスすると先程と同じ内容が表示されます。

/testにアクセス
/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ではなくexpress.json()+exporess.urlencode()を利用することができます。その場合は下記を設定してください。


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に保存されます。

POSTリクエストを送る場合には2つの方法があり、x-www-form-urlencodedはサーバに対してテキストデータを送る際に使用されます。ファイルを送る場合には、multipart/form-dataが使用されます。後ほど確認するフォームではx-www-form-urlencodedで送信されてきます。

app.use(bodyParser.urlencoded({ extended: true }));
送られてくるContent-Typeを確認したい場合は、res.send(request.header(‘Content-Type’))で確認することができます。

入力フォームの作成

入力フォームは/testにブラウザがアクセスがあった場合に返すtest.htmlファイルの中に記述します。


app.get('/test', (req, res) => res.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.urlencoded()により、req.bodyの中に保存されるので、req.body.nameで入力した値を取り出します。受け取ったデータの内容を確認するためにsendメソッドでブラウザに戻します。


app.post('/test', (req, res) => res.send('送信したユーザ名は' + req.body.name))

入力フォームに入れて送信ボタンを押すとExpress側でPOSTデータを受け取りbody-parserまたはexpress.urlencoded()で受け取ったデータを扱える形に変換して、その結果がブラウザに表示されます。

入力した内容が戻される
入力した内容が戻される

express.urlencoded()またはbody-parserを利用することでPOSTで送られてきたデータをExpress.jsで取得できることが確認できました。送信されてくるデータはJSONではない場合はapp.use(express.json())は必要ありません。

HTMLの表示方法と入力フォームでのデータの取得方法がわかったのでExpressのWEBサーバとしての基本設定を理解することができました。

ミドルウェアの理解

Express.jsを使いこなすためにミドルウェアを理解しておく必要があります。ミドルウェアはクライアント(ブラウザ,API)からリクエストが送信されてきてからレスポンスを戻す前に実行される処理です。

以下の最もシンプルで簡単なミドルウェアを作成して”リクエストが送信されてきてからレスポンスを戻す前に実行される処理”という意味を確認しましょう。


app.use((req, res, next) => {
  console.log('1つ目のミドルウェアを通った?');
  next();
});

app.get('/', (req, res) => res.send('Hello World!'));

app.useの中にミドルウェアは記述することができます。ここではreq, res, nextの3つの引数をとります。nextはミドルウェアの処理が完了したら次のミドルウェアに処理が渡すために設定します。nextがないと次の処理に進まないのでルーティングの処理も行うことができません。ミドルウェアの中ではreq, resにアクセスすることも可能です。

実際に上記のコードを設定後ブラウザで/(ルート)にアクセスするとindex.jsを実行しているコンソールに”1つ目のミドルウェアを通った?”が表示されます。console.logでメッセージを表示するというだけのものですがリクエストとレスポンスの間で処理を実行しています。では次にapp.get(‘/’,…)の下に2つ目のミドルウェアを設定してみましょう。


app.use((req, res, next) => {
  console.log('1つ目のミドルウェアを通った?');
  next();
});

app.get('/', (req, res) => res.send('Hello World!'));

app.use((req, res, next) => {
  console.log('2つ目のミドルウェアを通った?');
  next();
});

この場合はapp.get(‘/’,…)の処理が実行されブラウザにレスポンスが戻ってしまっているので追加したミドルウェアが実行されることはありません。

シンプルな例ですが、ミドルウェアがリクエストが送信されてきてからレスポンスを戻す前に実行される処理”という意味を理解することができたのではないでしょうか。