Fastify入門|ファクトリー

概要

Fastify は、Web アプリケーションを構築するための高速かつ効率的なフレームワークです。Fastify は、Node.js の EventEmitter パターンを採用し、各種機能をプラグインとして提供しています。Fastify のプラグインは、内部で使用することもでき、外部に公開することもできます。

Fastify には、サーバーを生成する Factory と呼ばれる機能があります。Factory を使用することで、より高度なカスタマイズが可能になります。

環境

Fastify v4.0.0
Node v19.7.0

使用例

Factory とは、Fastify インスタンスを生成するための関数です。Factory を使用することで、カスタムプラグインや設定を簡単に適用することができます。Factory は、次のようにして定義します。

const fastify = require("fastify")({
  logger: true,
});

fastify.get("/hello", function(request, reply) {
  request.log.info("Hello World!");
  reply.send("Hello World!");
});

const start = async () => {
  try {
    await fastify.listen(3000);
  } catch (err) {
    fastify.log.error(err);
    process.exit(1);
  }
};

start();

各種 Factory

Fastify には、以下のようなサーバーオプションがあります。

  • http
    Fastify では、http モジュールを使用して HTTP サーバーを作成することができます。
  • http2
    HTTP/2 プロトコルによる通信を実現するための機能が含まれているモジュールです。Fastify では、http2 モジュールを使用して HTTP/2 サーバーを作成することができます。
  • https
    SSL / TLS による暗号化通信を実現するための機能が含まれているモジュールです。Fastify では、https モジュールを使用して HTTPS サーバーを作成することができます。
  • connectionTimeout
    クライアントとの接続がタイムアウトするまでの時間をミリ秒単位で指定します。デフォルトは “5000” です。
  • keepAliveTimeout
    クライアントとの接続がアイドル状態であるときに、サーバーが接続を切断するまでの時間をミリ秒単位で指定します。デフォルトは “5000” です。
  • forceCloseConnections
    接続がアイドル状態になっているときに、接続を強制的に切断するかどうかを設定するためのオプションです。デフォルトでは、false に設定されており、接続を強制的に切断しません。
  • maxRequestsPerSocket
    1 つのソケットに対して処理することができるリクエストの最大数を設定するためのオプションです。デフォルトでは、null に設定されており、制限がありません。
  • requestTimeout
    リクエストに対する応答を待機するタイムアウト時間を設定するためのオプションです。指定した時間内に応答がない場合、タイムアウトエラーが発生します。
  • ignoreTrailingSlash
    パスの末尾にスラッシュが含まれている場合でも、ルーティングが正しく行われるようにします。デフォルトは false です。
  • ignoreDuplicateSlashes
    デフォルトでは、Fastify は URL 中の重複したスラッシュを無視しません。ignoreDuplicateSlashes オプションを true に設定することで、URL 中の重複したスラッシュを無視することができます。
  • maxParamLength
    パスパラメーターの最大長を指定できます。デフォルトでは 100 です。
  • bodyLimit
    リクエストボディの最大サイズを指定できます。デフォルトでは 1048576 (1 MB) です。
  • onProtoPoisoning
    プロトタイプ汚染攻撃に対する対策を行うことができます。
  • onConstructorPoisoning
    コンストラクタ汚染攻撃に対する対策を行うことができます。
  • logger: Fastify が内部的に使用している Pino というロガーライブラリを使用して、アプリケーションのログ出力を行うことができます。
  • disableRequestLogging
    リクエストログを無効にすることができます。
  • serverFactory
    Fastify が内部的に使用する http.Server のファクトリ関数を指定できます。
  • jsonShorthand
    JSON ショートハンド機能を有効にするかどうかを指定できます。デフォルトは true です。
  • caseSensitive
    URL の大文字と小文字を区別する場合は true、区別しない場合は false を設定します。デフォルトは false です。
  • allowUnsafeRegex
    パスパラメータにおいて、危険な正規表現を許可するかどうかを指定できます。デフォルトは false です。
  • requestIdHeader
    リクエスト ID を格納するヘッダー名を指定できます。デフォルトは “request-id” です。
  • requestIdLogLabel
    ログ出力時に使用されるリクエスト ID のラベルを指定できます。デフォルトは “reqId” です。
  • genReqId
    リクエスト ID を生成する関数を指定できます。
  • trustProxy
    プロキシサーバーからのリクエストを信頼するかどうかを指定できます。デフォルトは false です。
  • pluginTimeout
    プラグインが読み込まれるまでのタイムアウトを指定できます。デフォルトは 10000 (10 秒) です。
  • querystringParser
    Fastify は、クエリパラメータを自動的に解析する機能を持っています。デフォルトでは、クエリパラメータは JavaScript オブジェクトとして解析されます。querystringParser オプションを使用すると、このデフォルトの動作を変更することができます。たとえば、qs モジュールを使用してクエリパラメータを解析するように設定することができます。
  • exposeHeadRoutes
    有効にすると、Fastify は自動的にすべてのルートに HEAD メソッドを追加します。デフォルトでは、このオプションは無効になっています。
  • constraints
    ルートパラメーターのバリデーションを行うために使用されます。このオプションを使用すると、ルートに対するパラメータのデータ型、最小値、最大値などを指定することができます。これにより、アプリケーションがより強力なバリデーションを実行できます。
  • return503OnClosing
    アプリケーションのサーバーが終了する際に、リクエストに対する応答として 503 エラーを返すように設定できます。これにより、アプリケーションの終了中にリクエストが処理されずに失敗することを回避できます。
  • ajv
    JSON スキーマのバリデーションを行うことができます。ajv オプションを使用すると、Fastify はアプリケーションで使用する Ajv インスタンスを構成することができます。
  • serializerOpts
    Fastify のシリアライザの設定を変更することができます。このオプションを使用すると、Fastify がオブジェクトを JSON 形式に変換する方法をカスタマイズできます。
  • http2SessionTimeout
    Fastify は HTTP/2 セッションを使用して通信することができます。http2SessionTimeout オプションを使用すると、Fastify が HTTP/2 セッションを保持する時間を設定することができます。
  • frameworkErrors
    例外の種類を構成することができます。デフォルトでは、Fastify は Error クラスから派生する例外のみを処理します。このオプションを使用すると、Fastify が処理する例外の種類を追加できます。例えば、TypeError などの例外を追加できます。
  • clientErrorHandler
    すべてのエラーを処理するためのカスタムエラーハンドラーを指定することができます。このオプションを使用すると、Fastify のデフォルトのエラーハンドラーを上書きすることができます。
  • rewriteUrl
    受信したすべてのリクエストの URL を再書き込みするために使用されます。このオプションを使用すると、受信したリクエストの URL を変更して、Fastify が処理する前に必要な前処理を実行することができます。

