ルーティング

ルーティングとは、アプリケーションのエンドポイント(URI)がクライアントリクエストにどのように応答するかを指します。ルーティングの概要については、基本的なルーティングを参照してください。

ルーティングは、HTTP メソッドに対応する Express app オブジェクトのメソッドを使用して定義します。たとえば、GET リクエストを処理するには app.get() を、POST リクエストを処理するには app.post を使用します。完全なリストについては、app.METHOD を参照してください。また、すべての HTTP メソッドを処理するには app.all() を、コールバック関数としてミドルウェアを指定するには app.use() を使用できます(詳細については、ミドルウェアの使用を参照してください)。

これらのルーティングメソッドは、アプリケーションが指定されたルート(エンドポイント)と HTTP メソッドへのリクエストを受信したときに呼び出されるコールバック関数(「ハンドラー関数」と呼ばれることもあります)を指定します。つまり、アプリケーションは、指定されたルートとメソッドに一致するリクエストを「リッスン」し、一致を検出すると、指定されたコールバック関数を呼び出します。

実際、ルーティングメソッドは、引数として複数のコールバック関数を持つことができます。複数のコールバック関数を使用する場合は、コールバック関数に引数として next を指定し、関数の本体内で next() を呼び出して、次のコールバックに関数を制御を渡すことが重要です。

次のコードは、非常に基本的なルートの例です。

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

// respond with "hello world" when a GET request is made to the homepage
app.get('/', (req, res) => {
  res.send('hello world')
})

ルートメソッド

ルートメソッドは、HTTP メソッドのいずれかから派生し、express クラスのインスタンスにアタッチされます。

次のコードは、アプリケーションのルートへの GET メソッドと POST メソッドに定義されたルートの例です。

// GET method route
app.get('/', (req, res) => {
  res.send('GET request to the homepage')
})

// POST method route
app.post('/', (req, res) => {
  res.send('POST request to the homepage')
})

Express は、すべての HTTP リクエストメソッドに対応するメソッドをサポートしています:getpost など。完全なリストについては、app.METHOD を参照してください。

特別なルーティングメソッドである app.all() は、すべての HTTP リクエストメソッドのパスにミドルウェア関数をロードするために使用されます。たとえば、次のハンドラーは、GET、POST、PUT、DELETE、または http モジュール でサポートされているその他の HTTP リクエストメソッドを使用するかどうかによらず、「/secret」ルートへのリクエストに対して実行されます。

app.all('/secret', (req, res, next) => {
  console.log('Accessing the secret section ...')
  next() // pass control to the next handler
})

ルートパス

ルートパスは、リクエストメソッドと組み合わせて、リクエストを行うことができるエンドポイントを定義します。ルートパスは、文字列、文字列パターン、または正規表現にすることができます。

文字 ?+*、および () は、それぞれの正規表現のサブセットです。ハイフン(-)とドット(.)は、文字列ベースのパスでは文字通りに解釈されます。

パス文字列でドル記号($)を使用する必要がある場合は、エスケープして ([]) で囲みます。たとえば、「/data/$book」へのリクエストのパス文字列は、「/data/([\$])book」になります。

Express は、ルートパスのマッチングに path-to-regexp を使用します。ルートパスの定義におけるすべての可能性については、path-to-regexp のドキュメントを参照してください。Express Route Tester は、基本的な Express ルートをテストするための便利なツールですが、パターンマッチングはサポートしていません。

クエリ文字列はルートパスの一部ではありません。

文字列に基づくルートパスの例を次に示します。

このルートパスは、ルートルート / へのリクエストに一致します。

app.get('/', (req, res) => {
  res.send('root')
})

このルートパスは、/about へのリクエストに一致します。

app.get('/about', (req, res) => {
  res.send('about')
})

このルートパスは、/random.text へのリクエストに一致します。

app.get('/random.text', (req, res) => {
  res.send('random.text')
})

文字列パターンに基づくルートパスの例を次に示します。

このルートパスは、acdabcd に一致します。

app.get('/ab?cd', (req, res) => {
  res.send('ab?cd')
})

このルートパスは、abcdabbcdabbbcd などに一致します。

app.get('/ab+cd', (req, res) => {
  res.send('ab+cd')
})

このルートパスは、abcdabxcdabRANDOMcdab123cd などに一致します。

app.get('/ab*cd', (req, res) => {
  res.send('ab*cd')
})

このルートパスは、/abe/abcde に一致します。

app.get('/ab(cd)?e', (req, res) => {
  res.send('ab(cd)?e')
})

正規表現に基づくルートパスの例

このルートパスは、「a」を含むすべてに一致します。

app.get(/a/, (req, res) => {
  res.send('/a/')
})

このルートパスは、butterflydragonfly に一致しますが、butterflymandragonflyman などには一致しません。

app.get(/.*fly$/, (req, res) => {
  res.send('/.*fly$/')
})

ルートパラメータ

ルートパラメータは、URL 内の位置で指定された値をキャプチャするために使用される名前付き URL セグメントです。キャプチャされた値は、req.params オブジェクトに入力され、パスで指定されたルートパラメータの名前がそれぞれのキーとして使用されます。

Route path: /users/:userId/books/:bookId
Request URL: https://127.0.0.1:3000/users/34/books/8989
req.params: { "userId": "34", "bookId": "8989" }

ルートパラメータを使用してルートを定義するには、以下に示すように、ルートのパスにルートパラメータを指定するだけです。

