Express.jsの基本的な使い方

2019/03/08更新

目次

概要

Node.jsにおけるウェブアプリケーションフレームワークのデファクトスタンダードであるExpress.jsの基本的な使用方法を簡単にまとめておく。

なお、Express.jsのバージョンは4.x系を想定している。

基本

Hello, world

Expressでアプリを作るための最低限のコードは以下の通り。

const app = require('express')();

// 「/」をリクエストされたら「Hello, world」を返す
app.get('/', (req, res) => {
    res.send('Hello, world');
});

// 8080ポートで待機する
app.listen(8080);

上記を「app.js」などとして保存し、node app.jsを実行して、http://localhost:8080/にアクセスすると、「Hello, world」が表示される。

環境変数

Node.jsでは、プログラム実行時の環境変数keyの値をprocess.env.keyで参照できる。Bash等のシェル上であれば、nodeコマンドの前にkey=valueを付けて実行することで、環境変数keyにvalueを割り当ててプログラムに渡すことができる。

特に、NODE_ENVという環境変数は、プログラムの実行環境を表すものとして「production」「staging」「development」「test」「local」などの値がよく指定される。Expressでは、app.get('env')process.env.NODE_ENVを参照できるが、NODE_ENVが未指定の場合は「development」が自動的に返る。

// 「NODE_ENV=production PORT=8080 node app.js」を実行した場合:
const app = require('express')();
console.log(app.get('env'));       // "production"
console.log(process.env.NODE_ENV); // "production"
console.log(process.env.PORT);     // "8080" ※全てStringとして渡されるので注意。

// 「node app.js」を実行した場合:
const app = require('express')();
console.log(app.get('env'));       // "development" ※NODE_ENV未指定なので「development」が返る。
console.log(process.env.NODE_ENV); // undefined

NODE_ENVの値をキーにしたJSONで環境ごとの設定を記述しておけば、自前の設定ファイルを簡単に作ることができる。

// ./config.jsonの内容:
// { "production" : { … }, "development": { … }, … }
const config = require('./config.json')[app.get('env')];

リクエストの受け付け

特定のパスに来たリクエストを処理するには、以下のように記述する。なお、レスポンスの仕方は後述する。

app.get('/hoge', (req, res) => {
    // 「/hoge」というパスに対するGETリクエストを処理
});

.get()以外に、POST、PUT、DELETEなどに対応した、.post().put().delete()などが使用できる。また、全てのメソッドを受け取る場合は、.all()を使う。パス部分は、定文字列の他、正規表現や配列も指定できる。

app.post(/^\/(?:hoge|fuga)/, (req, res) => {
    // 「/hoge」または「/fuga」で始まるPOSTリクエストを処理
});

引数のreqはリクエストに関する情報を持っている。プロトコル、ホスト名、IPアドレス、クッキー、HTTPヘッダなどを取得できる。

app.get('/hoge/fuga', (req, res) => {
    // 「http://localhost:8080/hoge/fuga」にリクエストした場合
    console.log(req.hostname);               // localhost
    console.log(req.path);                   // /hoge/fuga
    console.log(req.protocol);               // http
    console.log(req.headers['user-agent']);  // Mozilla/5.0 ~
      :
});

パラメーターの受け取り

パスとして:名前を指定すると、その部分をパラメーターとして受け取れる。

app.get('/:arg1/:arg2', (req, res) => {
    // 「/hoge/fuga」にリクエストした場合
    console.log(req.params.arg1);  // hoge
    console.log(req.params.arg2);  // fuga
      :
});

URLのクエリは、req.queryにオブジェクトとして格納される。

app.get('/', (req, res) => {
    // 「/?hoge=fuga%21」にリクエストした場合
    console.log(req.query.hoge);  // fuga!
      :
});

POST送信されたデータは、body-parserというモジュールを使って取得する。ただし、POST送信でもファイルアップロードの場合(multipart/form-data)は、別のmulterというモジュールを使う必要がある。

const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: true }));
app.post('/', (req, res) => {
    // 「hoge=fuga」をPOST送信した場合
    console.log(req.body.hoge);  // fuga
      :
});

レスポンスの出力

通常のレスポンスには、HTMLなどを返すres.send()、JSONデータを返すres.json()が使える。これらはリクエストごとに一度しか呼べない。

// HTMLを返す
app.get('/html', (req, res) => {
    // res.set(name, value)またはres.set({ name1: value1, ... })でHTTPヘッダを指定できる。
    // res.type('text/plain')でContent-typeを変更できる。
    res.send('<html><body><p>Hello, world</p></body></html>');
});

// JSONデータを返す
app.get('/json', (req, res) => {
    res.json({message: 'Hello, world'});
});

リダイレクトするには、res.redirect()を呼ぶ。

// 302リダイレクト
app.get('/', (req, res) => {
    res.redirect('http://example.com');
});

// 301リダイレクト
app.get('/', (req, res) => {
    res.redirect(301, 'http://example.com');
});

ステータスコードを返すには、res.status()を呼ぶ。