http

Fastify の http ファクトリは、Node.js の標準モジュールである http モジュールを使用して HTTP サーバーを作成します。このファクトリを使用することで、Fastify で HTTP サーバーを作成することができます。

HTTP サーバーを作成する場合は、以下のように Fastify をインポートし、http ファクトリを使用して Fastify インスタンスを作成します。

const http = require('http')

const server = http.createServer((req, res) => {
  fastify(req, res)
})

server.listen(3000, (err, address) => {
  if (err) {
    fastify.log.error(err)
    process.exit(1)
  }
  fastify.log.info(`server listening on ${address}`)
})

Fastify インスタンスを HTTP サーバーにバインドするために、http.createServer()関数に渡されたコールバック関数内で、Fastify インスタンスを呼び出します。

http ファクトリを使用して Fastify インスタンスを作成する場合、http リクエストのパースには、Node.js の http モジュールによって提供されるデフォルトのパーサーが使用されます。これは、Fastify が提供する高速で柔軟なパーサーではありません。

ただし、http ファクトリは、http2 ファクトリや https ファクトリのような他のファクトリと同様に、Fastify が提供する高速で柔軟なパーサーを使用することができます。これにより、より高速で、柔軟性のある HTTP サーバーを構築することができます。

http2

Fastify では、HTTP2 プロトコルを使用するためのファクトリも提供されています。HTTP2 を使用すると、単一の TCP 接続上で複数の並列ストリームを扱うことができ、より高速で効率的な通信が可能になります。

HTTP2 ファクトリを作成するには、fastify オブジェクトの http2Server メソッドを呼び出します。

const fastify = require('fastify')();

const http2Opts = {
  key: fs.readFileSync('./ssl/key.pem'),
  cert: fs.readFileSync('./ssl/cert.pem')
};

fastify.http2Server(http2Opts, (req, res) => {
  res.end('Hello World!');
});

fastify.listen(3000, (err, address) => {
  if (err) {
    console.error(err);
    process.exit(1);
  }
  console.log(`Server listening at ${address}`);
});

上記の例では、http2Opts には必要な TLS 証明書情報を含めます。http2Server メソッドの第 1 引数には、TLS 証明書に関する情報を含むオブジェクトを渡します。第 2 引数には、リクエストに対するハンドラ関数を渡します。

Fastify は、HTTP2 ストリームのハンドリングに特化しているため、HTTP1.x のようなリクエストパース処理の必要がありません。そのため、HTTP2 ストリームを扱うことができる、効率的なウェブアプリケーションを構築することができます。

また、HTTP2 ファクトリは、HTTP1.x と同様に listen メソッドを使用してポートをバインドすることができます。例えば、上記の例では fastify.listen(3000)を呼び出しています。

https

Fastify には、HTTPS 通信を行うための https ファクトリーがあります。このファクトリーを使用すると、SSL/TLS 証明書の検証、サーバー認証、クライアント認証を行うことができます。

以下は、基本的な HTTPS サーバーを作成する例です。

const fs = require('fs')
const path = require('path')
const fastify = require('fastify')({
  https: {
    key: fs.readFileSync(path.join(__dirname, 'ssl', 'key.pem')),
    cert: fs.readFileSync(path.join(__dirname, 'ssl', 'cert.pem'))
  }
})

fastify.get('/', function (req, res) {
  res.send('Hello, HTTPS!')
})

fastify.listen(3000, function (err) {
  if (err) {
    console.log(err)
    process.exit(1)
  }
  console.log('Listening on port 3000.')
})

この例では、https オプションを使用して、サーバーの秘密鍵と証明書を設定しています。このファクトリーを使用することで、HTTPS プロトコルを使用して暗号化された通信を行うことができます。

サーバーの設定に加えて、クライアントに対してトラストされた証明書を提供する必要があります。そのためには、CA ルート証明書を使用することができます。https オプションの ca プロパティに CA ルート証明書を含めることができます。また、クライアント認証を有効化する場合は、requestCert プロパティを true に設定し、クライアント証明書を要求することができます。rejectUnauthorized プロパティを true に設定することで、サーバーがクライアント証明書を検証することもできます。