app.get('/users/:userId/books/:bookId', (req, res) => {
  res.send(req.params)
})

ルートパラメータの名前は、「単語文字」([A-Za-z0-9_]) で構成する必要があります。

ハイフン(-)とドット(.)は文字通りに解釈されるため、ルートパラメータと一緒に使用すると便利です。

Route path: /flights/:from-:to
Request URL: https://127.0.0.1:3000/flights/LAX-SFO
req.params: { "from": "LAX", "to": "SFO" }
Route path: /plantae/:genus.:species
Request URL: https://127.0.0.1:3000/plantae/Prunus.persica
req.params: { "genus": "Prunus", "species": "persica" }

ルートパラメータで一致させることができる正確な文字列をより詳細に制御するには、括弧(())内に正規表現を追加します。

Route path: /user/:userId(\d+)
Request URL: https://127.0.0.1:3000/user/42
req.params: {"userId": "42"}

正規表現は通常リテラル文字列の一部であるため、\ 文字は追加のバックスラッシュ(例:\\d+)でエスケープしてください。

Express 4.x では、正規表現の * 文字は通常の方法では解釈されません。回避策として、* の代わりに {0,} を使用してください。これは Express 5 で修正される可能性があります。

ルートハンドラ

リクエストを処理するために、ミドルウェアのように動作する複数のコールバック関数を指定できます。唯一の例外は、これらのコールバックが next('route') を呼び出して、残りのルートコールバックをバイパスする可能性があることです。このメカニズムを使用して、ルートに事前条件を課し、現在のルートを続行する理由がない場合は、後続のルートに制御を渡すことができます。

ルートハンドラは、次の例に示すように、関数、関数の配列、またはその両方の組み合わせの形式にすることができます。

単一のコールバック関数は、ルートを処理できます。例えば

app.get('/example/a', (req, res) => {
  res.send('Hello from A!')
})

複数のコールバック関数は、ルートを処理できます(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!')
})

コールバック関数の配列は、ルートを処理できます。例えば

const cb0 = function (req, res, next) {
  console.log('CB0')
  next()
}

const cb1 = function (req, res, next) {
  console.log('CB1')
  next()
}

const cb2 = function (req, res) {
  res.send('Hello from C!')
}

app.get('/example/c', [cb0, cb1, cb2])

独立した関数と関数の配列の組み合わせは、ルートを処理できます。例えば

const cb0 = function (req, res, next) {
  console.log('CB0')
  next()
}

const cb1 = function (req, res, next) {
  console.log('CB1')
  next()
}

app.get('/example/d', [cb0, cb1], (req, res, next) => {
  console.log('the response will be sent by the next function ...')
  next()
}, (req, res) => {
  res.send('Hello from D!')
})

レスポンスメソッド

次の表のレスポンスオブジェクト(res)のメソッドは、クライアントにレスポンスを送信し、リクエスト-レスポンスサイクルを終了できます。これらのメソッドがいずれもルートハンドラから呼び出されない場合、クライアントリクエストはハングしたままになります。

メソッド 説明
res.download() ファイルをダウンロードするように促します。
res.end() レスポンスプロセスを終了します。
res.json() JSON レスポンスを送信します。
res.jsonp() JSONP サポート付きの JSON レスポンスを送信します。
res.redirect() リクエストをリダイレクトします。
res.render() ビュテンプレートをレンダリングします。
res.send() さまざまなタイプのレスポンスを送信します。
res.sendFile() ファイルをオクテットストリームとして送信します。
res.sendStatus() レスポンスステータスコードを設定し、その文字列表現をレスポンス本文として送信します。

app.route()

app.route() を使用して、ルートパスにチェーン可能なルートハンドラを作成できます。パスは単一の場所で指定されるため、モジュラールートの作成に役立ち、冗長性とタイプミスを減らすことができます。ルートの詳細については、Router() ドキュメントを参照してください。

app.route() を使用して定義されたチェーンルートハンドラの例を次に示します。

app.route('/book')
  .get((req, res) => {
    res.send('Get a random book')
  })
  .post((req, res) => {
    res.send('Add a book')
  })
  .put((req, res) => {
    res.send('Update the book')
  })

express.Router

express.Router クラスを使用して、モジュール化可能でマウント可能なルートハンドラを作成します。Router インスタンスは、完全なミドルウェアおよびルーティングシステムです。このため、しばしば「ミニアプリ」と呼ばれます。

次の例では、モジュールとしてルーターを作成し、その中にミドルウェア関数をロードし、いくつかのルートを定義し、メインアプリのパスにルーターモジュールをマウントします。

アプリディレクトリに birds.js という名前のルーターファイルを作成し、次の内容を追加します。

const express = require('express')
const router = express.Router()

// middleware that is specific to this router
const timeLog = (req, res, next) => {
  console.log('Time: ', Date.now())
  next()
}
router.use(timeLog)

// define the home page route
router.get('/', (req, res) => {
  res.send('Birds home page')
})
// define the about route
router.get('/about', (req, res) => {
  res.send('About birds')
})

module.exports = router

次に、アプリにルーターモジュールをロードします。

const birds = require('./birds')

// ...

app.use('/birds', birds)

これで、アプリは /birds/birds/about へのリクエストを処理できるようになり、ルートに固有の timeLog ミドルウェア関数を呼び出すこともできます。