TypeScript
TypeScript
FastifyフレームワークはバニラJavaScriptで記述されており、そのため型定義のメンテナンスは容易ではありません。しかし、バージョン2以降、メンテナーとコントリビューターは型を改善するために多大な努力を払ってきました。
型システムはFastifyバージョン3で変更されました。新しい型システムでは、ジェネリックな制約とデフォルト、およびリクエストボディ、クエリ文字列などのスキーマ型を定義する新しい方法が導入されました。チームがフレームワークと型定義の相乗効果を改善する中で、APIの一部が型付けされていなかったり、誤った型付けがされている場合があります。ギャップを埋めるために、ぜひ**コントリビューション**をお願いします。スムーズに進めるために、開始する前にCONTRIBUTING.md
ファイルを必ずお読みください。
このセクションのドキュメントは、Fastifyバージョン3.xの型付けについて説明しています
プラグインに型付けが含まれているかどうかは、プラグインによって異なります。詳細については、プラグインを参照してください。型付けサポートを改善するために、プルリクエストを送ることをお勧めします。
🚨 @types/node
をインストールすることを忘れないでください
例から学ぶ
Fastifyの型システムを学ぶ最良の方法は、例から学ぶことです!次の4つの例は、Fastify開発で最も一般的なケースをカバーしています。例の後に、型システムに関するさらに詳細なドキュメントがあります。
はじめに
この例では、FastifyとTypeScriptを起動して実行します。これにより、空白のhttp Fastifyサーバーが生成されます。
新しいnpmプロジェクトを作成し、Fastifyをインストールし、TypeScriptとNode.jsの型をピア依存関係としてインストールします
npm init -y
npm i fastify
npm i -D typescript @types/nodepackage.json
の"scripts"
セクションに次の行を追加します{
"scripts": {
"build": "tsc -p tsconfig.json",
"start": "node index.js"
}
}TypeScript構成ファイルを初期化します
npx tsc --init
または、推奨されるものの1つを使用します。
注意: tsconfig.json
の target
プロパティを es2017
以上に設定して、FastifyDeprecation 警告を回避してください。
index.ts
ファイルを作成します。ここにはサーバーコードが含まれます次のコードブロックをファイルに追加します
import fastify from 'fastify'
const server = fastify()
server.get('/ping', async (request, reply) => {
return 'pong\n'
})
server.listen({ port: 8080 }, (err, address) => {
if (err) {
console.error(err)
process.exit(1)
}
console.log(`Server listening at ${address}`)
})npm run build
を実行します。これにより、index.ts
がindex.js
にコンパイルされ、Node.jsを使用して実行できます。エラーが発生した場合は、fastify/helpに問題をオープンしてくださいnpm run start
を実行して、Fastifyサーバーを実行しますコンソールに
Server listening at http://127.0.0.1:8080
と表示されるはずですcurl localhost:8080/ping
を使用してサーバーを試してみてください。pong
🏓 が返されるはずです
🎉 これで、動作するTypescript Fastifyサーバーができました!この例では、バージョン3.xの型システムの単純さを示しています。デフォルトでは、型システムはhttp
サーバーを使用していると想定しています。後の例では、https
やhttp2
などのより複雑なサーバーを作成する方法、ルートスキーマを指定する方法などを示します!
TypeScriptを使用したFastifyの初期化に関する詳細な例(HTTP2の有効化など)については、詳細なAPIセクションこちらをご覧ください
ジェネリックの使用
型システムは、最も正確な開発エクスペリエンスを提供するために、ジェネリックプロパティに大きく依存しています。一部の人はオーバーヘッドが少し面倒だと感じるかもしれませんが、トレードオフする価値はあります!この例では、ルートスキーマとルートレベルのrequest
オブジェクトにある動的プロパティに対してジェネリック型を実装することについて詳しく説明します。
前の例を完了していない場合は、ステップ1〜4に従って設定します。
index.ts
内で、3つのインターフェースIQuerystring
、IHeaders
、およびIReply
を定義しますinterface IQuerystring {
username: string;
password: string;
}
interface IHeaders {
'h-Custom': string;
}
interface IReply {
200: { success: boolean };
302: { url: string };
'4xx': { error: string };
}3つのインターフェースを使用して、新しいAPIルートを定義し、それらをジェネリックとして渡します。短縮形のルートメソッド(つまり、
.get
)は、5つの名前付きプロパティ(Body
、Querystring
、Params
、Headers
、およびReply
)を含むジェネリックオブジェクトRouteGenericInterface
を受け入れます。インターフェースBody
、Querystring
、Params
、およびHeaders
は、ルートメソッドを介してルートメソッドハンドラーrequest
インスタンスに渡され、Reply
インターフェースはreply
インスタンスに渡されます。server.get<{
Querystring: IQuerystring,
Headers: IHeaders,
Reply: IReply
}>('/auth', async (request, reply) => {
const { username, password } = request.query
const customerHeader = request.headers['h-Custom']
// do something with request data
// chaining .statusCode/.code calls with .send allows type narrowing. For example:
// this works
reply.code(200).send({ success: true });
// but this gives a type error
reply.code(200).send('uh-oh');
// it even works for wildcards
reply.code(404).send({ error: 'Not found' });
return `logged in!`
})npm run build
とnpm run start
を使用して、サーバーコードをビルドして実行しますAPIをクエリします
curl localhost:8080/auth?username=admin&password=Password123!
そして、
logged in!
が返ってくるはずですしかし、まだあります!ジェネリックインターフェースは、ルートレベルのフックメソッド内でも使用できます。
preValidation
フックを追加して、前のルートを変更しますserver.get<{
Querystring: IQuerystring,
Headers: IHeaders,
Reply: IReply
}>('/auth', {
preValidation: (request, reply, done) => {
const { username, password } = request.query
done(username !== 'admin' ? new Error('Must be admin') : undefined) // only validate `admin` account
}
}, async (request, reply) => {
const customerHeader = request.headers['h-Custom']
// do something with request data
return `logged in!`
})ビルドと実行を行い、
username
クエリ文字列オプションがadmin
以外に設定された状態でクエリを実行します。APIは、HTTP 500エラー{"statusCode":500,"error":"Internal Server Error","message":"Must be admin"}
を返すようになりました
🎉 よくできました。これで、各ルートのインターフェースを定義し、厳密に型付けされたrequestインスタンスとreplyインスタンスを持つことができます。Fastify型システムの他の部分も、ジェネリックプロパティに依存しています。利用可能なものについて詳しくは、以下の詳細な型システムドキュメントを参照してください。
JSONスキーマ
リクエストとレスポンスを検証するには、JSONスキーマファイルを使用できます。ご存じないかもしれませんが、Fastifyルートのスキーマを定義すると、スループットが向上する可能性があります!詳細については、バリデーションとシリアライゼーションのドキュメントをご覧ください。
また、ハンドラー(プリバリデーションなどを含む)内で定義された型を使用できるという利点もあります。
これを実現する方法に関するいくつかのオプションを次に示します。
Fastify型プロバイダー
Fastifyは、json-schema-to-ts
とtypebox
をラップする2つのパッケージを提供しています
および、サードパーティによるzod
ラッパーであるfastify-type-provider-zod
これらはスキーマ検証の設定を簡略化し、タイププロバイダーページで詳細を読むことができます。
以下は、タイププロバイダーなしでtypebox
、json-schema-to-typescript
、およびjson-schema-to-ts
パッケージを使用してスキーマ検証を設定する方法です。
TypeBox
型とスキーマを同時に構築するための便利なライブラリはTypeBoxです。TypeBoxを使用すると、コード内でスキーマを定義し、必要に応じて型またはスキーマとして直接使用できます。
Fastifyルートで一部のペイロードの検証に使用する場合は、次のように実行できます
プロジェクトに
typebox
をインストールします。npm i @sinclair/typebox
Type
を使用して必要なスキーマを定義し、Static
を使用してそれぞれの型を作成します。import { Static, Type } from '@sinclair/typebox'
export const User = Type.Object({
name: Type.String(),
mail: Type.Optional(Type.String({ format: 'email' })),
})
export type UserType = Static<typeof User>ルートの定義中に、定義された型とスキーマを使用します
import Fastify from 'fastify'
// ...
const fastify = Fastify()
fastify.post<{ Body: UserType, Reply: UserType }>(
'/',
{
schema: {
body: User,
response: {
200: User
},
},
},
(request, reply) => {
// The `name` and `mail` types are automatically inferred
const { name, mail } = request.body;
reply.status(200).send({ name, mail });
}
)
json-schema-to-typescript
最後の例では、Typeboxを使用してルートの型とスキーマを定義しました。多くのユーザーは、これらのプロパティを定義するためにすでにJSONスキーマを使用しているため、幸運なことに、既存のJSONスキーマをTypeScriptインターフェースに変換する方法があります!
'はじめに'の例を完了していない場合は、戻ってまずステップ1〜4に従ってください。
json-schema-to-typescript
モジュールをインストールしますnpm i -D json-schema-to-typescript
schemas
という新しいフォルダーを作成し、2つのファイルheaders.json
とquerystring.json
を追加します。次のスキーマ定義をそれぞれのファイルにコピーして貼り付けます{
"title": "Headers Schema",
"type": "object",
"properties": {
"h-Custom": { "type": "string" }
},
"additionalProperties": false,
"required": ["h-Custom"]
}{
"title": "Querystring Schema",
"type": "object",
"properties": {
"username": { "type": "string" },
"password": { "type": "string" }
},
"additionalProperties": false,
"required": ["username", "password"]
}package.json
にcompile-schemas
スクリプトを追加します
{
"scripts": {
"compile-schemas": "json2ts -i schemas -o types"
}
}
json2ts
は、json-schema-to-typescript
に含まれるCLIユーティリティです。schemas
は入力パスであり、types
は出力パスです。5. npm run compile-schemas
を実行します。types
ディレクトリに2つの新しいファイルが作成されたはずです。6. 次のコードを含むようにindex.ts
を更新します
import fastify from 'fastify'
// import json schemas as normal
import QuerystringSchema from './schemas/querystring.json'
import HeadersSchema from './schemas/headers.json'
// import the generated interfaces
import { QuerystringSchema as QuerystringSchemaInterface } from './types/querystring'
import { HeadersSchema as HeadersSchemaInterface } from './types/headers'
const server = fastify()
server.get<{
Querystring: QuerystringSchemaInterface,
Headers: HeadersSchemaInterface
}>('/auth', {
schema: {
querystring: QuerystringSchema,
headers: HeadersSchema
},
preValidation: (request, reply, done) => {
const { username, password } = request.query
done(username !== 'admin' ? new Error('Must be admin') : undefined)
}
// or if using async
// preValidation: async (request, reply) => {
// const { username, password } = request.query
// if (username !== "admin") throw new Error("Must be admin");
// }
}, async (request, reply) => {
const customerHeader = request.headers['h-Custom']
// do something with request data
return `logged in!`
})
server.route<{
Querystring: QuerystringSchemaInterface,
Headers: HeadersSchemaInterface
}>({
method: 'GET',
url: '/auth2',
schema: {
querystring: QuerystringSchema,
headers: HeadersSchema
},
preHandler: (request, reply, done) => {
const { username, password } = request.query
const customerHeader = request.headers['h-Custom']
done()
},
handler: (request, reply) => {
const { username, password } = request.query
const customerHeader = request.headers['h-Custom']
reply.status(200).send({username});
}
})
server.listen({ port: 8080 }, (err, address) => {
if (err) {
console.error(err)
process.exit(0)
}
console.log(`Server listening at ${address}`)
})
このファイルの先頭にあるインポートに特に注意してください。冗長に見えるかもしれませんが、スキーマファイルと生成されたインターフェースの両方をインポートする必要があります。
素晴らしい出来です!これで、JSONスキーマとTypeScript定義の両方を使用できるようになりました。
json-schema-to-ts
スキーマから型を生成したくないが、コードから直接使用したい場合は、json-schema-to-tsパッケージを使用できます。
開発依存関係としてインストールできます。
npm i -D json-schema-to-ts
コードでは、通常のオブジェクトのようにスキーマを定義できます。ただし、モジュールのドキュメントで説明されているように、必ずconstにしてください。
const todo = {
type: 'object',
properties: {
name: { type: 'string' },
description: { type: 'string' },
done: { type: 'boolean' },
},
required: ['name'],
} as const; // don't forget to use const !
提供されている型FromSchema
を使用すると、スキーマから型を構築し、ハンドラーで使用できます。
import { FromSchema } from "json-schema-to-ts";
fastify.post<{ Body: FromSchema<typeof todo> }>(
'/todo',
{
schema: {
body: todo,
response: {
201: {
type: 'string',
},
},
}
},
async (request, reply): Promise<void> => {
/*
request.body has type
{
[x: string]: unknown;
description?: string;
done?: boolean;
name: string;
}
*/
request.body.name // will not throw type error
request.body.notthere // will throw type error
reply.status(201).send();
},
);
プラグイン
Fastifyの最も際立った機能の1つは、その広範なプラグインエコシステムです。プラグインの型は完全にサポートされており、宣言マージパターンを利用します。この例は、3つの部分に分かれています。TypeScript Fastifyプラグインの作成、Fastifyプラグインの型定義の作成、およびTypeScriptプロジェクトでのFastifyプラグインの使用です。
TypeScript Fastifyプラグインの作成
新しいnpmプロジェクトを初期化し、必要な依存関係をインストールします
npm init -y
npm i fastify fastify-plugin
npm i -D typescript @types/nodepackage.json
ファイルの"scripts"
セクションにbuild
スクリプトを追加し、"types"
セクションに'index.d.ts'
を追加します。{
"types": "index.d.ts",
"scripts": {
"build": "tsc -p tsconfig.json"
}
}TypeScript構成ファイルを初期化します
npx typescript --init
ファイルが生成されたら、
"compilerOptions"
オブジェクトで"declaration"
オプションを有効にします。{
"compilerOptions": {
"declaration": true
}
}index.ts
ファイルを作成します。これがプラグインコードを含むファイルになります。index.ts
に次のコードを追加します。import { FastifyPluginCallback, FastifyPluginAsync } from 'fastify'
import fp from 'fastify-plugin'
// using declaration merging, add your plugin props to the appropriate fastify interfaces
// if prop type is defined here, the value will be typechecked when you call decorate{,Request,Reply}
declare module 'fastify' {
interface FastifyRequest {
myPluginProp: string
}
interface FastifyReply {
myPluginProp: number
}
}
// define options
export interface MyPluginOptions {
myPluginOption: string
}
// define plugin using callbacks
const myPluginCallback: FastifyPluginCallback<MyPluginOptions> = (fastify, options, done) => {
fastify.decorateRequest('myPluginProp', 'super_secret_value')
fastify.decorateReply('myPluginProp', options.myPluginOption)
done()
}
// define plugin using promises
const myPluginAsync: FastifyPluginAsync<MyPluginOptions> = async (fastify, options) => {
fastify.decorateRequest('myPluginProp', 'super_secret_value')
fastify.decorateReply('myPluginProp', options.myPluginOption)
}
// export plugin using fastify-plugin
export default fp(myPluginCallback, '3.x')
// or
// export default fp(myPluginAsync, '3.x')npm run build
を実行してプラグインコードをコンパイルし、JavaScript ソースファイルと型定義ファイルの両方を生成します。これでプラグインが完成したので、以下ができます。[npm に公開]またはローカルで使用します。
プラグインを使用するために npm に公開する必要はありません。 Fastify プロジェクトに含めて、他のコードと同じように参照できます。 TypeScript ユーザーの場合は、TypeScript インタープリターが処理できるように、宣言のオーバーライドがプロジェクトのコンパイルに含まれる場所に存在することを確認してください。
Fastify プラグインの型定義の作成
このプラグインガイドは、JavaScript で記述された Fastify プラグインを対象としています。この例で概説されている手順は、プラグインを使用するユーザー向けに TypeScript サポートを追加するためのものです。
新しいnpmプロジェクトを初期化し、必要な依存関係をインストールします
npm init -y
npm i fastify-pluginindex.js
とindex.d.ts
の 2 つのファイルを作成します。package.json
を変更して、これらのファイルをmain
プロパティとtypes
プロパティの下に含めます (名前は明示的にindex
である必要はありませんが、ファイル名を同じにすることをお勧めします)。{
"main": "index.js",
"types": "index.d.ts"
}index.js
を開き、次のコードを追加します。// fastify-plugin is highly recommended for any plugin you write
const fp = require('fastify-plugin')
function myPlugin (instance, options, done) {
// decorate the fastify instance with a custom function called myPluginFunc
instance.decorate('myPluginFunc', (input) => {
return input.toUpperCase()
})
done()
}
module.exports = fp(myPlugin, {
fastify: '5.x',
name: 'my-plugin' // this is used by fastify-plugin to derive the property name
})index.d.ts
を開き、次のコードを追加します。import { FastifyPluginCallback } from 'fastify'
interface PluginOptions {
//...
}
// Optionally, you can add any additional exports.
// Here we are exporting the decorator we added.
export interface myPluginFunc {
(input: string): string
}
// Most importantly, use declaration merging to add the custom property to the Fastify type system
declare module 'fastify' {
interface FastifyInstance {
myPluginFunc: myPluginFunc
}
}
// fastify-plugin automatically adds named export, so be sure to add also this type
// the variable name is derived from `options.name` property if `module.exports.myPlugin` is missing
export const myPlugin: FastifyPluginCallback<PluginOptions>
// fastify-plugin automatically adds `.default` property to the exported plugin. See the note below
export default myPlugin
注: fastify-plugin v2.3.0 以降では、自動的に .default
プロパティと、エクスポートされたプラグインへの名前付きエクスポートが追加されます。最高の開発者エクスペリエンスを提供するために、型定義で export default
と export const myPlugin
を必ず使用してください。完全な例については、@fastify/swagger を確認してください。
これらのファイルが完成すると、プラグインは TypeScript プロジェクトで使用できるようになります。
Fastify プラグインシステムを使用すると、開発者は Fastify インスタンスと、リクエスト/レスポンスインスタンスを装飾できます。詳細については、宣言マージとジェネリック継承に関するこのブログ投稿を確認してください。
プラグインの使用
TypeScript で Fastify プラグインを使用するのは、JavaScript で使用するのと同じくらい簡単です。import/from
を使用してプラグインをインポートすれば、準備は完了です。ただし、ユーザーが注意すべき例外が 1 つあります。
Fastify プラグインは、宣言マージを使用して既存の Fastify 型インターフェイスを変更します (詳細については、前の 2 つの例を参照してください)。宣言マージはあまりスマートではありません。つまり、プラグインの型定義が TypeScript インタープリターのスコープ内にある場合、プラグインが使用されているかどうかに関係なく、プラグインの型が含まれます。これは TypeScript を使用する上での不幸な制限であり、今のところ回避できません。
ただし、このエクスペリエンスを向上させるためのいくつかの提案があります。
- ESLint で
no-unused-vars
ルールが有効になっていること、およびインポートされたプラグインが実際に読み込まれていることを確認してください。 @typescript-eslint/no-floating-promises
を有効にしている場合は、typescript-eslint no-floating-promises allowForKnownSafePromises documentation
で説明されているように、ESLint 構成にallowForKnownSafePromises
プロパティが含まれていることを再確認してください。
{
"rules": {
"@typescript-eslint/no-floating-promises": ["error", {
"allowForKnownSafePromises": [
{ "from": "package", "name": "FastifyInstance", "package": "fastify" },
{ "from": "package", "name": "FastifyReply", "package": "fastify" },
{ "from": "package", "name": "SafePromiseLike", "package": "fastify" },
]
}]
}
}
require
を使用すると、型定義が適切に読み込まれず、型エラーが発生する可能性があることに注意してください。TypeScript は、コードに直接インポートされた型のみを識別できます。つまり、上部でインポートを使用して require をインラインで使用できます。例:
import 'plugin' // here will trigger the type augmentation.
fastify.register(require('plugin'))
import plugin from 'plugin' // here will trigger the type augmentation.
fastify.register(plugin)
または tsconfig で明示的な構成もできます。
{
"types": ["plugin"] // we force TypeScript to import the types
}
プレーン JavaScript でのコード補完
プレーン JavaScript では、TypeScript JSDoc リファレンスに従うことで、公開された型を使用してコード補完 (例: Intellisense) を提供できます。
例:
/** @type {import('fastify').FastifyPluginAsync<{ optionA: boolean, optionB: string }>} */
module.exports = async function (fastify, { optionA, optionB }) {
fastify.get('/look', () => 'at me');
}
API 型システムドキュメント
このセクションでは、Fastify バージョン 3.x で利用可能なすべての型について詳しく説明します。
すべての http
、https
、および http2
型は、@types/node
から推論されます。
ジェネリックは、デフォルト値と制約値でドキュメント化されています。TypeScript ジェネリックの詳細については、これらの記事を参照してください。
インポート方法
Fastify API は、fastify()
メソッドによって提供されます。JavaScript では、const fastify = require('fastify')
を使用してインポートします。TypeScript では、型を解決できるように、代わりに import/from
構文を使用することをお勧めします。Fastify 型システムでは、いくつかのサポートされているインポート方法があります。
import fastify from 'fastify'
型は解決されますが、ドット表記を使用してアクセスすることはできません。
例:
import fastify from 'fastify'
const f = fastify()
f.listen({ port: 8080 }, () => { console.log('running') })分割代入を使用して型にアクセスする
import fastify, { FastifyInstance } from 'fastify'
const f: FastifyInstance = fastify()
f.listen({ port: 8080 }, () => { console.log('running') })分割代入は、メインの API メソッドでも機能します。
import { fastify, FastifyInstance } from 'fastify'
const f: FastifyInstance = fastify()
f.listen({ port: 8080 }, () => { console.log('running') })
import * as Fastify from 'fastify'
型は解決され、ドット表記を使用してアクセスできます。
メインの Fastify API メソッドを呼び出すには、わずかに異なる構文が必要です (例を参照)。
例:
import * as Fastify from 'fastify'
const f: Fastify.FastifyInstance = Fastify.fastify()
f.listen({ port: 8080 }, () => { console.log('running') })
const fastify = require('fastify')
この構文は有効であり、期待どおりに fastify をインポートします。ただし、型は解決されません。
例:
const fastify = require('fastify')
const f = fastify()
f.listen({ port: 8080 }, () => { console.log('running') })分割代入はサポートされており、型が適切に解決されます。
const { fastify } = require('fastify')
const f = fastify()
f.listen({ port: 8080 }, () => { console.log('running') })
ジェネリック
多くの型定義は同じジェネリックパラメーターを共有しています。これらはすべてこのセクションで詳細に説明されています。
ほとんどの定義は、@types/node
モジュール http
、https
、および http2
に依存しています。
RawServer
基になる Node.js サーバー型
デフォルト: http.Server
制約: http.Server
、https.Server
、http2.Http2Server
、http2.Http2SecureServer
ジェネリックパラメーターを適用: RawRequest
、RawReply
RawRequest
基になる Node.js リクエスト型
デフォルト: RawRequestDefaultExpression
制約: http.IncomingMessage
、http2.Http2ServerRequest
適用: RawServer
RawReply
基になる Node.js レスポンス型
デフォルト: RawReplyDefaultExpression
制約: http.ServerResponse
、http2.Http2ServerResponse
適用: RawServer
Logger
Fastify ロギングユーティリティ
デフォルト: FastifyLoggerOptions
適用: RawServer
RawBody
コンテンツタイプパーサーメソッドのジェネリックパラメーター。
制約: string | Buffer
Fastify
fastify< RawRequest, RawReply, Logger>(opts?: FastifyServerOptions): FastifyInstance
メインの Fastify API メソッド。デフォルトでは、HTTP サーバーを作成します。判別共用体とオーバーロードメソッドを利用して、型システムは、メソッドに渡されるオプションのみに基づいて、作成されるサーバー (http、https、または http2) のタイプを自動的に推論します (詳細については、以下の例を参照してください)。また、基になる Node.js Server、Request、および Reply オブジェクトを拡張できるように、広範なジェネリック型システムをサポートします。さらに、カスタムログタイプ用の Logger
ジェネリックが存在します。詳細については、以下の例とジェネリックの内訳を参照してください。
例 1: 標準 HTTP サーバー
型システムは HTTP をデフォルトとするため、Server
ジェネリックを指定する必要はありません。
import fastify from 'fastify'
const server = fastify()
詳細な http サーバーのウォークスルーについては、「例で学ぶ - はじめに」の例を参照してください。
例 2: HTTPS サーバー
@types/node
とfastify
から次のインポートを作成します。import fs from 'fs'
import path from 'path'
import fastify from 'fastify'key.pem
ファイルとcert.pem
ファイルを作成するために、Fastify HTTPS サーバーをセットアップする前に、次の手順を実行します。
openssl genrsa -out key.pem
openssl req -new -key key.pem -out csr.pem
openssl x509 -req -days 9999 -in csr.pem -signkey key.pem -out cert.pem
rm csr.pem
Fastify https サーバーをインスタンス化し、ルートを追加します。
const server = fastify({
https: {
key: fs.readFileSync(path.join(__dirname, 'key.pem')),
cert: fs.readFileSync(path.join(__dirname, 'cert.pem'))
}
})
server.get('/', async function (request, reply) {
return { hello: 'world' }
})
server.listen({ port: 8080 }, (err, address) => {
if (err) {
console.error(err)
process.exit(0)
}
console.log(`Server listening at ${address}`)
})ビルドして実行します。
curl -k https://127.0.0.1:8080
でクエリを実行して、サーバーをテストします。
例 3: HTTP2 サーバー
HTTP2 サーバータイプには、セキュアと非セキュアの 2 つのタイプがあります。どちらも、options
オブジェクトで http2
プロパティを true
として指定する必要があります。https
プロパティはセキュアな http2 サーバーを作成するために使用されます。https
プロパティを省略すると、非セキュアな http2 サーバーが作成されます。
const insecureServer = fastify({ http2: true })
const secureServer = fastify({
http2: true,
https: {} // use the `key.pem` and `cert.pem` files from the https section
})
HTTP2 の使用の詳細については、Fastify HTTP2 ドキュメントページを参照してください。
例 4: 拡張 HTTP サーバー
サーバータイプだけでなく、リクエストタイプとレスポンスタイプも指定できます。したがって、特別なプロパティ、メソッドなどを指定できます。サーバーのインスタンス化時に指定すると、カスタムタイプのカスタムタイプは、以降のすべてのインスタンスで使用できるようになります。
import fastify from 'fastify'
import http from 'http'
interface customRequest extends http.IncomingMessage {
mySpecialProp: string
}
const server = fastify<http.Server, customRequest>()
server.get('/', async (request, reply) => {
const someValue = request.raw.mySpecialProp // TS knows this is a string, because of the `customRequest` interface
return someValue.toUpperCase()
})
例 5: ロガータイプの指定
Fastify は内部で Pino ロギングライブラリを使用しています。pino@7
以降、Fastify のインスタンスを構築する際に logger
フィールドを介して、そのすべてのプロパティを設定できます。必要なプロパティが公開されていない場合は、Pino
に Issue をオープンするか、同じフィールド経由で Fastify への一時的な修正として、事前に設定された外部の Pino インスタンス(またはその他の互換性のあるロガー)を渡してください。これにより、カスタムシリアライザーを作成することもできます。詳細については、ロギングのドキュメントを参照してください。
import fastify from 'fastify'
const server = fastify({
logger: {
level: 'info',
redact: ['x-userinfo'],
messageKey: 'message'
}
})
server.get('/', async (request, reply) => {
server.log.info('log message')
return 'another message'
})
fastify.HTTPMethods
ユニオン型: 'DELETE' | 'GET' | 'HEAD' | 'PATCH' | 'POST' | 'PUT' | 'OPTIONS'
fastify.RawServerBase
@types/node
モジュールの http
、https
、http2
に依存
ユニオン型: http.Server | https.Server | http2.Http2Server | http2.Http2SecureServer
fastify.RawServerDefault
@types/node
モジュールの http
に依存
http.Server
の型エイリアス
fastify.FastifyServerOptions< RawServer, Logger>
Fastify サーバーのインスタンス化で使用されるプロパティのインターフェースです。メインの fastify()
メソッドで使用されます。RawServer
および Logger
のジェネリックパラメータは、そのメソッドを通じて渡されます。
TypeScript で Fastify サーバーをインスタンス化する例については、メインの fastify メソッドの型定義セクションを参照してください。
fastify.FastifyInstance< RawServer, RawRequest, RequestGeneric, Logger>
Fastify サーバーオブジェクトを表すインターフェースです。これは fastify()
メソッドから返されるサーバーインスタンスです。この型はインターフェースなので、コードで decorate
メソッドを使用する場合は、宣言のマージを介して拡張できます。
ジェネリックカスケードを使用することにより、インスタンスにアタッチされたすべてのメソッドは、インスタンス化からのジェネリックプロパティを継承します。つまり、サーバー、リクエスト、またはリプライの型を指定することにより、すべてのメソッドはそれらのオブジェクトの型を把握できます。
詳細なガイドについては、メインの 例から学ぶ セクションを、このインターフェースの詳細については、より簡略化された fastify メソッドの例を確認してください。
Request
fastify.FastifyRequest< RequestGeneric, RawServer, RawRequest>
このインターフェースには、Fastify リクエストオブジェクトのプロパティが含まれています。ここに追加されたプロパティは、リクエストオブジェクトの種類(http vs http2)や、サービスを提供しているルートレベルに関係なく、request.body
を GET リクエスト内で呼び出してもエラーはスローされません(ただし、ボディ付きの GET リクエストを送信するのは困難です 😉)。
FastifyRequest
オブジェクトにカスタムプロパティを追加する必要がある場合(例えば、[decorateRequest
][DecorateRequest]メソッドを使用する場合など)は、このインターフェースで宣言のマージを使用する必要があります。
基本的な例は、FastifyRequest
セクションに記載されています。より詳細な例については、例から学ぶセクション:プラグイン を参照してください。
Example
import fastify from 'fastify'
const server = fastify()
server.decorateRequest('someProp', 'hello!')
server.get('/', async (request, reply) => {
const { someProp } = request // need to use declaration merging to add this prop to the request interface
return someProp
})
// this declaration must be in scope of the typescript interpreter to work
declare module 'fastify' {
interface FastifyRequest { // you must reference the interface and not the type
someProp: string
}
}
// Or you can type your request using
type CustomRequest = FastifyRequest<{
Body: { test: boolean };
}>
server.get('/typedRequest', async (request: CustomRequest, reply: FastifyReply) => {
return request.body.test
})
fastify.RequestGenericInterface
Fastify リクエストオブジェクトには、body
、params
、query
、headers
の 4 つの動的なプロパティがあります。それぞれの型は、このインターフェースを介して割り当て可能です。これは、開発者が指定したくないプロパティを無視できるようにする、名前付きプロパティインターフェースです。省略されたすべてのプロパティは、デフォルトで unknown
になります。対応するプロパティ名は、Body
、Querystring
、Params
、Headers
です。
import fastify, { RequestGenericInterface } from 'fastify'
const server = fastify()
interface requestGeneric extends RequestGenericInterface {
Querystring: {
name: string
}
}
server.get<requestGeneric>('/', async (request, reply) => {
const { name } = request.query // the name prop now exists on the query prop
return name.toUpperCase()
})
このインターフェースの使用例の詳細については、例から学ぶセクション:JSON Schema を参照してください。
fastify.RawRequestDefaultExpression<RawServer>
@types/node
モジュールの http
、https
、http2
に依存
ジェネリックパラメータ RawServer
はデフォルトで RawServerDefault
です
RawServer
が http.Server
または https.Server
型の場合、この式は http.IncomingMessage
を返し、それ以外の場合は http2.Http2ServerRequest
を返します。
import http from 'http'
import http2 from 'http2'
import { RawRequestDefaultExpression } from 'fastify'
RawRequestDefaultExpression<http.Server> // -> http.IncomingMessage
RawRequestDefaultExpression<http2.Http2Server> // -> http2.Http2ServerRequest
Reply
fastify.FastifyReply<RequestGeneric, RawServer, RawRequest, RawReply, ContextConfig>
このインターフェースには、Fastify が標準の Node.js リプライオブジェクトに追加するカスタムプロパティが含まれています。ここに追加されたプロパティは、リプライオブジェクトの種類(http vs http2)に関係なく有効です。
FastifyReply オブジェクトにカスタムプロパティを追加する必要がある場合(例えば、decorateReply
メソッドを使用する場合など)は、このインターフェースで宣言のマージを使用する必要があります。
基本的な例は、FastifyReply
セクションに記載されています。より詳細な例については、例から学ぶセクション:プラグイン を参照してください。
Example
import fastify from 'fastify'
const server = fastify()
server.decorateReply('someProp', 'world')
server.get('/', async (request, reply) => {
const { someProp } = reply // need to use declaration merging to add this prop to the reply interface
return someProp
})
// this declaration must be in scope of the typescript interpreter to work
declare module 'fastify' {
interface FastifyReply { // you must reference the interface and not the type
someProp: string
}
}
fastify.RawReplyDefaultExpression< RawServer>
@types/node
モジュールの http
、https
、http2
に依存
ジェネリックパラメータ RawServer
はデフォルトで RawServerDefault
です
RawServer
が http.Server
または https.Server
型の場合、この式は http.ServerResponse
を返し、それ以外の場合は http2.Http2ServerResponse
を返します。
import http from 'http'
import http2 from 'http2'
import { RawReplyDefaultExpression } from 'fastify'
RawReplyDefaultExpression<http.Server> // -> http.ServerResponse
RawReplyDefaultExpression<http2.Http2Server> // -> http2.Http2ServerResponse
Plugin
Fastify では、プラグインを使用して機能を拡張できます。プラグインは、ルートのセット、サーバーデコレータなど、任意のものにすることができます。プラグインをアクティブ化するには、fastify.register()
メソッドを使用します。
Fastify のプラグインを作成する際は、fastify-plugin
モジュールを使用することをお勧めします。また、例から学ぶの プラグイン セクションに、TypeScript と Fastify でプラグインを作成するためのガイドがあります。
fastify.FastifyPluginCallback< Options>
fastify.register()
メソッド内で使用されるインターフェースメソッド定義。
fastify.FastifyPluginAsync< Options>
fastify.register()
メソッド内で使用されるインターフェースメソッド定義。
fastify.FastifyPlugin< Options>
fastify.register()
メソッド内で使用されるインターフェースメソッド定義。一般的な FastifyPlugin
は非同期関数の型を適切に推論しないため、FastifyPluginCallback
および FastifyPluginAsync
を推奨しており、ドキュメントは非推奨です。
fastify.FastifyPluginOptions
fastify.register()
の options
パラメータをオブジェクトに制約するために使用される、緩く型付けされたオブジェクト。プラグインを作成する際は、オプションをこのインターフェースの拡張(interface MyPluginOptions extends FastifyPluginOptions
)として定義することで、登録メソッドに渡すことができます。
Register
fastify.FastifyRegister(plugin: FastifyPluginCallback, opts: FastifyRegisterOptions)
fastify.FastifyRegister(plugin: FastifyPluginAsync, opts: FastifyRegisterOptions)
fastify.FastifyRegister(plugin: FastifyPlugin, opts: FastifyRegisterOptions)
この型インターフェースは、fastify.register()
メソッドの型を指定します。この型インターフェースは、基になるジェネリック Options
を持つ関数シグネチャを返します。これはデフォルトで FastifyPluginOptions に設定されています。この関数を呼び出すときに、FastifyPlugin パラメータからこのジェネリックが推論されるため、基になるジェネリックを指定する必要はありません。オプションパラメータは、プラグインのオプションと、追加のオプションプロパティ 2 つ(prefix: string
と logLevel
: LogLevel)の交差部分です。FastifyPlugin
は非推奨であり、代わりに FastifyPluginCallback
と FastifyPluginAsync
を使用してください。
以下に、オプションの推論の例を示します
const server = fastify()
const plugin: FastifyPluginCallback<{
option1: string;
option2: boolean;
}> = function (instance, opts, done) { }
server().register(plugin, {}) // Error - options object is missing required properties
server().register(plugin, { option1: '', option2: true }) // OK - options object contains required properties
Fastify で TypeScript プラグインを作成する詳細な例については、例から学ぶの プラグイン セクションを参照してください。
fastify.FastifyRegisterOptions
この型は、Options
ジェネリックと、オプションプロパティ 2 つ(prefix: string
と logLevel
: LogLevel)を指定する、エクスポートされていないインターフェース RegisterOptions
の交差部分です。この型は、上記で説明した交差部分を返す関数としても指定できます。
Logger
カスタムロガーの指定の詳細については、ロガー型の指定 の例を参照してください。
fastify.FastifyLoggerOptions< RawServer, RawRequest, RawReply>
内部Fastifyロガーのインターフェース定義です。これは、Pino.jsロガーをエミュレートしたものです。サーバーオプションで有効にした場合は、一般的なロガードキュメントに従って使用します。
fastify.FastifyLogFn
Fastifyがログメソッドを呼び出す2つの方法を実装するオーバーロード関数インターフェースです。このインターフェースは、FastifyLoggerOptionsオブジェクトの関連するすべてのログレベルプロパティに渡されます。
fastify.LogLevel
次のユニオン型: 'info' | 'error' | 'debug' | 'fatal' | 'warn' | 'trace'
Context
コンテキスト型定義は、型システムの他の高度に動的な部分と同様です。ルートコンテキストは、ルートハンドラーメソッドで使用できます。
fastify.FastifyRequestContext
デフォルトでunknown
に設定される単一の必須プロパティconfig
を持つインターフェースです。ジェネリックまたはオーバーロードを使用して指定できます。
この型定義は不完全な可能性があります。これを使用しており、定義を改善する方法について詳細を提供できる場合は、メインのfastify/fastifyリポジトリでissueを開くことを強くお勧めします。よろしくお願いします。
fastify.FastifyReplyContext
デフォルトでunknown
に設定される単一の必須プロパティconfig
を持つインターフェースです。ジェネリックまたはオーバーロードを使用して指定できます。
この型定義は不完全な可能性があります。これを使用しており、定義を改善する方法について詳細を提供できる場合は、メインのfastify/fastifyリポジトリでissueを開くことを強くお勧めします。よろしくお願いします。
ルーティング
Fastifyのコア原則の1つは、そのルーティング機能です。このセクションで定義されている型のほとんどは、Fastifyインスタンスの.route
および.get/.post/.etc
メソッドによって内部的に使用されます。
fastify.RouteHandlerMethod< RawServer, RawRequest, RawReply, RequestGeneric, ContextConfig>
ルートハンドラーメソッドの型宣言です。request
とreply
の2つの引数があり、それぞれFastifyRequest
とFastifyReply
によって型付けされます。ジェネリックパラメータは、これらの引数に渡されます。メソッドは、同期および非同期ハンドラーに対して、それぞれvoid
またはPromise<any>
を返します。
fastify.RouteOptions< RawServer, RawRequest, RawReply, RequestGeneric, ContextConfig>
RouteShorthandOptionsを拡張し、次の3つの必須プロパティを追加するインターフェース
- 単一のHTTPMethodまたはHTTPMethodsのリストに対応する
method
- ルートの文字列である
url
- ルートハンドラーメソッドである
handler
。詳細については、[RouteHandlerMethod][]を参照してください。
fastify.RouteShorthandMethod< RawServer, RawRequest, RawReply>
.get/.post/.etc
メソッドと組み合わせて使用する、3種類のショートカットルートメソッドのオーバーロード関数インターフェース。
fastify.RouteShorthandOptions< RawServer, RawRequest, RawReply, RequestGeneric, ContextConfig>
ルートのすべての基本オプションをカバーするインターフェース。このインターフェースの各プロパティはオプションであり、RouteOptionsおよびRouteShorthandOptionsWithHandlerインターフェースのベースとして機能します。
fastify.RouteShorthandOptionsWithHandler< RawServer, RawRequest, RawReply, RequestGeneric, ContextConfig>
このインターフェースは、RouteShorthandOptionsインターフェースに単一の必須プロパティhandler
を追加します。これは、RouteHandlerMethod型です。
パーサー
RawBody
string
またはBuffer
のいずれかのジェネリック型
fastify.FastifyBodyParser< RawBody, RawServer, RawRequest>
ボディパーサーメソッドを指定するための関数型定義。RawBody
ジェネリックを使用して、解析されるボディの型を指定します。
fastify.FastifyContentTypeParser< RawServer, RawRequest>
ボディパーサーメソッドを指定するための関数型定義。コンテンツは、RawRequest
ジェネリックを介して型付けされます。
fastify.AddContentTypeParser< RawServer, RawRequest>
addContentTypeParser
メソッドのオーバーロードインターフェース関数定義。parseAs
がopts
パラメータに渡された場合、定義は[FastifyBodyParser][]をparser
パラメータに使用します。それ以外の場合は、[FastifyContentTypeParser][].
を使用します。
fastify.hasContentTypeParser
特定のコンテンツタイプの型パーサーの存在を確認するためのメソッド
エラー
fastify.FastifyError
FastifyErrorは、ステータスコードと検証結果を含むカスタムエラーオブジェクトです。
Node.jsのError
型を拡張し、さらに2つのオプションのプロパティstatusCode: number
とvalidation: ValidationResult[]
を追加します。
fastify.ValidationResult
ルート検証は、内部的に高性能なJSONスキーマバリデーターであるAjvに依存しています。
このインターフェースは、FastifyErrorのインスタンスに渡されます。
フック>| void
onRequest
は、リクエストライフサイクルで最初に実行されるフックです。前のフックはなく、次のフックはpreParsing
になります。
注意:onRequest
フックでは、ボディの解析がpreHandler
フックの前に行われるため、request.bodyは常にnullになります。
fastify.preParsingHookHandler< RawServer, RawRequest, RawReply, RequestGeneric, ContextConfig>(request: FastifyRequest, reply: FastifyReply, done: (err?: FastifyError) => void): Promise\<unknown>| void
preParsing
は、リクエストライフサイクルで2番目に実行されるフックです。前のフックはonRequest
であり、次のフックはpreValidation
になります。
注意:preParsing
フックでは、ボディの解析がpreValidation
フックの前に行われるため、request.bodyは常にnullになります。
注意:返されたストリームにreceivedEncodedLength
プロパティも追加する必要があります。このプロパティは、リクエストペイロードをContent-Length
ヘッダー値と正しく一致させるために使用されます。理想的には、このプロパティは受信したチャンクごとに更新する必要があります。
fastify.preValidationHookHandler< RawServer, RawRequest, RawReply, RequestGeneric, ContextConfig>(request: FastifyRequest, reply: FastifyReply, done: (err?: FastifyError) => void): Promise\<unknown>| void
preValidation
は、リクエストライフサイクルで3番目に実行されるフックです。前のフックはpreParsing
であり、次のフックはpreHandler
になります。
fastify.preHandlerHookHandler< RawServer, RawRequest, RawReply, RequestGeneric, ContextConfig>(request: FastifyRequest, reply: FastifyReply, done: (err?: FastifyError) => void): Promise\<unknown>| void
preHandler
は、リクエストライフサイクルで4番目に実行されるフックです。前のフックはpreValidation
であり、次のフックはpreSerialization
になります。
fastify.preSerializationHookHandler< PreSerializationPayload, RawServer, RawRequest, RawReply, RequestGeneric, ContextConfig>(request: FastifyRequest, reply: FastifyReply, payload: PreSerializationPayload, done: (err: FastifyError | null, res?: unknown) => void): Promise\<unknown>| void
preSerialization
はリクエストライフサイクルで5番目に実行されるフックです。前のフックは preHandler
で、次のフックは onSend
です。
注:ペイロードが文字列、Buffer、ストリーム、またはnullの場合、このフックは呼び出されません。
fastify.onSendHookHandler< OnSendPayload, RawServer, RawRequest, RawReply, RequestGeneric, ContextConfig>(request: FastifyRequest, reply: FastifyReply, payload: OnSendPayload, done: (err: FastifyError | null, res?: unknown) => void): Promise\<unknown>| void
onSend
フックを使用してペイロードを変更できます。これはリクエストライフサイクルで6番目に実行されるフックです。前のフックは preSerialization
で、次のフックは onResponse
です。
注:ペイロードを変更する場合、文字列、Buffer、ストリーム、またはnullのみに変更できます。
fastify.onResponseHookHandler< RawServer, RawRequest, RawReply, RequestGeneric, ContextConfig>(request: FastifyRequest, reply: FastifyReply, done: (err?: FastifyError) => void): Promise\<unknown>| void
onResponse
はリクエストフックライフサイクルで7番目かつ最後のフックです。前のフックは onSend
で、次のフックはありません。
onResponseフックはレスポンスが送信されたときに実行されるため、クライアントにさらにデータを送信することはできません。ただし、たとえば統計情報を収集するために、外部サービスにデータを送信するのに役立ちます。
fastify.onErrorHookHandler< RawServer, RawRequest, RawReply, RequestGeneric, ContextConfig>(request: FastifyRequest, reply: FastifyReply, error: FastifyError, done: () => void): Promise\<unknown>| void
このフックは、カスタムエラーログを実行したり、エラーが発生した場合に特定のヘッダーを追加したりする必要がある場合に役立ちます。
エラーを変更することを目的としておらず、reply.sendを呼び出すと例外がスローされます。
このフックは、customErrorHandlerが実行された後、かつcustomErrorHandlerがエラーをユーザーに返送した場合にのみ実行されます(デフォルトのcustomErrorHandlerは常にエラーをユーザーに返送することに注意してください)。
注意:他のフックとは異なり、done関数にエラーを渡すことはサポートされていません。
fastify.onRouteHookHandler< RawServer, RawRequest, RawReply, RequestGeneric, ContextConfig>(opts: RouteOptions &{path: string; prefix: string }): Promise\<unknown>| void
新しいルートが登録されたときにトリガーされます。リスナーには、唯一のパラメーターとしてrouteOptionsオブジェクトが渡されます。インターフェイスは同期であるため、リスナーにコールバックは渡されません。
fastify.onRegisterHookHandler< RawServer, RawRequest, RawReply, Logger>(instance: FastifyInstance, done: (err?: FastifyError) => void): Promise\<unknown>| void
新しいプラグインが登録され、新しいカプセル化コンテキストが作成されたときにトリガーされます。このフックは、登録されたコードの前に実行されます。
このフックは、プラグインコンテキストが形成されたことを知る必要があり、その特定のコンテキストで操作したいプラグインを開発している場合に役立ちます。
注:このフックは、プラグインがfastify-plugin内にラップされている場合は呼び出されません。
fastify.onCloseHookHandler< RawServer, RawRequest, RawReply, Logger>(instance: FastifyInstance, done: (err?: FastifyError) => void): Promise\<unknown>| void
fastify.close() がサーバーを停止するために呼び出されたときにトリガーされます。これは、プラグインが「シャットダウン」イベントを必要とする場合、たとえばデータベースへのオープン接続を閉じる場合に役立ちます。