connectionTimeout

connectionTimeout オプションは、Fastify サーバーがクライアントの接続を待機するタイムアウト時間を設定します。つまり、Fastify サーバーがクライアントからリクエストを受け取った後、クライアントからの次のリクエストを待つタイムアウト時間を設定します。

デフォルトでは connectionTimeout オプションは無効になっています。connectionTimeout オプションを設定するには、Fastify インスタンスのオプションオブジェクトの中に connectionTimeout オプションを追加します。値はミリ秒単位で設定します。

以下は、5 秒間クライアントからの接続を待機する例です。

const fastify = require("fastify")({
  connectionTimeout: 5000,
});

fastify.get("/", function (request, reply) {
  reply.send("Hello World!");
});

const start = async () => {
  try {
    await fastify.listen(3000);
    console.log(`Fastify server running on port ${fastify.server.address().port}`);
  } catch (err) {
    console.error(err);
    process.exit(1);
  }
};

start();

以上のコードで Fastify サーバーは、クライアントからリクエストを受け取った後、5 秒間接続を待機します。5 秒以内に次のリクエストが来ない場合は、Fastify サーバーは接続を切断します。

keepAliveTimeout

keepAliveTimeout オプションは、HTTP Keep-Alive 接続のタイムアウト時間を設定します。HTTP Keep-Alive 接続は、同じクライアントからの複数のリクエストに対して、サーバーが接続を維持し続ける機能です。

keepAliveTimeout オプションは、ミリ秒単位で指定します。デフォルトでは、値は 5000 (5 秒) に設定されています。このオプションを調整することで、サーバーが Keep-Alive 接続を維持する時間を設定することができます。

以下は、keepAliveTimeout オプションを 30 秒に設定する例です。

const fastify = require('fastify')({
  keepAliveTimeout: 30000
})

fastify.get('/hello', function(request, reply) {
  reply.send('Hello World!')
})

const start = async () => {
  try {
    await fastify.listen(3000)
  } catch (err) {
    fastify.log.error(err)
    process.exit(1)
  }
}

start()

この例では、クライアントがリクエストを送信した後、30 秒以内に次のリクエストを送信しなかった場合、サーバーは Keep-Alive 接続を切断します。

forceCloseConnections

forceCloseConnections オプションは、Fastify インスタンスの接続が閉じられた後も、接続を閉じるためにソケットを強制的に閉じるかどうかを制御するためのオプションです。

デフォルトでは、Fastify はソケットを再利用するように設定されており、keep-alive ヘッダーを使用してソケットを維持します。ただし、一部のプロキシサーバーやリバースプロキシサーバーでは、接続が閉じられた後もソケットを開いたままにする場合があります。この場合、Fastify が再利用されるソケットを閉じないようにするには、forceCloseConnections オプションを使用します。

例えば、以下のように設定することができます。

const fastify = require('fastify')({
  logger: true,
  forceCloseConnections: true
});

fastify.get('/hello', function(request, reply) {
  reply.send('Hello World!')
})

const start = async () => {
  try {
    await fastify.listen(3000)
  } catch (err) {
    fastify.log.error(err)
    process.exit(1)
  }
}

start()

この場合、Fastify はソケットを再利用せず、接続が閉じられた後にソケットを閉じます。このオプションは、プロキシサーバーやリバースプロキシサーバーがソケットを保持しており、Fastify サーバーに対して接続が長時間維持される場合に役立ちます。ただし、forceCloseConnections オプションが有効になると、性能に悪影響を与える可能性があるため、注意が必要です。

maxRequestsPerSocket

maxRequestsPerSocket オプションは、単一の TCP ソケットで許容される最大リクエスト数を設定するための Fastify サーバーオプションです。

Fastify は、リクエストを処理するために単一の TCP コネクション(またはソケット)を使用します。 maxRequestsPerSocket オプションを使用すると、単一の TCP ソケットで許容される最大リクエスト数を制限することができます。デフォルトでは、Fastify は maxRequestsPerSocket を無制限に設定しています。

以下の例では、単一の TCP ソケットで許容される最大リクエスト数を 3 に設定しています。

const fastify = require('fastify')({
  maxRequestsPerSocket: 3
})

fastify.get('/hello', function(request, reply) {
  reply.send('Hello World!')
})

const start = async () => {
  try {
    await fastify.listen(3000)
  } catch (err) {
    fastify.log.error(err)
    process.exit(1)
  }
}

start()

このオプションを使用することで、サーバーのメモリ使用量を制限することができます。しかし、maxRequestsPerSocket を小さく設定しすぎると、Web サイトのパフォーマンスに影響を与える可能性があるため、適切なバランスを見つける必要があります。

requestTimeout

requestTimeout は、Fastify アプリケーションがリクエストを受け取ってから、リクエストの完了までの最大時間を設定するオプションです。つまり、リクエストが長時間実行されることを防ぎ、アプリケーションのパフォーマンスを維持することができます。

requestTimeout は、ミリ秒単位で設定されます。デフォルトの値は 0 で、タイムアウトが無効になっています。

const fastify = require("fastify")({
  logger: true,
  requestTimeout: 5000
});

fastify.addHook('onRequest', (req, res, done) => {
  res.once('timeout', () => {
    done(new Error('Request Timeout'))
  })
  done()
})

fastify.get('/test', (req, res) => {
  // some long running operation
})

fastify.listen(3000, (err, address) => {
  if (err) {
    fastify.log.error(err)
    process.exit(1)
  }
  console.log(`Server listening on ${address}`)
})