// 「404 Not Found」を返す
app.get('/', (req, res) => {
    res.status(404).end();
    // .end()をつけないとレスポンスが終わらないので注意。
    // .end()の代わりに.send(~)とすると、本文をつけて返すことができる。
    // res.sendStatus(404)とすると「Not Found」などの文字列を自動的に付けて返す。
});

応用

ミドルウェア

Expressでは、パスに応じた一つ一つの処理のことをミドルウェアと呼ぶ。

app.get('/', (req, res, next) => {
    // 1つ目のミドルウェアでの処理
    if (~) {
        // res.send()などでレスポンスを終了させることもできる。
        res.send('Canceled by the 1st middleware.');
    } else {
        // next()を呼ぶと、次のミドルウェアへ処理が引き継がれる。
        next();
    }
}, (req, res, next) => {
    // 2つ目のミドルウェアでの処理
      :
    next();
}, (req, res) => {
    // 最後のミドルウェアでの処理
      :
    res.send('Done.');
});

app.use()でパスごとに共通のミドルウェアを登録することができる。

// 「/」で始まるパスに共通するミドルウェアを登録(1つ目の引数が無い場合は、'/'を渡したのと同義)
app.use('/', (req, res, next) => {
    console.log('This is a message from middleware.');
    next();
}, (req, res, next) => {
    // コールバックを複数渡す、または、app.use()を複数回呼ぶことで、
    // 複数のミドルウェアを登録可能。登録した順に実行される。
      :
});

// 「/hoge」にアクセスすると、app.use()で登録したミドルウェアが実行されてから、
// app.get()のコールバックが実行される。
app.get('/hoge', (req, res) => {
    res.send('Done.');
});

app.use()を使うことで、パラメータチェック、ログインチェック、ロギングなど、全リクエストに対する共通の処理を行なわせることができる。

また、以下のようにエラーハンドリングのためのミドルウェアも設定できる。

app.use('/', (err, req, res, next) => {
    // 通常のミドルウェアと異なり、引数が4つあることに注意
    res.send(err);
});

app.get('/', (req, res, next) => {
    // next()に引数を渡すか、何かをthrowするとエラーハンドリングのミドルウェアへ処理が移る。
    if (~) {
        next('error');
    }
});

高度なルーティング

特定の文字列から始まるパスに対して一連の処理を設定したい場合などに、処理をまとめて記述する方法がある。

// 通常の書き方
app.get('/api/get', (req, res) => { … });
app.post('/api/update', (req, res) => { … });
  :

// Routerを用いた書き方
const router = express.Router();
router.get('/get', (req, res) => { … });
router.post('/update', (req, res) => { … });
  :
app.use('/api', router);

上記の例であれば、routerだけモジュールとして分割しておき、app.useで任意のパスにマウントする、という使い方が簡単にできる。

静的ファイル

通常のApacheサーバーのように、リクエストパスに応じた静的ファイルを返すには、staticミドルウェアを使う。

app.use('/static', express.static(path.join(__dirname, 'public')));
// 「/static」というパスで、「public」というディレクトリ以下の静的ファイルを返す。
// 「http://~/static/hoge/file.txt」で「public/hoge/file.txt」が返される。

Cookie

Cookieを取り扱うには、cookieParserミドルウェアを使う。

app.use(express.cookieParser());

app.get('/', (req, res) => {
    // Cookieの取得
    let myCookieValue = req.cookie.myCookie;
    // Cookieの設定
    res.cookie('myCookie', 'hoge', { maxAge: 864e5 });
      :
});

セッション

アクセスするユーザーごとにセッション情報を持たせるには、express-sessionというモジュールを使う。

const session = require('express-session');
app.use(session({
    secret: 'hogehoge',        // クッキー暗号化用のキー(任意の文字列)
    resave: true,              // セッションチェックのたびに新規セッションとするかどうか
    cookie: { maxAge: 864e5 }, // 有効期限
    saveUninitialized: true    // 未初期化状態のセッションを保存するかどうか
}));
app.get('/', (req, res) => {
    // req.session下にユーザーごとの任意の情報を保存・参照できるようになる。
    if (req.session.myInfo) {
        req.session.myInfo = 'hoge';
          :

テンプレートエンジンの使用

Expressでは、レスポンス返却時にEJSやJadeなどのテンプレートエンジンを使ってHTMLを生成できる。

例えば、EJSを使うには、まず以下のようなEJSテンプレート「index.ejs」を用意しておく。

<!doctype html>
<html>
  <head>
    <title><%= title %></title>
  </head>
  <body>
    <p><%= message %></p>
  </body>
</html>

これを以下のようにして利用することができる。

// テンプレートエンジンを指定
app.set('view engine', 'ejs');

app.get('/', (req, res) => {
    // renderメソッドでテンプレートにデータを渡す
    res.render('./index.ejs', {
        title: 'Sample title',
        message: 'Sample message'
    });
});

アクセスログ

アクセスログを取るには、morganというモジュールを使う。

const morgan = require('morgan');
app.use(morgan());

これだと、コンソールにログが出力される。フォーマットを変更したり、ファイルに出力したりと、様々な設定ができる。

関連記事