TypeScript
TypeScript
Fastify 框架是用原生 JavaScript 撰寫的,因此類型定義並不容易維護;然而,自從第 2 版以後,維護者和貢獻者都投入了大量的精力來改進類型。
類型系統在 Fastify 第 3 版中進行了更改。新的類型系統引入了泛型約束和預設值,以及定義 schema 類型的新方法,例如請求主體、查詢字串等等!由於團隊致力於改進框架和類型定義的協同作用,有時 API 的某些部分將不會被輸入類型,或者可能被錯誤地輸入。我們鼓勵您貢獻以幫助我們填補空白。只需確保在開始之前閱讀我們的 CONTRIBUTING.md
文件,以確保一切順利!
本節中的文件涵蓋 Fastify 3.x 版的類型。
插件可能包含或不包含類型。有關更多資訊,請參閱插件。我們鼓勵使用者發送 pull request 以改進類型支援。
🚨 別忘了安裝 @types/node
從範例中學習
學習 Fastify 類型系統的最佳方式是透過範例!以下四個範例應涵蓋最常見的 Fastify 開發案例。在範例之後,還有關於類型系統的更詳細文件。
開始使用
此範例將讓您開始使用 Fastify 和 TypeScript。它會產生一個空白的 http Fastify 伺服器。
建立一個新的 npm 專案,安裝 Fastify,並安裝 typescript 和 Node.js 類型作為對等相依性
npm init -y
npm i fastify
npm i -D typescript @types/node將以下行添加到
package.json
的"scripts"
部分{
"scripts": {
"build": "tsc -p tsconfig.json",
"start": "node index.js"
}
}初始化一個 TypeScript 設定檔
npx tsc --init
或使用推薦的其中一個設定檔。
注意:在 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 中開啟一個 issue執行
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
、如何指定路由 schema 等等!
有關使用 TypeScript 初始化 Fastify 的更多範例 (例如啟用 HTTP2),請查看此處的詳細 API 區段 這裡
使用泛型
類型系統嚴重依賴泛型屬性來提供最準確的開發體驗。雖然有些人可能會覺得額外負擔有點麻煩,但這種權衡是值得的!此範例將深入探討如何為路由 schema 和位於路由層級 request
物件上的動態屬性實作泛型類型。
如果您沒有完成先前的範例,請按照步驟 1-4 進行設定。
在
index.ts
內,定義三個介面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 };
}使用這三個介面,定義一個新的 API 路由並將它們作為泛型傳遞。速記路由方法 (即
.get
) 接受一個泛型物件RouteGenericInterface
,其中包含五個命名屬性:Body
、Querystring
、Params
、Headers
和Reply
。介面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!
但等等,還有更多!泛型介面也可用於路由層級 hook 方法內。透過新增
preValidation
hook 來修改先前的路由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!`
})建置並執行,並使用設定為非
admin
的任何值的username
查詢字串選項進行查詢。API 現在應傳回 HTTP 500 錯誤{"statusCode":500,"error":"Internal Server Error","message":"Must be admin"}
🎉 做得好,現在您可以為每個路由定義介面,並擁有嚴格輸入類型的請求和回覆實例。Fastify 類型系統的其他部分依賴泛型屬性。請務必參考下方詳細的類型系統文件,以了解更多可用資訊。
JSON Schema
為了驗證您的請求和回應,您可以使用 JSON Schema 檔案。如果您還不知道,為您的 Fastify 路由定義 schema 可以增加其吞吐量!請查看驗證和序列化文件以取得更多資訊。
它還具有在您的處理常式 (包括預先驗證等) 中使用已定義類型的優點。
以下是一些關於如何實現這一點的選項。
Fastify 類型提供器
Fastify 提供兩個封裝 json-schema-to-ts
和 typebox
的套件
以及由第三方提供的 zod
包裝器,稱為 fastify-type-provider-zod
它們簡化了 schema 驗證設定,您可以在類型提供器頁面中閱讀有關它們的更多資訊。
以下是如何在使用或不使用類型提供器的情況下,使用 typebox
、json-schema-to-typescript
和 json-schema-to-ts
套件設定 schema 驗證的方法。
TypeBox
一個用於一次建置類型和 schema 的有用程式庫是 TypeBox。使用 TypeBox,您可以在程式碼內定義 schema,並根據需要直接將它們用作類型或 schema。
當您想要將其用於驗證 fastify 路由中的某些 payload 時,您可以按如下方式進行
在您的專案中安裝
typebox
。npm i @sinclair/typebox
使用
Type
定義您需要的 schema,並使用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>在定義路由時,使用定義的類型和 schema
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 為我們的路由定義類型和 schema。許多使用者已經在使用 JSON Schema 來定義這些屬性,幸運的是,有一種方法可以將現有的 JSON Schema 轉換為 TypeScript 介面!
如果您沒有完成「開始使用」範例,請返回並先按照步驟 1-4 進行。
安裝
json-schema-to-typescript
模組npm i -D json-schema-to-typescript
建立一個名為
schemas
的新資料夾,並新增兩個檔案headers.json
和querystring.json
。將以下 schema 定義複製並貼到各自的檔案中{
"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"]
}將
compile-schemas
指令碼新增到 package.json
{
"scripts": {
"compile-schemas": "json2ts -i schemas -o types"
}
}
json2ts
是 json-schema-to-typescript
中包含的 CLI 公用程式。schemas
是輸入路徑,而 types
是輸出路徑。5. 執行 npm run compile-schemas
。應該會在 types
目錄中建立兩個新檔案。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}`)
})
請特別注意此檔案頂部的 import。它可能看起來很多餘,但您需要 import schema 檔案和產生的介面。
做得好!現在您可以同時使用 JSON Schema 和 TypeScript 定義。
json-schema-to-ts
如果您不想從 schema 產生類型,但想要直接從程式碼中使用它們,可以使用套件 json-schema-to-ts。
您可以將其安裝為開發相依性。
npm i -D json-schema-to-ts
在您的程式碼中,您可以像一般物件一樣定義您的 schema。但請注意像模組文件中所解釋的那樣使其為 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
,您可以從您的 schema 建構類型並在您的處理常式中使用它。
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 最顯著的特色之一是其豐富的外掛程式生態系統。外掛程式類型完全支援,並利用宣告合併模式。此範例分為三個部分:建立 TypeScript Fastify 外掛程式、為 Fastify 外掛程式建立類型定義,以及在 TypeScript 專案中使用 Fastify 外掛程式。
建立 TypeScript Fastify 外掛程式
初始化新的 npm 專案並安裝所需的相依性
npm init -y
npm i fastify fastify-plugin
npm i -D typescript @types/node將
build
指令碼新增至package.json
檔案的"scripts"
區段,並將'index.d.ts'
新增至"types"
區段{
"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-plugin建立兩個檔案
index.js
和index.d.ts
修改 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
匯入外掛程式,就一切就緒了 -- 但使用者應注意一個例外。
Fastify 外掛程式使用宣告合併來修改現有的 Fastify 類型介面 (如需更多詳細資訊,請查看前兩個範例)。宣告合併並不是很聰明,也就是說,如果外掛程式的類型定義在 TypeScript 解譯器的範圍內,則無論外掛程式是否正在使用,都會包含外掛程式類型。這是使用 TypeScript 的一個不幸限制,而且目前無法避免。
不過,有一些建議可以協助改善這種體驗
- 請確保在ESLint 中啟用
no-unused-vars
規則,並且實際載入了任何匯入的外掛程式。 - 如果您啟用了
@typescript-eslint/no-floating-promises
,請仔細檢查您的 ESLint 設定是否包含typescript-eslint no-floating-promises allowForKnownSafePromises 文件
中描述的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 一起內嵌使用。例如
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
}
Vanilla JavaScript 中的程式碼完成
Vanilla JavaScript 可以使用已發佈的類型來提供程式碼完成 (例如Intellisense),方法是遵循TypeScript JSDoc 參考。
例如
/** @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 回應類型
限制:http.ServerResponse
、http2.Http2ServerResponse
由以下項目強制執行:RawServer
Logger
Fastify 記錄公用程式
由以下項目強制執行:RawServer
RawBody
內容類型剖析器方法的泛型參數。
限制:string | Buffer
Fastify
fastify< RawRequest, RawReply, Logger>(opts?: FastifyServerOptions): FastifyInstance
主要的 Fastify API 方法。預設會建立 HTTP 伺服器。利用辨別聯集和多載方法,類型系統會根據傳遞至方法的選項自動推斷正在建立哪種伺服器類型 (http、https 或 http2) (請參閱以下範例以取得更多資訊)。它也支援廣泛的泛型類型系統,讓使用者能夠擴充基礎的 Node.js 伺服器、請求和回覆物件。此外,Logger
泛型可用於自訂記錄類型。請參閱以下範例和泛型分解以取得更多資訊。
範例 1:標準 HTTP 伺服器
不需要指定 Server
泛型,因為類型系統會預設為 HTTP。
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' - 在設定 Fastify HTTPS 伺服器之前,請執行以下步驟以建立
key.pem
和cert.pem
檔案:
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 伺服器類型有兩種:不安全和安全。兩者都需要在 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
欄位進行設定。如果您需要的屬性沒有公開,請開啟一個 Issue 給 Pino
,或將預先設定的外部 Pino 實例(或任何其他相容的記錄器)作為臨時修復程式透過相同的欄位傳遞給 Fastify。這也允許建立自訂序列化程式,請參閱 記錄 文件以取得更多資訊。
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
泛型參數會透過該方法傳遞。
請參閱主要的 fastify 方法類型定義章節,以取得使用 TypeScript 實例化 Fastify 伺服器的範例。
fastify.FastifyInstance< RawServer, RawRequest, RequestGeneric, Logger>
表示 Fastify 伺服器物件的介面。這是從 fastify()
方法傳回的伺服器實例。此類型是一個介面,因此如果您的程式碼使用 decorate
方法,則可以透過 宣告合併 進行擴充。
透過使用泛型級聯,附加到實例的所有方法都會繼承實例化的泛型屬性。這表示透過指定伺服器、請求或回應類型,所有方法都會知道如何輸入這些物件。
請參閱主要的 從範例學習 章節以取得詳細指南,或更簡化的 fastify 方法範例,以取得有關此介面的其他詳細資訊。
請求
fastify.FastifyRequest< RequestGeneric, RawServer, RawRequest>
此介面包含 Fastify 請求物件的屬性。此處新增的屬性會忽略請求物件的類型(http 或 http2),並忽略它所服務的路由層級;因此,在 GET 請求內部呼叫 request.body
不會擲回錯誤(但祝您好運傳送具有主體的 GET 請求 😉)。
如果您需要在 FastifyRequest
物件中新增自訂屬性(例如,當使用[decorateRequest
][DecorateRequest]方法時),您需要在這個介面上使用宣告合併。
在 FastifyRequest
章節中提供了一個基本範例。如需更詳細的範例,請參閱「從範例學習」章節:外掛程式
範例
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
。它們各自的類型可透過此介面指定。它是一個具名屬性介面,使開發人員可以忽略他們不想指定的屬性。所有省略的屬性都會預設為 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 結構描述。
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
回應
fastify.FastifyReply<RequestGeneric, RawServer, RawRequest, RawReply, ContextConfig>
此介面包含 Fastify 新增至標準 Node.js 回應物件的自訂屬性。此處新增的屬性會忽略回應物件的類型(http 或 http2)。
如果您需要在 FastifyReply 物件中新增自訂屬性(例如,當使用 decorateReply
方法時),您需要在這個介面上使用宣告合併。
在 FastifyReply
章節中提供了一個基本範例。如需更詳細的範例,請參閱「從範例學習」章節:外掛程式
範例
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
外掛程式
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 方法。
Register
fastify.FastifyRegister(plugin: FastifyPluginCallback, opts: FastifyRegisterOptions)
fastify.FastifyRegister(plugin: FastifyPluginAsync, opts: FastifyRegisterOptions)
fastify.FastifyRegister(plugin: FastifyPlugin, opts: FastifyRegisterOptions)
此類型介面指定了 fastify.register()
方法的類型。此類型介面傳回一個具有底層泛型 Options
的函數簽名,其預設值為 FastifyPluginOptions。當呼叫此函數時,它會從 FastifyPlugin 參數推斷此泛型,因此無需指定底層泛型。options 參數是外掛程式選項和兩個額外可選屬性的交集: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
泛型和一個未導出的介面 RegisterOptions
的交集,該介面指定了兩個可選屬性:prefix: string
和 logLevel
: LogLevel。此類型也可以指定為一個函式,該函式傳回先前描述的交集。
Logger
請查看 指定記錄器類型 的範例,以取得有關指定自訂記錄器的更多詳細資訊。
fastify.FastifyLoggerOptions< RawServer, RawRequest, RawReply>
內部 Fastify 記錄器的介面定義。它模仿了 Pino.js 記錄器。當透過伺服器選項啟用時,請按照一般的 記錄器 文件使用它。
fastify.FastifyLogFn
一個重載函數介面,實作 Fastify 呼叫記錄方法的方式。此介面會傳遞到 FastifyLoggerOptions 物件上所有相關的記錄層級屬性。
fastify.LogLevel
以下項目的聯集類型:'info' | 'error' | 'debug' | 'fatal' | 'warn' | 'trace'
Context
內容類型定義與類型系統的其他高度動態的部分類似。路由內容在路由處理常式方法中可用。
fastify.FastifyRequestContext
一個具有單一必要屬性 config
的介面,其預設設定為 unknown
。可以使用泛型或重載來指定。
此類型定義可能不完整。如果您正在使用它,並且可以提供更多關於如何改進定義的詳細資訊,我們強烈建議您在主要的 fastify/fastify 儲存庫中開啟一個問題。預先感謝!
fastify.FastifyReplyContext
一個具有單一必要屬性 config
的介面,其預設設定為 unknown
。可以使用泛型或重載來指定。
此類型定義可能不完整。如果您正在使用它,並且可以提供更多關於如何改進定義的詳細資訊,我們強烈建議您在主要的 fastify/fastify 儲存庫中開啟一個問題。預先感謝!
Routing
Fastify 的核心原則之一是其路由功能。此章節中定義的大多數類型都由 Fastify 實例的 .route
和 .get/.post/.etc
方法在底層使用。
fastify.RouteHandlerMethod< RawServer, RawRequest, RawReply, RequestGeneric, ContextConfig>
路由處理常式方法的類型宣告。有兩個引數,request
和 reply
,它們分別由 FastifyRequest
和 FastifyReply
類型化。泛型參數會傳遞到這些引數。該方法會傳回 void
或 Promise<any>
,分別用於同步和非同步處理常式。
fastify.RouteOptions< RawServer, RawRequest, RawReply, RequestGeneric, ContextConfig>
一個擴展 RouteShorthandOptions 並新增以下三個必要屬性的介面
method
對應於單一 HTTPMethod 或 HTTPMethods 的清單url
路由的字串handler
路由處理常式方法,請參閱[RouteHandlerMethod][]以取得更多詳細資訊
fastify.RouteShorthandMethod< RawServer, RawRequest, RawReply>
一個重載的函數介面,用於三種簡寫路由方法,以便與 .get/.post/.etc
方法結合使用。
fastify.RouteShorthandOptions< RawServer, RawRequest, RawReply, RequestGeneric, ContextConfig>
一個涵蓋路由所有基本選項的介面。此介面上的每個屬性都是可選的,並且它是 RouteOptions 和 RouteShorthandOptionsWithHandler 介面的基礎。
fastify.RouteShorthandOptionsWithHandler< RawServer, RawRequest, RawReply, RequestGeneric, ContextConfig>
此介面向 RouteShorthandOptions 介面新增了一個單一必要屬性 handler
,其類型為 RouteHandlerMethod
Parsers
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
類型,並新增了兩個額外的可選屬性:statusCode: number
和 validation: ValidationResult[]
。
fastify.ValidationResult
路由驗證在內部依賴 Ajv,這是一個高效能的 JSON Schema 驗證器。
此介面會傳遞給 FastifyError 的實例。
Hook
fastify.onRequestHookHandler< RawServer, RawRequest, RawReply, RequestGeneric, ContextConfig>(request: FastifyRequest, reply: FastifyReply, done: (err?: FastifyError) => void): Promise<unknown>| void
onRequest
是請求生命週期中第一個執行的 Hook。之前沒有 Hook,下一個 Hook 將是 preParsing
。
注意:在 onRequest
Hook 中,request.body 將始終為 null,因為 body 解析發生在 preHandler
Hook 之前。
fastify.preParsingHookHandler< RawServer, RawRequest, RawReply, RequestGeneric, ContextConfig>(request: FastifyRequest, reply: FastifyReply, done: (err?: FastifyError) => void): Promise<unknown>| void
preParsing
是請求生命週期中第二個執行的 Hook。先前的 Hook 是 onRequest
,下一個 Hook 將是 preValidation
。
注意:在 preParsing
Hook 中,request.body 將始終為 null,因為 body 解析發生在 preValidation
Hook 之前。
注意:您還應該將 receivedEncodedLength
屬性新增至返回的 stream。此屬性用於正確地將請求 payload 與 Content-Length
標頭值相匹配。理想情況下,應該在每個接收到的 chunk 上更新此屬性。
fastify.preValidationHookHandler< RawServer, RawRequest, RawReply, RequestGeneric, ContextConfig>(request: FastifyRequest, reply: FastifyReply, done: (err?: FastifyError) => void): Promise<unknown>| void
preValidation
是請求生命週期中第三個執行的 Hook。先前的 Hook 是 preParsing
,下一個 Hook 將是 preHandler
。
fastify.preHandlerHookHandler< RawServer, RawRequest, RawReply, RequestGeneric, ContextConfig>(request: FastifyRequest, reply: FastifyReply, done: (err?: FastifyError) => void): Promise<unknown>| void
preHandler
是請求生命週期中第四個執行的 Hook。先前的 Hook 是 preValidation
,下一個 Hook 將是 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
是請求生命週期中第五個執行的 Hook。先前的 Hook 是 preHandler
,下一個 Hook 將是 onSend
。
注意:如果 payload 是字串、Buffer、stream 或 null,則不會呼叫此 Hook。
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
Hook 更改 payload。它是請求生命週期中第六個執行的 Hook。先前的 Hook 是 preSerialization
,下一個 Hook 將是 onResponse
。
注意:如果您更改 payload,則只能將其更改為字串、Buffer、stream 或 null。
fastify.onResponseHookHandler< RawServer, RawRequest, RawReply, RequestGeneric, ContextConfig>(request: FastifyRequest, reply: FastifyReply, done: (err?: FastifyError) => void): Promise<unknown>| void
onResponse
是請求 Hook 生命週期中的第七個也是最後一個 Hook。先前的 Hook 是 onSend
,沒有下一個 Hook。
當已發送回應時,會執行 onResponse Hook,因此您將無法向用戶端發送更多資料。不過,它對於向外部服務發送資料很有用,例如收集統計資料。
fastify.onErrorHookHandler< RawServer, RawRequest, RawReply, RequestGeneric, ContextConfig>(request: FastifyRequest, reply: FastifyReply, error: FastifyError, done: () => void): Promise<unknown>| void
如果您需要執行一些自訂錯誤記錄或在發生錯誤時新增一些特定的標頭,此 Hook 非常有用。
它不適用於變更錯誤,並且呼叫 reply.send 將會擲回例外狀況。
只有在 customErrorHandler 執行之後,且僅當 customErrorHandler 將錯誤發送回使用者時,才會執行此 Hook (請注意,預設的 customErrorHandler 始終將錯誤發送回使用者)。
注意:與其他 Hook 不同,不支援將錯誤傳遞給 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
在註冊新外掛程式並建立新的封裝環境時觸發。此 Hook 將在註冊的程式碼之前執行。
如果您正在開發需要知道何時形成外掛程式環境的外掛程式,並且您想要在該特定環境中運作,則此 Hook 非常有用。
注意:如果外掛程式包裝在 fastify-plugin 內,則不會呼叫此 Hook。
fastify.onCloseHookHandler< RawServer, RawRequest, RawReply, Logger>(instance: FastifyInstance, done: (err?: FastifyError) => void): Promise<unknown>| void
當調用 fastify.close() 以停止伺服器時觸發。當外掛程式需要「關閉」事件時,例如關閉到資料庫的開啟連線時,此功能非常有用。