上記の例では、リクエストが受信された際に onRequest フックが呼び出され、res.once メソッドによって timeout イベントを監視しています。リクエストがタイムアウトすると、エラーが発生し、エラーメッセージを含むエラーオブジェクトが返されます。このエラーは、Fastify の log.error メソッドを使用してログ出力することができます。

ignoreTrailingSlash

ignoreTrailingSlash オプションは、URL の末尾にスラッシュがある場合とない場合を区別するかどうかを設定します。このオプションを true に設定すると、URL 末尾のスラッシュを無視してリクエストを処理するようになります。例えば、"/hello"と"/hello/“は同じ URL として扱われます。

ignoreTrailingSlash オプションを有効にすることで、リクエストの処理において、URL においてスラッシュの有無によるバグを回避することができます。ただし、このオプションを有効にした場合は、本来区別されるべき URL が同じとして扱われてしまうことがあるため、適切に利用する必要があります。

ignoreTrailingSlash オプションを true に設定することで、URL 末尾のスラッシュを無視することができます。以下は ignoreTrailingSlash オプションを有効化する例です。

const fastify = require("fastify")({
  logger: true,
  ignoreTrailingSlash: true,
});

fastify.get("/hello", function(request, reply) {
  reply.send("Hello World!");
});

const start = async () => {
  try {
    await fastify.listen(3000);
  } catch (err) {
    fastify.log.error(err);
    process.exit(1);
  }
};

start();

ignoreDuplicateSlashes

ignoreDuplicateSlashes オプションは、URL に含まれる重複したスラッシュを無視するかどうかを制御するための Fastify のサーバーオプションです。デフォルトでは、このオプションは無効になっています。

例えば、次のような URL がある場合、デフォルトでは Fastify は異なる URL として扱います。

http://example.com//path/to/resource
const fastify = require("fastify")({
  logger: true,
  ignoreDuplicateSlashes: true
});

fastify.get("/hello", function(request, reply) {
  reply.send("Hello World!");
});

const start = async () => {
  try {
    await fastify.listen(3000);
  } catch (err) {
    fastify.log.error(err);
    process.exit(1);
  }
};

start();

このオプションを有効にすることで、URL の見た目を統一し、システムの保守性を向上させることができます。ただし、URL の意味が変わってしまう可能性があるため、慎重に使用する必要があります。

maxParamLength

Fastify における maxParamLength オプションは、URL 内のパラメータ(プレースホルダー)の最大長を指定します。デフォルト値は 100 です。

const fastify = require("fastify")({
  logger: true,
  maxParamLength: 10
});

fastify.get("/hello", function(request, reply) {
  request.log.info("Hello World!");
  reply.send("Hello World!");
});

const start = async () => {
  try {
    await fastify.listen(3000);
  } catch (err) {
    fastify.log.error(err);
    process.exit(1);
  }
};

start();

このコードでは、Fastify インスタンスを作成し、maxParamLength オプションを設定しています。maxParamLength オプションは、URL のパスパラメーターの最大長を設定するために使用されます。デフォルトでは、最大長は 100 バイトですが、この例では 10 バイトに設定されています。

bodyLimit

デフォルトでは、Fastify はリクエストボディのサイズに上限を設けていません。しかし、不正なリクエストが送信された場合や、意図せず大量のデータが送信された場合に、アプリケーションがダウンしてしまう可能性があります。

bodyLimit オプションを設定することで、リクエストボディのサイズに上限を設けることができます。以下は bodyLimit オプションを有効化する例です。

const fastify = require("fastify")({
  logger: true,
  bodyLimit: 1024 * 1024 * 5, // 5 MB
});

fastify.post("/upload", function(request, reply) {
  // ファイルのアップロード処理
});

const start = async () => {
  try {
    await fastify.listen(3000);
  } catch (err) {
    fastify.log.error(err);
    process.exit(1);
  }
};

start();

上記の例では、bodyLimit を 5MB に設定しています。

また、Fastify はデフォルトで、10MB までのリクエストを受け付けるように設定されています。これは、大量の画像やビデオなど、大容量のファイルをアップロードする場合に有用です。ただし、安全上の理由から、サーバーのメモリが不足している場合は、リクエストを拒否することがあります。

onProtoPoisoning

onProtoPoisoning オプションは、Fastify が受信したリクエストのプロトタイプの変更を検出するための機能です。悪意のあるリクエストによって、オブジェクトのプロトタイプを変更され、セキュリティ上の問題を引き起こすことがあります。このオプションを true に設定することで、Fastify がプロトタイプ変更の検出を行い、エラーをスローしてリクエストを拒否することができます。

const fastify = require("fastify")({
  logger: true,
  onProtoPoisoning: 'error'
});

fastify.get("/hello", function(request, reply) {
  reply.send("Hello World!");
});

const start = async () => {
  try {
    await fastify.listen(3000);
  } catch (err) {
    fastify.log.error(err);
    process.exit(1);
  }
};

start();

onConstructorPoisoning

onConstructorPoisoning オプションは、オブジェクトを作成する際に悪意のあるコードが注入されるのを防ぐためのものです。このオプションを使用することで、Fastify はオブジェクトのコンストラクタを確認し、悪意のあるコードが注入されているかどうかを検出することができます。

オプションの値は、検出された場合に行うアクションを定義するコールバック関数です。デフォルトでは、Fastify はエラーをスローしてリクエストを終了します。オプションの使用例を以下に示します。

