TypeScript
Fastify 框架使用纯 JavaScript 编写,因此类型定义的维护并不容易;然而,从版本 2 开始,维护者和贡献者已经付出了巨大的努力来改进类型。
在 Fastify 版本 3 中更改了类型系统。新的类型系统引入了泛型约束和默认值,并且提供了一种新方法来定义模式类型,例如请求体、查询字符串等!随着团队致力于提高框架与类型定义的协同作用,有时 API 的某些部分可能没有类型或类型不正确。我们鼓励您 贡献 来帮助我们填补这些空白。请务必在开始之前阅读我们的
CONTRIBUTING.md
文件以确保一切顺利!
本节文档涵盖 Fastify 版本 3.x 的类型定义
插件可能包含或不包含类型定义。有关更多信息,请参阅 插件。我们鼓励用户提交拉取请求来改进类型支持。
🚨 别忘了安装 @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 中打开一个问题。 - 运行
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
中,定义三个接口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'];
// 对请求数据进行操作
// 使用 .statusCode/.code 调用链允许类型缩小。例如:
// 这个可以工作
reply.code(200).send({ success: true });
// 但是这个会引发类型错误
reply.code(200).send('uh-oh');
// 即使对于通配符也有效
reply.code(404).send({ error: 'Not found' });
return `已登录!`
})
- 使用
npm run build
和npm run start
构建并运行服务器代码 - 查询 API
curl localhost:8080/auth?username=admin&password=Password123!
它应该返回 已登录!
6. 但等等,还有更多!通用接口也可以在路由级别的钩子方法中使用。通过添加一个 preValidation
钩子来修改之前的路由:
server.get<{
Querystring: IQuerystring,
Headers: IHeaders,
Reply: IReply
}>('/auth', {
preValidation: (request, reply, done) => {
const { username, password } = request.query
done(username !== 'admin' ? new Error('必须是管理员') : undefined) // 只验证 `admin` 账户
}
}, async (request, reply) => {
const customerHeader = request.headers['h-Custom']
// 对请求数据进行处理
return `已登录!`
})
- 构建并运行,然后使用不同于
admin
的username
查询字符串选项来查询 API。API 现在应该返回一个 HTTP 500 错误{"statusCode":500,"error":"内部服务器错误","message":"必须是管理员"}
🎉 很好,现在你可以为每个路由定义接口,并拥有严格类型化的请求和响应实例。Fastify 类型系统的其他部分依赖于泛型属性。请参考下面的详细类型系统文档以了解更多信息。
JSON Schema
为了验证您的请求和响应,您可以使用JSON Schema文件。如果您还不知道的话,为Fastify路由定义模式可以提高它们的吞吐量!更多相关信息请参阅验证与序列化文档。
此外,它还具有在处理程序中使用已定义类型的优点(包括预验证等)。
以下是一些实现此功能的方法。
Fastify 类型提供器
Fastify 提供了两个包装 json-schema-to-ts
和 typebox
的包:
还有一个由第三方提供的名为fastify-type-provider-zod
的 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) => { // `name` 和 `mail` 类型会自动推断出来 const { name, mail } = request.body; reply.status(200).send({ name, mail }); } )
json-schema-to-typescript
在上一个示例中,我们使用了 Typebox 来定义路由的类型和模式。许多用户已经在使用 JSON Schema 来定义这些属性,并且幸运的是有一种方法可以将现有的 JSON Schema 转换为 TypeScript 接口!
- 如果您没有完成“入门”示例,请返回并先执行步骤 1-4。
- 安装
json-schema-to-typescript
模块:
npm i -D json-schema-to-typescript
- 创建一个名为
schemas
的新文件夹,并添加两个文件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
目录中创建两个新的文件。
6. 更新 index.ts
以包含以下代码:
import fastify from 'fastify'
// 正常导入 json 模式
import QuerystringSchema from './schemas/querystring.json'
import HeadersSchema from './schemas/headers.json'
// 导入生成的接口
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('必须是管理员') : undefined)
}
// 或者如果使用异步方法
// preValidation: async (request, reply) => {
// const { username, password } = request.query
// if (username !== "admin") throw new Error("必须是管理员");
// }
}, async (request, reply) => {
const customerHeader = request.headers['h-Custom']
// 对请求数据进行处理
return `已登录!`
})
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(`服务器正在监听 ${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; // 不要忘记使用 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 的类型为
{
[x: string]: unknown;
description?: string;
done?: boolean;
name: string;
}
*/
request.body.name // 不会抛出类型错误
request.body.notthere // 会抛出类型错误
reply.status(201).send();
},
);
插件
Fastify 最具辨识度的功能之一是其庞大的插件生态系统。Fastify 支持各种类型的插件,并利用了声明合并模式(声明合并 )。本示例分为三个部分:创建一个 TypeScript Fastify 插件、为 Fastify 插件创建类型定义,以及在 TypeScript 项目中使用 Fastify 插件。
创建一个TypeScript Fastify插件
- 初始化一个新的npm项目并安装所需的依赖项
npm init -y
npm i fastify fastify-plugin
npm i -D typescript @types/node
- 在
package.json
文件的"scripts"
部分添加一个build
脚本,并在"types"
部分添加'index.d.ts'
{ "types": "index.d.ts", "scripts": { "build": "tsc -p tsconfig.json" } }
3. 初始化一个TypeScript配置文件:
```bash
npx typescript --init
文件生成后,在 "compilerOptions"
对象中启用 "declaration"
选项。
{
"compilerOptions": {
"declaration": true
}
}
- 创建一个
index.ts
文件 - 这个文件将包含插件代码 - 将以下代码添加到
index.ts
import { FastifyPluginCallback, FastifyPluginAsync } from 'fastify'
import fp from 'fastify-plugin'
// 使用声明合并,向适当的 fastify 接口添加您的插件属性
// 如果在这里定义了属性类型,则在调用 decorate{,Request,Reply} 时会进行类型检查
declare module 'fastify' {
interface FastifyRequest {
myPluginProp: string
}
interface FastifyReply {
myPluginProp: number
}
}
// 定义选项
export interface MyPluginOptions {
myPluginOption: string
}
// 使用回调定义插件
const myPluginCallback: FastifyPluginCallback<MyPluginOptions> = (fastify, options, done) => {
fastify.decorateRequest('myPluginProp', 'super_secret_value')
fastify.decorateReply('myPluginProp', options.myPluginOption)
done()
}
// 使用 promise 定义插件
const myPluginAsync: FastifyPluginAsync<MyPluginOptions> = async (fastify, options) => {
fastify.decorateRequest('myPluginProp', 'super_secret_value')
fastify.decorateReply('myPluginProp', options.myPluginOption)
}
// 使用 fastify-plugin 导出插件
export default fp(myPluginCallback, '3.x')
或者
// export default fp(myPluginAsync, '3.x')
- 运行
npm run build
编译插件代码,生成 JavaScript 源文件和类型定义文件。 - 完成插件后,您可以发布到 npm 或本地使用。
您不需要将插件发布到 npm 才能使用它。您可以在 Fastify 项目中包含它,并像引用任何代码一样引用它!作为 TypeScript 用户,请确保声明覆盖存在于您的项目编译过程中会包含的某个位置,以便 TypeScript 解释器可以处理它。
注意:锚点链接中的“publish to npm”需要根据上下文翻译为“发布到-npm”,并替换为实际中文标题对应的格式。
为 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
const fp = require('fastify-plugin')
function myPlugin (instance, options, done) {
// 使用名为 myPluginFunc 的自定义函数装饰 Fastify 实例
instance.decorate('myPluginFunc', (input) => {
return input.toUpperCase()
})
done()
}
module.exports = fp(myPlugin, {
fastify: '5.x',
name: 'my-plugin' // 此名称由 fastify-plugin 用于推导属性名
})
- 打开
index.d.ts
并添加以下代码:
import { FastifyPluginCallback } from 'fastify'
interface PluginOptions {
//...
}
// 可选地,您可以添加任何其他导出。
// 在这里我们导出了我们添加的装饰器。
export interface myPluginFunc {
(input: string): string
}
// 最重要的是,使用声明合并将自定义属性添加到 Fastify 类型系统中
declare module 'fastify' {
interface FastifyInstance {
myPluginFunc: myPluginFunc
}
}
// fastify-plugin 自动添加命名导出,因此请确保也添加以下类型声明
// 变量名由 `options.name` 属性派生而来,如果缺少 `module.exports.myPlugin`
export const myPlugin: FastifyPluginCallback<PluginOptions>
// fastify-plugin 自动在导出的插件上添加 `.default` 属性。请参阅下方注释
export default myPlugin
注意: fastify-plugin
(https://github.com/fastify/fastify-plugin )版本 2.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
规则,并确保导入的所有插件都被实际加载。 - 使用诸如 depcheck 或 npm-check 这样的模块来验证项目中是否使用了插件依赖项。
请注意,使用 require
将无法正确加载类型定义,并可能导致类型错误。
TypeScript 只能识别直接导入代码中的类型,这意味着您可以将 require 与 import 结合使用。例如:
import 'plugin' // 这里会触发类型扩展。
fastify.register(require('plugin'))
import plugin from 'plugin' // 这里会触发类型扩展。
fastify.register(plugin)
或者在 tsconfig 中显式配置
{
"types": ["plugin"] // 我们强制 TypeScript 导入这些类型
}
纯JavaScript中的代码补全
纯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('运行中') })
- 使用解构语法可以访问类型:
import fastify, { FastifyInstance } from 'fastify' const f: FastifyInstance = fastify() f.listen({ port: 8080 }, () => { console.log('运行中') })
- 解构也可以用于主 API 方法:
import { fastify, FastifyInstance } from 'fastify' const f: FastifyInstance = fastify() f.listen({ port: 8080 }, () => { console.log('运行中') })
-
import * as Fastify from 'fastify'
- 解决了类型,并且可以通过点表示法访问
- 调用主 Fastify API 方法需要稍微不同的语法(见示例)
- 示例:
import * as Fastify from 'fastify' const f: Fastify.FastifyInstance = Fastify.fastify() f.listen({ port: 8080 }, () => { console.log('运行中') })
-
const fastify = require(‘fastify’)
- 这种语法有效,可以按预期导入 fastify;但是类型将 不会 被解析
- 示例:
const fastify = require('fastify') const f = fastify() f.listen({ port: 8080 }, () => { console.log('运行中') })
- 解构语法支持,并且可以正确解析类型
const { fastify } = require('fastify') const f = fastify(); f.listen({ port: 8080 }, () => { console.log('运行中'); });
泛型
许多类型定义共享相同的泛型参数;它们都在本节中详细记录。
大多数定义依赖于 @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
用于 content-type-parser 方法的泛型参数。
约束条件:string | Buffer
Fastify
(由于提供的原文仅包含一个标题,没有具体内容和链接,因此无法进行进一步的锚点替换和其他部分的翻译。如果有更多内容需要翻译,请提供完整文档。)
fastify< RawRequest, RawReply, Logger>(opts?: FastifyServerOptions): FastifyInstance
Fastify 主 API 方法。默认情况下创建一个 HTTP 服务器。利用区分联合类型和重载方法,类型系统会根据传递给该方法的选项自动推断出正在创建的是哪种类型的服务器(HTTP、HTTPS 或者 HTTP2)。此外,它还支持广泛的泛型类型系统,允许用户扩展底层 Node.js Server、Request 和 Reply 对象。另外,Logger
泛型用于自定义日志类型。请参阅下面的示例和泛型分解以获取更多信息。
示例 1:标准 HTTP 服务器
无需指定 Server
泛型,因为默认为 HTTP 类型。
import fastify from 'fastify'
const server = fastify()
查看通过示例学习 - 入门 获取更详细的 HTTP 服务器教程。
示例 2:HTTPS 服务器
- 创建来自
@types/node
和fastify
的以下导入:
import fs from 'node:fs'
import path from 'node: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://localhost:8080
来测试您的服务器。
示例 3:HTTP2 服务器
有两种类型的 HTTP2 服务器,不安全的和安全的。两者都需要在 options
对象中将 http2
属性设置为 true
。使用 https
属性来创建一个安全的 http2 服务器;省略 https
属性将会创建一个不安全的 http2 服务器。
const insecureServer = fastify({ http2: true })
const secureServer = fastify({
http2: true,
https: {} // 使用来自 HTTPS 部分的 `key.pem` 和 `cert.pem` 文件
})
有关使用 HTTP2 的更多详细信息,请参阅 Fastify HTTP2 文档页面。
示例4:扩展HTTP服务器
不仅可以指定服务器类型,还可以指定请求和响应的类型。 因此,允许您指定特殊属性、方法等!当在服务器实例化时指定自定义类型后, 该自定义类型将在所有进一步的自定义类型的实例中可用。
import fastify from 'fastify'
import http from 'node: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 知道这是一个字符串,因为 `customRequest` 接口的定义
return someValue.toUpperCase()
})
示例5:指定日志类型
Fastify 使用 Pino 日志库。从 pino@7
开始,
所有属性都可以通过构造 Fastify 实例时的 logger
字段进行配置。
如果需要的属性没有暴露,请在 Pino
上打开一个 Issue,或者传递一个预配置的外部 Pino 实例(或其他兼容的日志库)作为临时解决方案。这还允许创建自定义序列化器,
有关更多信息请参阅 日志记录 文档。
import fastify from 'fastify'
const server = fastify({
logger: {
level: 'info',
redact: ['x-userinfo'],
messageKey: 'message'
}
})
server.get('/', async (request, reply) => {
server.log.info('日志消息')
return '另一个消息'
})
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.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.HTTPMethods
[src](https://github.com/fastify/fastify/blob/main/types/utils.d.ts#L8)
Union type of: `'DELETE' | 'GET' | 'HEAD' | 'PATCH' | 'POST' | 'PUT' |
'OPTIONS'`
##### fastify.RawServerBase
[src](https://github.com/fastify/fastify/blob/main/types/utils.d.ts#L13)
Dependent on `@types/node` modules `http`, `https`, `http2`
Union type of: `http.Server | https.Server | http2.Http2Server |
http2.Http2SecureServer`
##### fastify.RawServerDefault
[src](https://github.com/fastify/fastify/blob/main/types/utils.d.ts#L18)
Dependent on `@types/node` modules `http`
Type alias for `http.Server`
---
##### fastify.FastifyServerOptions< [RawServer][rawservergeneric], [Logger][loggergeneric]>
[src](https://github.com/fastify/fastify/blob/main/fastify.d.ts#L29)
An interface of properties used in the instantiation of the Fastify server. Is
used in the main [`fastify()`][fastify] method. The `RawServer` and `Logger`
generic parameters are passed down through that method.
See the main [fastify][fastify] method type definition section for examples on
instantiating a Fastify server with TypeScript.
fastify.FastifyInstance< RawServer, RawRequest, RequestGeneric, Logger>
表示 Fastify 服务器对象的接口。这是从 fastify()
方法返回的服务器实例。此类型是一个接口,因此可以通过声明合并(declaration merging )进行扩展,如果你的代码使用了 decorate
方法。
通过泛型级联,在实例上附加的所有方法都会继承从实例化时指定的通用属性。这意味着通过指定服务器、请求或响应类型,所有方法都将知道如何对这些对象进行类型推断。
查看主要的 示例学习 部分以获取详细指南,或者参阅更简化的 fastify 方法示例以获取此接口的更多细节。
请求
fastify.FastifyRequest< RequestGeneric, RawServer, RawRequest>
此接口包含 Fastify 请求对象的属性。这里的属性不考虑请求对象的类型(http vs http2)以及路由级别,因此在 GET 请求中调用 request.body
不会抛出错误(但尝试发送带有正文的 GET 请求可能不会成功 😉)。
如果您需要向 FastifyRequest
对象添加自定义属性(例如使用 [decorateRequest
][DecorateRequest] 方法时),您需要在此接口上使用声明合并。
在FastifyRequest
部分提供了一个基本示例。对于更详细的示例,请参阅 Learn By Example 部分:
插件
示例
import fastify from 'fastify'
const server = fastify()
server.decorateRequest('someProp', 'hello!')
server.get('/', async (request, reply) => {
const { someProp } = request // 必须使用声明合并来添加此属性到请求接口中
return someProp
})
// 此声明必须在 TypeScript 解释器的作用域内才能生效
declare module 'fastify' {
interface FastifyRequest { // 您必须引用接口而不是类型
someProp: string
}
}
// 或者您可以使用以下方式为请求进行类型定义
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 // 现在 query 属性中存在 name 属性
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 'node:http'
import http2 from 'node: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
部分提供了一个基本示例。对于更详细的示例,请参阅 Learn By Example 部分:
插件
示例
import fastify from 'fastify'
const server = fastify()
server.decorateReply('someProp', 'world')
server.get('/', async (request, reply) => {
const { someProp } = reply // 必须使用声明合并来将此属性添加到回复接口中
return someProp
})
// 此声明必须在 TypeScript 解释器的作用域内才能生效
declare module 'fastify' {
interface FastifyReply { // 您必须引用接口而不是类型
someProp: string
}
}
fastify.RawReplyDefaultExpression< RawServer>
依赖于 @types/node
模块的 http
, https
, http2
泛型参数 RawServer
默认为 RawServerDefault
如果 RawServer
类型为 http.Server
或 https.Server
,则此表达式返回 http.ServerResponse
,否则返回 http2.Http2ServerResponse
。
import http from 'node:http'
import http2 from 'node:http2'
import { RawReplyDefaultExpression } from 'fastify'
RawReplyDefaultExpression<http.Server> // -> http.ServerResponse
RawReplyDefaultExpression<http2.Http2Server> // -> http2.Http2ServerResponse
插件
Fastify 允许用户通过插件扩展其功能。一个插件可以是一组路由、服务器装饰器或其他任何内容。要激活插件,请使用 fastify.register()
方法。
在为 Fastify 创建插件时,建议使用 fastify-plugin
模块。此外,在 Learn by Example 的 插件 部分提供了一个关于如何使用 TypeScript 和 Fastify 创建插件的指南。
fastify.FastifyPluginCallback< Options>
在 fastify.register()
方法中使用的接口方法定义。
fastify.FastifyPluginAsync< Options>
在 fastify.register()
方法中使用的异步接口方法定义。
fastify.FastifyPlugin< Options>
在 fastify.register()
方法中使用的接口方法定义。文档已弃用,建议使用 FastifyPluginCallback
和 FastifyPluginAsync
替代,因为通用的 FastifyPlugin
无法正确推断异步函数类型。
fastify.FastifyPluginOptions
一个松散类型的对象,用于将 fastify.register()
的 options
参数约束为一个对象。在创建插件时,定义其选项作为此接口的扩展(interface MyPluginOptions extends FastifyPluginOptions
),以便可以将其传递给注册方法。
注册
fastify.FastifyRegister(plugin: FastifyPluginCallback, opts: FastifyRegisterOptions)
fastify.FastifyRegister(plugin: FastifyPluginAsync, opts: FastifyRegisterOptions)
fastify.FastifyRegister(plugin: FastifyPlugin, opts: FastifyRegisterOptions)
此类型接口定义了
fastify.register()
方法的类型。该类型接口返回一个函数签名,其底层泛型 Options
默认为 FastifyPluginOptions。在调用此函数时,它会从 FastifyPlugin 参数中推断出这个泛型,因此不需要显式指定底层泛型。选项参数是插件选项和两个可选属性(prefix: string
和 logLevel
: LogLevel)的交集。FastifyPlugin
已废弃,请使用 FastifyPluginCallback
和 FastifyPluginAsync
替代。
以下是选项推断的实际示例:
const server = fastify()
const plugin: FastifyPluginCallback<{
option1: string;
option2: boolean;
}> = function (instance, opts, done) { }
server().register(plugin, {}) // 错误 - 选项对象缺少必需的属性
server().register(plugin, { option1: '', option2: true }) // 正确 - 选项对象包含必需的属性
请参阅示例学习部分,插件章节以获取更多关于在 Fastify 中创建 TypeScript 插件的详细示例。
fastify.FastifyRegisterOptions
此类型是 Options
泛型和一个未导出的接口 RegisterOptions
的交集,该接口指定了两个可选属性:prefix: string
和 logLevel
: LogLevel。此类型也可以指定为返回上述交集的一个函数。
日志记录器
请参阅 指定日志类型 示例,以获取更多关于指定自定义日志记录器的详细信息。
fastify.FastifyLoggerOptions< RawServer, RawRequest, RawReply>
内部 Fastify 日志记录器的接口定义。它模仿了 Pino.js 的日志记录器。通过服务器选项启用后,可以按照一般的 日志记录 文档使用。
fastify.FastifyLogFn
一个重载函数接口,实现了 Fastify 调用日志方法的两种方式。此接口传递给 FastifyLoggerOptions 对象上的所有相关日志级别属性。
fastify.LogLevel
联合类型:'info' | 'error' | 'debug' | 'fatal' | 'warn' | 'trace'
上下文
上下文类型定义类似于类型系统中其他高度动态的部分。路由上下文在路由处理方法中可用。
fastify.FastifyRequestContext
一个具有单个必需属性 config
的接口,默认设置为 unknown
。可以通过泛型或重载来指定该属性。
此类型定义可能是不完整的。如果您正在使用它并且可以提供更多关于如何改进定义的详细信息,我们强烈建议您在主 fastify/fastify 仓库中打开一个 issue。提前感谢您的贡献!
fastify.FastifyReplyContext
一个具有单个必需属性 config
的接口,默认设置为 unknown
。可以通过泛型或重载来指定该属性。
此类型定义可能是不完整的。如果您正在使用它并且可以提供更多关于如何改进定义的详细信息,我们强烈建议您在主 fastify/fastify 仓库中打开一个 issue。提前感谢您的贡献!
路由
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。
解析器
RawBody
一个通用类型,可以是 string
或 Buffer
fastify.FastifyBodyParser< RawBody, RawServer, RawRequest>
指定 body 解析方法的函数类型定义。使用 RawBody
泛型来指定正在解析的 body 类型。
fastify.FastifyContentTypeParser< RawServer, RawRequest>
指定 body 解析方法的函数类型定义。内容通过 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 模式验证器。
此接口传递给 FastifyError 的实例。
回调钩子
fastify.onRequestHookHandler< RawServer, RawRequest, RawReply, RequestGeneric, ContextConfig>(request: FastifyRequest, reply: FastifyReply, done: (err?: FastifyError) => void): Promise<unknown> | void
onRequest
是请求生命周期中第一个执行的钩子。在此之前没有其他钩子,下一个钩子将是 preParsing
。
注意:在 onRequest
钩子中,request.body
总是为 null,因为 body 解析发生在 preHandler
钩子之前。
fastify.preParsingHookHandler< RawServer, RawRequest, RawReply, RequestGeneric, ContextConfig>(request: FastifyRequest, reply: FastifyReply, done: (err?: FastifyError) => void): Promise<unknown> | void
preParsing
是请求生命周期中第二个执行的钩子。之前的钩子是 onRequest
,下一个钩子将是 preValidation
。
注意:在 preParsing
钩子中,request.body
总是为 null,因为 body 解析发生在 preValidation
钩子之前。
注意:您还应该向返回的流添加 receivedEncodedLength
属性。此属性用于正确匹配请求负载与 Content-Length
头部值。理想情况下,应在每个接收到的数据块中更新该属性。
fastify.preValidationHookHandler< RawServer, RawRequest, RawReply, RequestGeneric, ContextConfig>(request: FastifyRequest, reply: FastifyReply, done: (err?: FastifyError) => void): Promise<unknown> | void
preValidation
是请求生命周期中第三个执行的钩子。之前的钩子是 preParsing
,下一个钩子将是 preHandler
。
fastify.preHandlerHookHandler< RawServer, RawRequest, RawReply, RequestGeneric, ContextConfig>(request: FastifyRequest, reply: FastifyReply, done: (err?: FastifyError) => void): Promise<unknown> | void
preHandler
是请求生命周期中第四个执行的钩子。之前的钩子是 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
是请求生命周期中第五个执行的钩子。之前的钩子是 preHandler
,下一个钩子将是 onSend
。
注意:如果 payload 是字符串、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
钩子来更改响应负载。这是请求生命周期中第六个执行的钩子。前一个钩子是 preSerialization
,下一个钩子将是 onResponse
。
注意:如果您修改了负载,则只能将其更改为字符串、Buffer、流或 null。
fastify.onResponseHookHandler< RawServer, RawRequest, RawReply, RequestGeneric, ContextConfig>(request: FastifyRequest, reply: FastifyReply, done: (err?: FastifyError) => void): Promise<unknown> | void
onResponse
是请求生命周期中的第七个也是最后一个钩子。前一个钩子是 onSend
,没有下一个钩子。
当响应已经发送时会执行 onResponse
钩子,因此您将无法向客户端发送更多数据。但是,它可用于向外部服务发送数据,例如收集统计信息。
fastify.onErrorHookHandler< RawServer, RawRequest, RawReply, RequestGeneric, ContextConfig>(request: FastifyRequest, reply: FastifyReply, error: FastifyError, done: () => void): Promise | void
此钩子在需要进行自定义错误日志记录或在发生错误时添加特定头信息时非常有用。
它不用于更改错误,并且调用 reply.send 会抛出异常。
此钩子仅在 customErrorHandler 执行后执行,而且只有当 customErrorHandler 将错误返回给用户时才会执行(注意默认的 customErrorHandler 总是将错误返回给用户)。
注意:与其他钩子不同,向 done 函数传递错误不被支持。
fastify.onRouteHookHandler< RawServer, RawRequest, RawReply, RequestGeneric, ContextConfig>(opts: RouteOptions & { path: string; prefix: string }): Promise | void
当注册新路由时触发。监听器接收一个 routeOptions 对象作为唯一参数。接口是同步的,因此监听器不会接收到回调函数。
fastify.onRegisterHookHandler< RawServer, RawRequest, RawReply, Logger>(instance: FastifyInstance, done: (err?: FastifyError) => void): Promise<unknown> | void
当注册新插件并创建新的封装上下文时触发。此钩子在已注册代码执行之前运行。
如果正在开发一个需要知道插件上下文何时形成并在该特定上下文中操作的插件,这个钩子会很有用。
注意:如果插件被包裹在 fastify-plugin 中,则不会调用此钩子。
##### fastify.onRegisterHookHandler< [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [Logger][LoggerGeneric]>(instance: [FastifyInstance][FastifyInstance], done: (err?: [FastifyError][FastifyError]) => void): Promise\<unknown\> | void
fastify.onCloseHookHandler< RawServer, RawRequest, RawReply, Logger>(instance: FastifyInstance, done: (err?: FastifyError) => void): Promise<unknown> | void
当调用 fastify.close() 停止服务器时触发。这对于需要“关闭”事件的插件非常有用,例如关闭与数据库的连接。
当调用 fastify.close()
停止服务器时触发。这对于需要“关闭”事件的插件很有用,例如关闭与数据库的连接。