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());
これだと、コンソールにログが出力される。フォーマットを変更したり、ファイルに出力したりと、様々な設定ができる。