const fastify = require('fastify')({
  onConstructorPoisoning: 'log'
});

fastify.get('/', function (request, reply) {
  reply.send({ hello: 'world' });
});

const start = async () => {
  try {
    await fastify.listen(3000);
    fastify.log.info(`server listening on ${fastify.server.address().port}`);
  } catch (err) {
    fastify.log.error(err);
    process.exit(1);
  }
};
start();

この例では、コンストラクタの検出時にエラーをスローする代わりに、ログに警告を出力するように設定されています。onConstructorPoisoning オプションの値には、log 以外にも、ignore、remove、throw があります。

logger

logger オプションを true に設定することで、Fastify が内部的に使用している Pino というロガーライブラリを使用して、アプリケーションのログ出力を行うことができます。

const fastify = require("fastify")({
  logger: true,
});

fastify.get("/hello", function(request, reply) {
  request.log.info("Hello World!");
  reply.send("Hello World!");
});

const start = async () => {
  try {
    await fastify.listen(3000);
  } catch (err) {
    fastify.log.error(err);
    process.exit(1);
  }
};

start();

この例では、level オプションでログの詳細度を設定し、file オプションでログを出力するファイル名を指定しています。また、リクエストごとに異なるログを出力することも可能で、request.log を使用することでリクエストスコープのログを出力することができます。

以上のように、Fastify では logger オプションを使用することで簡単にログ出力を行うことができます。カスタムロガーを使用することもできるため、柔軟なログ出力が可能です。

disableRequestLogging

disableRequestLogging オプションは、リクエストログの出力を無効にするためのオプションです。これを true に設定すると、Fastify はリクエストに関するログを出力しなくなります。デフォルトは false であり、リクエストに関するログは出力されます。

例えば、以下のようにして disableRequestLogging オプションを設定することができます。

const fastify = require('fastify')({
  disableRequestLogging: true
})

fastify.get('/', function (req, reply) {
  reply.send({ hello: 'world' })
})

fastify.listen(3000, function (err) {
  if (err) {
    fastify.log.error(err)
    process.exit(1)
  }
})

この例では、disableRequestLogging オプションが true に設定されています。したがって、Fastify はリクエストログを出力しません。

serverFactory

serverFactory オプションは、Fastify インスタンスが利用するサーバーのファクトリ関数を指定するためのオプションです。このオプションを使用することで、Fastify は内部的に使用するサーバーをカスタマイズすることができます。

例えば、Node.js の標準的な HTTP サーバーではなく、Express や Koa などの別のサーバーライブラリを使用することができます。これにより、既存のアプリケーションを Fastify に移植する場合にも、既存のサーバーコードをそのまま利用することができます。 以下は、Express サーバーを使用する例です。

const fastify = require('fastify')({
  serverFactory: require('fastify-express')
})

また、serverFactory オプションは、クラスを指定することもできます。例えば、以下のように、HTTP2 サーバーを使用するための http2 モジュールの http2.createServer() メソッドを使用することができます。

const http2 = require('http2')
const server = http2.createServer()
const fastify = require('fastify')({
  serverFactory: () => server
})

Fastify は、 serverFactory オプションで指定されたサーバーファクトリ関数が必要とするオプションを自動的に設定します。ただし、オプションがサポートされていない場合は、Fastify はそのオプションを無視します。

jsonShorthand

jsonShorthand は、Fastify において JSON ショートハンドを有効または無効にするためのオプションです。JSON ショートハンドとは、JavaScript オブジェクトのプロパティの値を記述する際に、値が文字列である場合にダブルクォーテーションを省略する記述方法のことです。

const obj = {
  name: "Alice",
  age: 20,
  hobby: "reading",
};
const obj = {
  name: "Alice",
  age: 20,
  hobby: "reading"
};

caseSensitive

caseSensitive オプションは、URL の大文字と小文字を区別するかどうかを設定するためのオプションです。デフォルト値は false で、大文字小文字を区別しないように設定されています。

例えば、以下のように caseSensitive オプションを true に設定すると、同じパスでも大文字と小文字が異なる場合は別のルートとして扱われます。

const fastify = require("fastify")({
  caseSensitive: true
});

fastify.get("/hello", function(request, reply) {
  reply.send("Hello World!");
});

fastify.get("/Hello", function(request, reply) {
  reply.send("Hello World!");
});

const start = async () => {
  try {
    await fastify.listen(3000);
  } catch (err) {
    fastify.log.error(err);
    process.exit(1);
  }
};

start();

上記の例では、/hello と /Hello は別のルートとして扱われます。したがって、それぞれの URL にアクセスすると異なるレスポンスが返されます。

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

allowUnsafeRegex

allowUnsafeRegex は、Fastify が受信した正規表現パターンを安全に処理するかどうかを制御するオプションです。デフォルトでは false に設定されており、Fastify は受信したパターンを安全に処理するようになっています。これは、正規表現による攻撃を防ぐためのものです。

しかし、allowUnsafeRegex を true に設定すると、Fastify は受信した正規表現パターンを安全でないと判断しても処理を行います。このオプションは、Fastify が古いバージョンの Node.js を使用している場合に、正規表現のパフォーマンスを向上させることができます。ただし、悪意のある攻撃に対して脆弱性があるため、使用する際には注意が必要です。

以下は、allowUnsafeRegex を有効にした例です。

const fastify = require('fastify')({
  logger: true,
  allowUnsafeRegex: true
})

