いまさらながら Express 入門
こいつを調べようと思って、
Express ベースらしいので、最初はそっちから戯れる。
Hello Express!
$ mkdir hello_express $ cd hello_express $ npm init $ npm install express --save
$ cat app.js const express = require('express') const app = express() app.get('/', (req, res) => { res.send('Hello World!') }) app.listen(3000, () => { console.log('Example app listening on port 3000!') })
req
と res
は Node 標準 API の HTTP のやつと同じ。
$ node app.js
$ curl http://localhost:3000/
Routing 基本
基本形。
app.METHOD(PATH, HANDLER)
GETとPOSTのルーティング。
app.get('/', (req, res) => { res.send('Hello World!') }) app.post('/', (req, res) => { res.send('Got a POST request') })
Static ファイルの配信
ビルドインの express.static
middleware を使う。
app.use(express.static('public'))
特定URLでマッピングするなら、 app.use()
の第1引数にパスを指定する。
app.use('/static', express.static('public'))
ファイルの探索はプログラム起動したディレクトリからの相対パスなので、絶対パスで指定するのがよい。
app.use('/static', express.static(path.join(__dirname, 'public')))
404 のハンドリング方法
全ての middleware と route を実行した結果、どれもレスポンスを返せなかった場合に 404 となる。なので一番最後に以下 middleware を定義すればよい。
app.use((req, res, next) => { res.status(404).send("Sorry can't find that!") })
エラーハンドリング
引数4つの middleware でエラーハンドリングとなる。
app.use((err, req, res, next) => { console.error(err.stack) res.status(500).send('Something broke!') })
Routing
この基本形。
app.METHOD(PATH, HANDLER)
METHOD
は HTTP メソッドと対応してて、めっちゃ定義されている。
get, post, put, head, delete, options, trace, copy, lock, mkcol, move, purge, propfind, proppatch, unlock, report, mkactivity, checkout, merge, m-search, notify, subscribe, unsubscribe, patch, search, and connect
app.all()
という HTTP メソッドと対応していないやつがあり、HTTP メソッド関係ない。特定パスに対してのみ middleware を使うのに等しいのかな。
app.all('/secret', (req, res, next) => { console.log('Accessing the secret section ...') next() // pass control to the next handler })
PATH
にはパターンや正規表現が使える。 ?
, +
, *
, (
, )
はパターンで処理される。
app.get('/ab?cd', (req, res) => {}) // `/abcd`, `/acd` app.get('/ab+cd', (req, res) => {}) // `/abcd`, `/abbcd`, `/abbbcd` app.get('/ab*cd', (req, res) => {}) // `/abcd`, `/abxcd`, `/abRANDOMcd`, `/ab123cd` app.get('/ab(cd)?e', (req, res) => {}) // `/abe`, `/abcde` app.get('/ab(cd)?e', (req, res) => {}) // `/abe`, `/abcde` app.get(/a/, (req, res) => {}) // `a` 含むもの全て
:
でURLの部分文字列がパラメータにマッピングされる。
app.get('/users/:userId/books/:bookId', (req, res) => { console.log(req.params) // /users/1/books/23:title] => { userId: '1', bookId: '23' } })
-
, .
はその文字のまま取り扱われる。なので、以下定義ではそれぞれ from
, to
および genus
, species
がキャプチャ対象。
/flights/:from-:to /plantae/:genus.:species
HANDLER
は複数指定できる。next()
を呼ばないと次のハンドラには行かない。
app.get('/example/b', (req, res, next) => { console.log('the response will be sent by the next function ...') next() }, (req, res) => { res.send('Hello from B!') })
Arrayでもよい。
app.get('/example/c', [cb0, cb1, cb2])
express.Router
というやつを使うと、いくつかの route や middleware 利用をまとめてモジュールとできる。
var express = require('express') var router = express.Router() // middleware that is specific to this router router.use(function timeLog (req, res, next) { console.log('Time: ', Date.now()) next() }) // define the home page route router.get('/', function (req, res) { res.send('Birds home page') }) // define the about route router.get('/about', function (req, res) { res.send('About birds') }) module.exports = router
var birds = require('./birds') app.use('/birds', birds)
middleware と route の実行順
定義した順。next()
を呼ぶ限り、次の middleware or route が実行される。
next
仮引数
次の middleware 関数ってことらしい。
next('route')
とすると、次の middleware へ飛ぶ(stack を辿らない)。以下は 1-1
と 2
が出力される。
app.get('/', [ (req, res, next) => { console.log('1-1') next('route') }, (req, res) => { console.log('1-2') } ]) app.get('/', (req, res) => { console.log('2') })
テンプレートエンジン
テンプレートエンジンは I/F が準拠してるものは全て使える。
app.set('views', './views')
でテンプレートファイルがあるディレクトリを指定するapp.set('view engine', 'pug')
でテンプレートエンジンを指定する
上記が設定されていれば、 res.render()
を呼び出しすればよい。
res.render('index', { title: 'Hey', message: 'Hello there!' })
エラーハンドラする middleware を複数
app.use(logErrors) app.use(clientErrorHandler) app.use(errorHandler)
logErrors では next(err)
として、次のエラーハンドラに err
オブジェクトを渡してあげる必要がある。つまり next()
に引数を渡すと次のエラーハンドラが実行されるってことらしい。
function logErrors (err, req, res, next) { console.error(err.stack) next(err) }
デバッグ
環境変数で出力有無を制御できる。
$ DEBUG=express:* node index.js
値の指定方法は debug モジュールってやつを利用してて、名前空間的なアプローチっぽい。
app.set()
設定値的なやつを設定すると middleware をまたいで値の共有ができる。