fastify.get('/:id(\\d+)', (request, reply) => {
  const id = request.params.id
  reply.send({ id })
})

fastify.listen(3000, err => {
  if (err) {
    fastify.log.error(err)
    process.exit(1)
  }
})

この例では、正規表現パターン\d+を使用してパスパラメータ:id を検証しています。allowUnsafeRegex が true に設定されているため、受信した正規表現パターンを安全でないと判断しても、Fastify はパターンを処理します。

requestIdHeader

requestIdHeader オプションは、Fastify が生成するリクエスト ID に使用する HTTP ヘッダー名を指定するためのものです。リクエスト ID は、アプリケーション内でのトレースやデバッグなどに使用されます。デフォルトでは “request-id” というヘッダーが使用されますが、必要に応じてカスタマイズすることができます。

const fastify = require("fastify")({
  logger: true,
  requestIdHeader: 'x-request-id'
});

fastify.get("/hello", function(request, reply) {
  reply.send("Hello World!");
});

const start = async () => {
  try {
    await fastify.listen(3000);
  } catch (err) {
    fastify.log.error(err);
    process.exit(1);
  }
};

start();

requestIdLogLabel

requestIdLogLabel は Fastify のサーバーオプションの 1 つで、リクエスト ID がログ出力時に使用されるラベルを設定するために使用されます。

ログ出力時にリクエスト ID を含めることは、複数のリクエストが同時に発生している場合に、ログメッセージを識別するのに役立ちます。requestIdLogLabel オプションを使用することで、リクエスト ID のログ出力時のラベルを設定できます。

デフォルトでは、Fastify は “reqId” をラベルとして使用します。以下は、 requestIdLogLabel オプションを使用してラベルを “requestId” に設定する例です。

const fastify = require('fastify')({
  requestIdLogLabel: 'requestId'
});

fastify.get('/', (request, reply) => {
  request.log.info('Hello, World!');
  reply.send('Hello, World!');
});

fastify.listen(3000, (err) => {
  if (err) {
    fastify.log.error(err);
    process.exit(1);
  }
});

リクエストログ出力時のラベルを設定することで、ログメッセージがより分かりやすくなります。

genReqId

genReqId は、Fastify インスタンスで使用される関数であり、リクエスト ID を生成するために使用されます。リクエスト ID は、ログエントリーやトレーススパンなど、リクエストのライフサイクルを追跡するために使用されます。genReqId は、Fastify インスタンスのオプションで定義することができます。

genReqId は、2 つの引数を受け取ります。Fastify インスタンスと、Node.js の HTTP リクエストオブジェクトです。Fastify インスタンスは、Fastify のグローバルオプションやプラグインなどの設定を提供するために使用されます。HTTP リクエストオブジェクトは、リクエストに関する情報を提供するために使用されます。

genReqId 関数は、リクエスト ID を生成するために使用できるさまざまな方法があります。例えば、UUID やシーケンシャルな数字、ランダムな文字列などが使用されます。また、特定のヘッダーに基づいてリクエスト ID を生成することもできます。生成されたリクエスト ID は、Fastify のログエントリーに自動的に追加されます。

以下は、genReqId 関数を使用して、ランダムな文字列をリクエスト ID として生成する例です。

const fastify = require('fastify')({
  genReqId: () => uuidv4()
})

この例では、uuid ライブラリを使用してランダムな UUID を生成し、それをリクエスト ID として使用しています。

trustProxy

プロキシが利用される場合に設定します。true に設定すると、X-Forwarded-* ヘッダーから情報を取得してリクエスト処理を行います。デフォルトは false です。

const fastify = require("fastify")({
  trustProxy: true
});

fastify.get("/hello", function(request, reply) {
  reply.send("Hello World!");
});

const start = async () => {
  try {
    await fastify.listen(3000);
  } catch (err) {
    fastify.log.error(err);
    process.exit(1);
  }
};

start();

pluginTimeout

pluginTimeout は、プラグインが読み込まれるまでにかかる時間を制限するためのオプションです。プラグインが読み込まれるまでに指定された時間(ミリ秒)を超える場合、Fastify はエラーをスローします。

例えば、以下のようにして pluginTimeout を設定できます。

const fastify = require('fastify')({
  pluginTimeout: 1000 // 1秒
});

上記の例では、プラグインが読み込まれるまでに 1 秒以内に完了しない場合、エラーが発生します。

pluginTimeout を設定することで、Fastify アプリケーションの起動時間をより正確に管理できます。ただし、十分な時間を確保していない場合、プラグインの読み込みが遅くなり、アプリケーションの起動に失敗する可能性があります。適切な pluginTimeout を設定することが重要です。

querystringParser

querystringParser オプションは、Fastify がリクエスト URL からクエリストリングをパースする方法を設定するためのオプションです。デフォルトでは、Fastify は Node.js 標準の querystring モジュールを使用してクエリストリングをパースします。

以下は、querystringParser オプションを使用して、クエリストリングをパースする関数を独自に定義する例です。

const fastify = require('fastify')({
  querystringParser: function(str) {
    return myCustomQueryStringParser(str)
  }
})

fastify.get('/hello', function(request, reply) {
  reply.send('Hello World!')
})

const start = async () => {
  try {
    await fastify.listen(3000)
  } catch (err) {
    fastify.log.error(err)
    process.exit(1)
  }
}

start()

この例では、myCustomQueryStringParser 関数を使用してクエリストリングをパースするように設定しています。myCustomQueryStringParser 関数は、引数としてクエリストリングを受け取り、オブジェクトに変換したものを返します。この関数は、文字列をオブジェクトに変換するためのライブラリなどを使用して、クエリストリングをパースすることができます。

Fastify では、querystringParser オプションに関数を指定することで、独自のクエリストリングのパース方法を定義することができます。これにより、柔軟なリクエスト処理を実現することができます。

exposeHeadRoutes

exposeHeadRoutes オプションは、Fastify が HEAD メソッドのリクエストに自動的に 200 OK 応答を返すかどうかを制御します。HEAD メソッドは GET メソッドと同様に、リソースのヘッダー情報を要求するために使用されますが、実際のコンテンツは返されません。

デフォルトでは、exposeHeadRoutes オプションは true に設定されており、Fastify は HEAD メソッドのリクエストに 200 OK 応答を返します。オプションを false に設定すると、Fastify は HEAD メソッドのリクエストに自動応答しなくなります。

以下は、exposeHeadRoutes オプションを false に設定する例です。

const fastify = require("fastify")({
  exposeHeadRoutes: false,
});

fastify.get("/hello", function(request, reply) {
  reply.send("Hello World!");
});

const start = async () => {
  try {
    await fastify.listen(3000);
  } catch (err) {
    fastify.log.error(err);
    process.exit(1);
  }
};

start();

constraints

constraints オプションは、ルーティングのパスパラメーターに適用する正規表現制約を指定するために使用されます。例えば、パスパラメーターが数値であることを保証したり、文字列の長さが特定の範囲内であることを保証するために使用できます。

以下の例では、id パラメーターが数字であることを強制する正規表現 /^\d+$/ を使用しています。

const fastify = require('fastify')({
  logger: true
})

fastify.get('/users/:id', {
  handler: async (request, reply) => {
    const id = request.params.id
    const user = await getUserById(id)
    reply.send(user)
  },
  constraints: {
    id: /^\d+$/
  }
})

const start = async () => {
  try {
    await fastify.listen(3000)
    console.log('Server listening on port 3000')
  } catch (err) {
    console.error(err)
    process.exit(1)
  }
}

start()

この例では、id パラメーターに許可されるのは数字のみであり、それ以外の値が渡された場合は Fastify が自動的に 400 Bad Request エラーを返します。

constraints オプションは、正規表現の代わりに関数を指定することもできます。関数には、パラメーターの値が渡され、真偽値を返す必要があります。真偽値が false の場合、Fastify は自動的に 400 Bad Request エラーを返します。

return503OnClosing

return503OnClosing オプションは、Fastify が終了中のリクエストに 503 ステータスコードを返すかどうかを指定するためのものです。デフォルトでは false に設定されていますが、true に設定することで、終了中のリクエストに対して 503 ステータスコードを返すことができます。

const fastify = require("fastify")({
  logger: true,
  return503OnClosing: true
});

fastify.get("/hello", function(request, reply) {
  reply.send("Hello World!");
});

const start = async () => {
  try {
    await fastify.listen(3000);
  } catch (err) {
    fastify.log.error(err);
    process.exit(1);
  }
};

start();

ajv

Ajv(Another JSON Schema Validator)は、JSON スキーマを検証するための高速でパフォーマンスの高いバリデーションライブラリです。JSON スキーマは、JSON データが特定のフォーマット、データ型、および値を持つかどうかを定義するために使用されます。

Fastify では、Ajv を使用して入力データのバリデーションを行うことができます。例えば、クエリパラメーターやリクエストボディのデータが、特定の形式に従っているかどうかを検証することができます。

以下は、Ajv を使用してクエリパラメーターのバリデーションを行う例です。

const fastify = require('fastify')({
  logger: true
})

const schema = {
  querystring: {
    name: { type: 'string' },
    age: { type: 'number' }
  }
}

fastify.get('/user', {
  schema: schema
}, function (request, reply) {
  const { name, age } = request.query
  reply.send({ name, age })
})

fastify.listen(3000, function (err) {
  if (err) {
    fastify.log.error(err)
    process.exit(1)
  }
})

この例では、schema オブジェクトを定義し、querystring キーにクエリパラメータの検証ルールを定義しています。type プロパティを使用して、name パラメータが文字列であること、age パラメータが数値であることを定義しています。

fastify.get メソッドで、バリデーションルールを schema オプションに設定しています。リクエストが /user パスに来た際に、このルールに従ってクエリパラメータのバリデーションを行い、バリデーションエラーがある場合はエラーレスポンスを返します。

Ajv は高速で効率的なバリデーションライブラリであり、Fastify の標準的なバリデーションツールとして広く採用されています。

serializerOpts

serializerOpts は Fastify のオプションの 1 つで、Fastify がレスポンスのシリアル化に使用する Fastify-Serializer プラグインのオプションを設定するために使用されます。

Fastify-Serializer は、Fastify アプリケーションが送信するレスポンスをシリアル化するために使用されます。JSON や MessagePack、BSON などの形式をサポートしており、カスタムシリアル化関数を定義することもできます。serializerOpts は、Fastify-Serializer プラグインに渡されるオプションを設定するために使用されます。

以下は、serializerOpts を使用して、Fastify が JSON 形式のレスポンスを返すように設定する例です。

const fastify = require('fastify')({
  logger: true,
  serializerOpts: {
    serialize: JSON.stringify
  }
})

fastify.get('/', function (req, reply) {
  reply.send({ hello: 'world' })
})

const start = async () => {
  try {
    await fastify.listen(3000)
    fastify.log.info(`server listening on ${fastify.server.address().port}`)
  } catch (err) {
    fastify.log.error(err)
    process.exit(1)
  }
}

start()

上記の例では、Fastify-Serializer プラグインのオプション serialize に JSON.stringify 関数を設定し、Fastify が JSON 形式でレスポンスを返すように設定しています。この例では、/エンドポイントにリクエストを送信し、Fastify が JSON 形式で{ “hello”: “world” }を返すことを期待できます。

http2SessionTimeout

http2SessionTimeout オプションは、HTTP/2 セッションのタイムアウト時間を指定するために使用されます。デフォルトでは、HTTP/2 セッションのタイムアウトは 5 秒に設定されています。

HTTP/2 は、TCP コネクションの再利用をサポートしています。つまり、クライアントが同じサーバーに対して別のリクエストを送信するときに、以前のリクエストで使用された TCP コネクションを再利用することができます。この再利用は、HTTP/2 セッションとして知られるような仕組みを通じて実現されます。

http2SessionTimeout オプションは、HTTP/2 セッションがタイムアウトするまでの時間を設定します。つまり、同じサーバーに対する次のリクエストがない場合に、セッションが自動的にクローズされるまでの時間を指定することができます。

以下は http2SessionTimeout オプションを使用した例です。

const fastify = require('fastify')({
  http2: true,
  http2SessionTimeout: 60000, // 60 seconds
});

fastify.get('/', function (req, reply) {
  reply.send({ hello: 'world' })
})

const start = async () => {
  try {
    await fastify.listen(3000)
    console.log('Server started at http://localhost:3000')
  } catch (err) {
    console.error(err)
    process.exit(1)
  }
}

start()

この例では、http2SessionTimeout を 60000 に設定しています。つまり、同じサーバーに対する次のリクエストがない場合に、セッションが自動的にクローズされるまでの時間を 60 秒に設定しています。

frameworkErrors

frameworkErrors オプションは、Fastify が内部的に生成したエラーに対してカスタムのエラーハンドリングを設定するためのものです。

Fastify では、ハンドルされていないエラーは自動的に処理され、クライアントに 500 Internal Server Error として送信されます。frameworkErrors オプションを使用すると、この自動処理されたエラーをカスタマイズすることができます。

具体的には、frameworkErrors オプションにカスタムエラーハンドラーを定義することで、Fastify が自動処理されたエラーに対して、カスタムのエラーレスポンスを送信することができます。

例えば、以下のように設定することで、NotFoundError というエラーが発生した場合に、クライアントに 404 Not Found というレスポンスを送信することができます。

const fastify = require('fastify')({
  frameworkErrors: (err, req, res) => {
    if (err.statusCode === 404) {
      res.status(404).send('Not Found')
      return
    }

    res.status(500).send('Internal Server Error')
  }
})

fastify.get('/hello', (req, res) => {
  throw new Error('Something went wrong')
})

fastify.listen(3000, (err) => {
  if (err) {
    console.error(err)
    process.exit(1)
  }
})

frameworkErrors オプションを使用することで、自動処理されたエラーに対してカスタムのエラーハンドリングを簡単に設定することができます。

clientErrorHandler

clientErrorHandler は、Fastify アプリケーションで発生したクライアント側のエラーを処理するためのオプションです。

Fastify アプリケーションは、HTTP エラー以外にも、例外やエラーが発生する可能性があります。クライアントエラーは、サーバー側の問題ではなく、クライアント側の要求が不正であるため発生します。例えば、不正な形式のリクエストボディや、必須のパラメータがない場合などです。

Fastify では、clientErrorHandler オプションを使用することで、このようなクライアントエラーを取り扱うことができます。clientErrorHandler は、エラーが発生したときに呼び出されるコールバック関数を指定することができます。このコールバック関数は、3 つの引数を受け取ります。

const fastify = require('fastify')({
  logger: true,
  clientErrorHandler: function (error, request, reply) {
    reply.status(400).send({
      error: error.message
    })
  }
})

clientErrorHandler オプションの例では、エラーが発生したときに、400 Bad Request 応答を返すために、エラーオブジェクトのメッセージを含むオブジェクトを送信します。このオプションを使用することで、エラーメッセージを返すだけでなく、エラーをどのように処理するかを細かく制御することができます。

rewriteUrl

rewriteUrl オプションは、Fastify がリクエスト URL を解析する方法を変更するために使用されます。このオプションを使用すると、Fastify がリクエスト URL の一部を変更することができます。

例えば、次のように rewriteUrl オプションを使用して、リクエスト URL の先頭に /api を追加することができます。

const fastify = require('fastify')({
  rewriteUrl: (req) => {
    return '/api' + req.url
  }
})

この設定を使用すると、リクエスト URL /users は /api/users に変更されます。

このオプションを使用すると、例えばリバースプロキシなどで使用する URL の変換が可能になります。ただし、注意点として、rewriteUrl オプションを使用する場合、Fastify がリクエスト URL を解析するためのコードをすべて自分で実装する必要があるため、誤った実装によってセキュリティ上の問題が引き起こされる可能性があります。

まとめ

Fastify では、リクエスト情報を取得することができ、それを使用してリクエスト処理を行います。パスパラメータやクエリストリングなど、様々な情報を取得することができるため、柔軟なリクエスト処理が可能です。