Aktueller Stand

This commit is contained in:
2026-01-22 19:05:45 +01:00
parent 85dee61a4d
commit e280e4eadb
1967 changed files with 397327 additions and 74093 deletions

View File

@@ -1,18 +1,18 @@
<h1 align="center">Fastify</h1>
## Benchmarking
Benchmarking is important if you want to measure how a change can affect the
performance of your application. We provide a simple way to benchmark your
Benchmarking is important if you want to measure how a change can affect your
application's performance. We provide a simple way to benchmark your
application from the point of view of a user and contributor. The setup allows
you to automate benchmarks in different branches and on different Node.js
versions.
The modules we will use:
- [Autocannon](https://github.com/mcollina/autocannon): A HTTP/1.1 benchmarking
- [Autocannon](https://github.com/mcollina/autocannon): An HTTP/1.1 benchmarking
tool written in node.
- [Branch-comparer](https://github.com/StarpTech/branch-comparer): Checkout
multiple git branches, execute scripts and log the results.
- [Concurrently](https://github.com/kimmobrunfeldt/concurrently): Run commands
multiple git branches, execute scripts, and log the results.
- [Concurrently](https://github.com/open-cli-tools/concurrently): Run commands
concurrently.
- [Npx](https://github.com/npm/npx): NPM package runner used to run scripts
against different Node.js Versions and execute local binaries. Shipped with

View File

@@ -2,17 +2,17 @@
## Database
Fastify's ecosystem provides a handful of
plugins for connecting to various database engines.
This guide covers engines that have Fastify
Fastify's ecosystem provides a handful of
plugins for connecting to various database engines.
This guide covers engines that have Fastify
plugins maintained within the Fastify organization.
> If a plugin for your database of choice does not exist
> you can still use the database as Fastify is database agnostic.
> By following the examples of the database plugins listed in this guide,
> a plugin can be written for the missing database engine.
> If a plugin for your database of choice does not exist
> you can still use the database as Fastify is database agnostic.
> By following the examples of the database plugins listed in this guide,
> a plugin can be written for the missing database engine.
> If you would like to write your own Fastify plugin
> If you would like to write your own Fastify plugin
> please take a look at the [plugins guide](./Plugins-Guide.md)
### [MySQL](https://github.com/fastify/fastify-mysql)
@@ -104,8 +104,8 @@ fastify.listen({ port: 3000 }, err => {
})
```
By default `@fastify/redis` doesn't close
the client connection when Fastify server shuts down.
By default `@fastify/redis` doesn't close
the client connection when Fastify server shuts down.
To opt-in to this behavior, register the client like so:
```javascript
@@ -126,7 +126,7 @@ fastify.register(require('@fastify/mongodb'), {
// force to close the mongodb connection when app stopped
// the default value is false
forceClose: true,
url: 'mongodb://mongo/mydb'
})
@@ -178,8 +178,8 @@ fastify.listen({ port: 3000 }, err => {
```
### Writing plugin for a database library
We could write a plugin for a database
library too (e.g. Knex, Prisma, or TypeORM).
We could write a plugin for a database
library too (e.g. Knex, Prisma, or TypeORM).
We will use [Knex](https://knexjs.org/) in our example.
```javascript
@@ -245,7 +245,7 @@ for Postgres, MySQL, SQL Server and SQLite. For MongoDB migrations, please check
#### [Postgrator](https://www.npmjs.com/package/postgrator)
Postgrator is Node.js SQL migration tool that uses a directory of SQL scripts to
alter the database schema. Each file an migrations folder need to follow the
alter the database schema. Each file in a migrations folder needs to follow the
pattern: ` [version].[action].[optional-description].sql`.
**version:** must be an incrementing number (e.g. `001` or a timestamp).
@@ -281,7 +281,7 @@ async function migrate() {
const client = new pg.Client({
host: 'localhost',
port: 5432,
database: 'example',
database: 'example',
user: 'example',
password: 'example',
});
@@ -313,7 +313,7 @@ async function migrate() {
console.error(err)
process.exitCode = 1
}
await client.end()
}

View File

@@ -77,8 +77,8 @@ server.get('/ping', function (request, reply) {
})
server.post('/webhook', function (request, reply) {
// It's good practice to validate webhook requests really come from
// whoever you expect. This is skipped in this sample for the sake
// It's good practice to validate webhook requests come from
// who you expect. This is skipped in this sample for the sake
// of simplicity
const { magicKey } = request.body
@@ -103,7 +103,7 @@ server.get('/v1*', async function (request, reply) {
}
})
server.decorate('magicKey', null)
server.decorate('magicKey')
server.listen({ port: '1234' }, () => {
provider.thirdPartyMagicKeyGenerator(USUAL_WAIT_TIME_MS)
@@ -303,7 +303,7 @@ async function setup(fastify) {
fastify.server.on('listening', doMagic)
// Set up the placeholder for the magicKey
fastify.decorate('magicKey', null)
fastify.decorate('magicKey')
// Our magic -- important to make sure errors are handled. Beware of async
// functions outside `try/catch` blocks
@@ -406,7 +406,7 @@ https://nodejs.org/api/net.html#event-listening). We use that to reach out to
our provider as soon as possible, with the `doMagic` function.
```js
fastify.decorate('magicKey', null)
fastify.decorate('magicKey')
```
The `magicKey` decoration is also part of the plugin now. We initialize it with
@@ -448,10 +448,10 @@ have the possibility of giving the customer meaningful information, like how
long they should wait before retrying the request. Going even further, by
issuing a [`503` status
code](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/503) we're
signaling to our infrastructure components (namely load balancers) we're still
not ready to take incoming requests and they should redirect traffic to other
instances, if available, besides in how long we estimate that will be solved.
All of that in a few simple lines!
signaling to our infrastructure components (namely load balancers) that we're
still not ready to take incoming requests and they should redirect traffic to
other instances, if available. Additionally, we are providing a `Retry-After`
header with the time in milliseconds the client should wait before retrying.
It's noteworthy that we didn't use the `fastify-plugin` wrapper in the `delay`
factory. That's because we wanted the `onRequest` hook to only be set within
@@ -524,14 +524,17 @@ Retry-After: 5000
}
```
Then we attempt a new request (`req-2`), which was a `GET /ping`. As expected,
Then we attempted a new request (`req-2`), which was a `GET /ping`. As expected,
since that was not one of the requests we asked our plugin to filter, it
succeeded. That could also be used as means of informing an interested party
whether or not we were ready to serve requests (although `/ping` is more
commonly associated with *liveness* checks and that would be the responsibility
of a *readiness* check -- the curious reader can get more info on these terms
[here](https://cloud.google.com/blog/products/containers-kubernetes/kubernetes-best-practices-setting-up-health-checks-with-readiness-and-liveness-probes))
with the `ready` field. Below is the response for that request:
succeeded. That could also be used as a means of informing an interested party
whether or not we were ready to serve requests with the `ready` field. Although
`/ping` is more commonly associated with *liveness* checks and that would be
the responsibility of a *readiness* check. The curious reader can get more info
on these terms in the article
["Kubernetes best practices: Setting up health checks with readiness and liveness probes"](
https://cloud.google.com/blog/products/containers-kubernetes/kubernetes-best-practices-setting-up-health-checks-with-readiness-and-liveness-probes).
Below is the response to that request:
```sh
HTTP/1.1 200 OK
@@ -547,7 +550,7 @@ Keep-Alive: timeout=5
}
```
After that there were more interesting log messages:
After that, there were more interesting log messages:
<!-- markdownlint-disable -->
```sh

View File

@@ -4,30 +4,30 @@
## Introduction
Fastify provides request events to trigger at certain points in a request's
lifecycle. However, there isn't a built-in mechanism to
detect unintentional client disconnection scenarios such as when the client's
Fastify provides request events to trigger at certain points in a request's
lifecycle. However, there isn't a built-in mechanism to
detect unintentional client disconnection scenarios such as when the client's
internet connection is interrupted. This guide covers methods to detect if
and when a client intentionally aborts a request.
Keep in mind, Fastify's `clientErrorHandler` is not designed to detect when a
client aborts a request. This works in the same way as the standard Node HTTP
module, which triggers the `clientError` event when there is a bad request or
exceedingly large header data. When a client aborts a request, there is no
Keep in mind, Fastify's `clientErrorHandler` is not designed to detect when a
client aborts a request. This works in the same way as the standard Node HTTP
module, which triggers the `clientError` event when there is a bad request or
exceedingly large header data. When a client aborts a request, there is no
error on the socket and the `clientErrorHandler` will not be triggered.
## Solution
### Overview
The proposed solution is a possible way of detecting when a client
intentionally aborts a request, such as when a browser is closed or the HTTP
request is aborted from your client application. If there is an error in your
application code that results in the server crashing, you may require
The proposed solution is a possible way of detecting when a client
intentionally aborts a request, such as when a browser is closed or the HTTP
request is aborted from your client application. If there is an error in your
application code that results in the server crashing, you may require
additional logic to avoid a false abort detection.
The goal here is to detect when a client intentionally aborts a connection
so your application logic can proceed accordingly. This can be useful for
The goal here is to detect when a client intentionally aborts a connection
so your application logic can proceed accordingly. This can be useful for
logging purposes or halting business logic.
### Hands-on
@@ -78,10 +78,10 @@ const start = async () => {
start()
```
Our code is setting up a Fastify server which includes the following
Our code is setting up a Fastify server which includes the following
functionality:
- Accepting requests at http://localhost:3000, with a 3 second delayed response
- Accepting requests at `http://localhost:3000`, with a 3 second delayed response
of `{ ok: true }`.
- An onRequest hook that triggers when every request is received.
- Logic that triggers in the hook when the request is closed.
@@ -108,7 +108,7 @@ app.get('/', async (request, reply) => {
})
```
At any point in your business logic, you can check if the request has been
At any point in your business logic, you can check if the request has been
aborted and perform alternative actions.
```js
@@ -122,14 +122,14 @@ app.get('/', async (request, reply) => {
})
```
A benefit to adding this in your application code is that you can log Fastify
details such as the reqId, which may be unavailable in lower-level code that
A benefit to adding this in your application code is that you can log Fastify
details such as the reqId, which may be unavailable in lower-level code that
only has access to the raw request information.
### Testing
To test this functionality you can use an app like Postman and cancel your
request within 3 seconds. Alternatively, you can use Node to send an HTTP
To test this functionality you can use an app like Postman and cancel your
request within 3 seconds. Alternatively, you can use Node to send an HTTP
request with logic to abort the request before 3 seconds. Example:
```js
@@ -151,7 +151,7 @@ setTimeout(() => {
}, 1000);
```
With either approach, you should see the Fastify log appear at the moment the
With either approach, you should see the Fastify log appear at the moment the
request is aborted.
## Conclusion
@@ -160,13 +160,13 @@ Specifics of the implementation will vary from one problem to another, but the
main goal of this guide was to show a very specific use case of an issue that
could be solved within Fastify's ecosystem.
You can listen to the request close event and determine if the request was
aborted or if it was successfully delivered. You can implement this solution
You can listen to the request close event and determine if the request was
aborted or if it was successfully delivered. You can implement this solution
in an onRequest hook or directly in an individual route.
This approach will not trigger in the event of internet disruption, and such
detection would require additional business logic. If you have flawed backend
application logic that results in a server crash, then you could trigger a
false detection. The `clientErrorHandler`, either by default or with custom
logic, is not intended to handle this scenario and will not trigger when the
This approach will not trigger in the event of internet disruption, and such
detection would require additional business logic. If you have flawed backend
application logic that results in a server crash, then you could trigger a
false detection. The `clientErrorHandler`, either by default or with custom
logic, is not intended to handle this scenario and will not trigger when the
client aborts a request.

View File

@@ -12,8 +12,6 @@ section.
[accepts](https://www.npmjs.com/package/accepts) in your request object.
- [`@fastify/accepts-serializer`](https://github.com/fastify/fastify-accepts-serializer)
to serialize to output according to the `Accept` header.
- [`@fastify/any-schema`](https://github.com/fastify/any-schema-you-like) Save
multiple schemas and decide which one to use to serialize the payload.
- [`@fastify/auth`](https://github.com/fastify/fastify-auth) Run multiple auth
functions in Fastify.
- [`@fastify/autoload`](https://github.com/fastify/fastify-autoload) Require all
@@ -42,11 +40,6 @@ section.
plugin for adding
[CSRF](https://en.wikipedia.org/wiki/Cross-site_request_forgery) protection to
Fastify.
- [`@fastify/diagnostics-channel`](https://github.com/fastify/fastify-diagnostics-channel)
Plugin to deal with `diagnostics_channel` on Fastify
- [`@fastify/early-hints`](https://github.com/fastify/fastify-early-hints) Plugin
to add HTTP 103 feature based on [RFC
8297](https://datatracker.ietf.org/doc/html/rfc8297).
- [`@fastify/elasticsearch`](https://github.com/fastify/fastify-elasticsearch)
Plugin to share the same ES client.
- [`@fastify/env`](https://github.com/fastify/fastify-env) Load and check
@@ -91,6 +84,8 @@ section.
[`simple-oauth2`](https://github.com/lelylan/simple-oauth2).
- [`@fastify/one-line-logger`](https://github.com/fastify/one-line-logger) Formats
Fastify's logs into a nice one-line message.
- [`@fastify/otel`](https://github.com/fastify/otel) OpenTelemetry
instrumentation library.
- [`@fastify/passport`](https://github.com/fastify/fastify-passport) Use Passport
strategies to authenticate requests and protect route.
- [`@fastify/postgres`](https://github.com/fastify/fastify-postgres) Fastify
@@ -124,8 +119,8 @@ section.
HTTP errors and assertions, but also more request and reply methods.
- [`@fastify/session`](https://github.com/fastify/session) a session plugin for
Fastify.
- [`@fastify/soap-client`](https://github.com/fastify/fastify-soap-client) a SOAP
client plugin for Fastify.
- [`@fastify/sse`](https://github.com/fastify/sse) Plugin for Server-Sent Events
(SSE) support in Fastify.
- [`@fastify/static`](https://github.com/fastify/fastify-static) Plugin for
serving static files as fast as possible.
- [`@fastify/swagger`](https://github.com/fastify/fastify-swagger) Plugin for
@@ -159,8 +154,22 @@ section.
#### [Community](#community)
> Note:
> Fastify community plugins are part of the broader community efforts,
> and we are thankful for these contributions. However, they are not
> maintained by the Fastify team.
> Use them at your own discretion.
> If you find malicious code, please
> [open an issue](https://github.com/fastify/fastify/issues/new/choose) or
> submit a PR to remove the plugin from the list.
- [`@aaroncadillac/crudify-mongo`](https://github.com/aaroncadillac/crudify-mongo)
A simple way to add a crud in your fastify project.
- [`@applicazza/fastify-nextjs`](https://github.com/applicazza/fastify-nextjs)
Alternate Fastify and Next.js integration.
- [`@attaryz/fastify-devtools`](https://github.com/attaryz/fastify-devtools)
Development tools plugin for Fastify with live request dashboard, replay
capabilities, and metrics tracking.
- [`@blastorg/fastify-aws-dynamodb-cache`](https://github.com/blastorg/fastify-aws-dynamodb-cache)
A plugin to help with caching API responses using AWS DynamoDB.
- [`@clerk/fastify`](https://github.com/clerkinc/javascript/tree/main/packages/fastify)
@@ -173,13 +182,12 @@ section.
close the server gracefully on `SIGINT` and `SIGTERM` signals.
- [`@eropple/fastify-openapi3`](https://github.com/eropple/fastify-openapi3) Provides
easy, developer-friendly OpenAPI 3.1 specs + doc explorer based on your routes.
- [`@ethicdevs/fastify-custom-session`](https://github.com/EthicDevs/fastify-custom-session)
A plugin lets you use session and decide only where to load/save from/to. Has
great TypeScript support + built-in adapters for common ORMs/databases (Firebase,
Prisma Client, Postgres (wip), InMemory) and you can easily make your own adapter!
- [`@ethicdevs/fastify-git-server`](https://github.com/EthicDevs/fastify-git-server)
A plugin to easily create git server and make one/many Git repositories available
for clone/fetch/push through the standard `git` (over http) commands.
- [`@exortek/fastify-mongo-sanitize`](https://github.com/ExorTek/fastify-mongo-sanitize)
A Fastify plugin that protects against No(n)SQL injection by sanitizing data.
- [`@exortek/remix-fastify`](https://github.com/ExorTek/remix-fastify)
Fastify plugin for Remix.
- [`@fastify-userland/request-id`](https://github.com/fastify-userland/request-id)
Fastify Request ID Plugin
- [`@fastify-userland/typeorm-query-runner`](https://github.com/fastify-userland/typeorm-query-runner)
@@ -191,14 +199,16 @@ section.
Run REST APIs and other web applications using your existing Node.js
application framework (Express, Koa, Hapi and Fastify), on top of AWS Lambda,
Huawei and many other clouds.
- [`@hey-api/openapi-ts`](https://heyapi.dev/openapi-ts/plugins/fastify)
The OpenAPI to TypeScript codegen. Generate clients, SDKs, validators, and more.
- [`@immobiliarelabs/fastify-metrics`](https://github.com/immobiliare/fastify-metrics)
Minimalistic and opinionated plugin that collects usage/process metrics and
dispatches to [statsd](https://github.com/statsd/statsd).
- [`@immobiliarelabs/fastify-sentry`](https://github.com/immobiliare/fastify-sentry)
Sentry errors handler that just works! Install, add your DSN and you're good
to go!
A plugin to implement [Lyra](https://github.com/nearform/lyra) search engine
on Fastify
- [`@inaiat/fastify-papr`](https://github.com/inaiat/fastify-papr)
A plugin to integrate [Papr](https://github.com/plexinc/papr),
the MongoDB ORM for TypeScript & MongoDB, with Fastify.
- [`@jerome1337/fastify-enforce-routes-pattern`](https://github.com/Jerome1337/fastify-enforce-routes-pattern)
A Fastify plugin that enforces naming pattern for routes path.
- [`@joggr/fastify-prisma`](https://github.com/joggrdocs/fastify-prisma)
A plugin for accessing an instantiated PrismaClient on your server.
- [`@mgcrea/fastify-graceful-exit`](https://github.com/mgcrea/fastify-graceful-exit)
@@ -213,13 +223,15 @@ section.
Fast sodium-based crypto for @mgcrea/fastify-session
- [`@mgcrea/pino-pretty-compact`](https://github.com/mgcrea/pino-pretty-compact)
A custom compact pino-base prettifier
- [`@scalar/fastify-api-reference`](https://github.com/scalar/scalar/tree/main/packages/fastify-api-reference)
- [`@pybot/fastify-autoload`](https://github.com/kunal097/fastify-autoload)
Plugin to generate routes automatically with valid json content
- [`@scalar/fastify-api-reference`](https://github.com/scalar/scalar/tree/main/integrations/fastify)
Beautiful OpenAPI/Swagger API references for Fastify
- [`@trubavuong/fastify-seaweedfs`](https://github.com/trubavuong/fastify-seaweedfs)
SeaweedFS for Fastify
- [`apitally`](https://github.com/apitally/nodejs-client) Fastify plugin to
integrate with [Apitally](https://apitally.io), a simple API monitoring &
API key management solution.
- [`apitally`](https://github.com/apitally/apitally-js) Fastify plugin to
integrate with [Apitally](https://apitally.io/fastify), an API analytics,
logging and monitoring tool.
- [`arecibo`](https://github.com/nucleode/arecibo) Fastify ping responder for
Kubernetes Liveness and Readiness Probes.
- [`aws-xray-sdk-fastify`](https://github.com/aws/aws-xray-sdk-node/tree/master/sdk_contrib/fastify)
@@ -229,6 +241,9 @@ section.
request IDs into your logs.
- [`electron-server`](https://github.com/anonrig/electron-server) A plugin for
using Fastify without the need of consuming a port on Electron apps.
- [`elements-fastify`](https://github.com/rohitsoni007/elements-fastify) Fastify
Plugin for Stoplight Elements API Documentation using
openapi swagger json yml.
- [`fast-water`](https://github.com/tswayne/fast-water) A Fastify plugin for
waterline. Decorates Fastify with waterline models.
- [`fastify-204`](https://github.com/Shiva127/fastify-204) Fastify plugin that
@@ -252,7 +267,7 @@ section.
plugin to authenticate HTTP requests based on API key and signature
- [`fastify-appwrite`](https://github.com/Dev-Manny/fastify-appwrite) Fastify
Plugin for interacting with Appwrite server.
- [`fastify-asyncforge`](https://github.com/mcollina/fastify-asyncforge) Plugin
- [`fastify-asyncforge`](https://github.com/mcollina/fastify-asyncforge) Plugin
to access Fastify instance, logger, request and reply from Node.js [Async
Local Storage](https://nodejs.org/api/async_context.html#class-asynclocalstorage).
- [`fastify-at-mysql`](https://github.com/mateonunez/fastify-at-mysql) Fastify
@@ -280,7 +295,7 @@ section.
development servers that require Babel transformations of JavaScript sources.
- [`fastify-bcrypt`](https://github.com/beliven-it/fastify-bcrypt) A Bcrypt hash
generator & checker.
- [`fastify-better-sqlite3`](https://github.com/punkish/fastify-better-sqlite3)
- [`fastify-better-sqlite3`](https://github.com/punkish/fastify-better-sqlite3)
Plugin for better-sqlite3.
- [`fastify-blipp`](https://github.com/PavelPolyakov/fastify-blipp) Prints your
routes to the console, so you definitely know which endpoints are available.
@@ -292,7 +307,7 @@ section.
to add [bree](https://github.com/breejs/bree) support.
- [`fastify-bugsnag`](https://github.com/ZigaStrgar/fastify-bugsnag) Fastify plugin
to add support for [Bugsnag](https://www.bugsnag.com/) error reporting.
- [`fastify-cacheman`](https://gitlab.com/aalfiann/fastify-cacheman)
- [`fastify-cacheman`](https://gitlab.com/aalfiann/fastify-cacheman)
Small and efficient cache provider for Node.js with In-memory, File, Redis
and MongoDB engines for Fastify
- [`fastify-casbin`](https://github.com/nearform/fastify-casbin) Casbin support
@@ -347,7 +362,7 @@ section.
- [`fastify-event-bus`](https://github.com/Shiva127/fastify-event-bus) Event bus
support for Fastify. Built upon [js-event-bus](https://github.com/bcerati/js-event-bus).
- [`fastify-evervault`](https://github.com/Briscoooe/fastify-evervault/) Fastify
plugin for instantiating and encapsulating the
plugin for instantiating and encapsulating the
[Evervault](https://evervault.com/) client.
- [`fastify-explorer`](https://github.com/Eomm/fastify-explorer) Get control of
your decorators across all the encapsulated contexts.
@@ -356,7 +371,7 @@ section.
- [`fastify-feature-flags`](https://gitlab.com/m03geek/fastify-feature-flags)
Fastify feature flags plugin with multiple providers support (e.g. env,
[config](https://lorenwest.github.io/node-config/),
[unleash](https://unleash.github.io/)).
[unleash](https://github.com/Unleash/unleash)).
- [`fastify-file-routes`](https://github.com/spa5k/fastify-file-routes) Get
Next.js based file system routing into fastify.
- [`fastify-file-upload`](https://github.com/huangang/fastify-file-upload)
@@ -447,12 +462,16 @@ section.
middlewares into Fastify plugins
- [`fastify-kubernetes`](https://github.com/greguz/fastify-kubernetes) Fastify
Kubernetes client plugin.
- [`fastify-kysely`](https://github.com/alenap93/fastify-kysely) Fastify
plugin for supporting Kysely type-safe query builder.
- [`fastify-language-parser`](https://github.com/lependu/fastify-language-parser)
Fastify plugin to parse request language.
- [`fastify-lcache`](https://github.com/denbon05/fastify-lcache)
Lightweight cache plugin
- [`fastify-list-routes`](https://github.com/chuongtrh/fastify-list-routes)
A simple plugin for Fastify to list all available routes.
- [`fastify-lm`](https://github.com/galiprandi/fastify-lm#readme)
Use OpenAI, Claude, Google, Deepseek, and others LMs with one Fastify plugin.
- [`fastify-loader`](https://github.com/TheNoim/fastify-loader) Load routes from
a directory and inject the Fastify instance in each file.
- [`fastify-log-controller`](https://github.com/Eomm/fastify-log-controller/)
@@ -493,6 +512,8 @@ middlewares into Fastify plugins
[MS Graph Change Notifications webhooks](https://learn.microsoft.com/it-it/graph/change-notifications-delivery-webhooks?tabs=http).
- [`fastify-multer`](https://github.com/fox1t/fastify-multer) Multer is a plugin
for handling multipart/form-data, which is primarily used for uploading files.
- [`fastify-multilingual`](https://github.com/gbrugger/fastify-multilingual) Unobtrusively
decorates fastify request with Polyglot.js for i18n.
- [`fastify-nats`](https://github.com/mahmed8003/fastify-nats) Plugin to share
[NATS](https://nats.io) client across Fastify.
- [`fastify-next-auth`](https://github.com/wobsoriano/fastify-next-auth)
@@ -501,10 +522,7 @@ middlewares into Fastify plugins
Add `additionalProperties: false` by default to your JSON Schemas.
- [`fastify-no-icon`](https://github.com/jsumners/fastify-no-icon) Plugin to
eliminate thrown errors for `/favicon.ico` requests.
- [`fastify-normalize-request-reply`](https://github.com/ericrglass/fastify-normalize-request-reply)
Plugin to normalize the request and reply to the Express version 4.x request
and response, which allows use of middleware, like swagger-stats, that was
originally written for Express.
- [`fastify-now`](https://github.com/yonathan06/fastify-now) Structure your
endpoints in a folder and load them dynamically with Fastify.
- [`fastify-nuxtjs`](https://github.com/gomah/fastify-nuxtjs) Vue server-side
@@ -539,12 +557,17 @@ middlewares into Fastify plugins
OSM plugin to run overpass queries by OpenStreetMap.
- [`fastify-override`](https://github.com/matthyk/fastify-override)
Fastify plugin to override decorators, plugins and hooks for testing purposes
- [`fastify-passkit-webservice`](https://github.com/alexandercerutti/fastify-passkit-webservice)
A set of Fastify plugins to integrate Apple Wallet Web Service specification
- [`fastify-peekaboo`](https://github.com/simone-sanfratello/fastify-peekaboo)
Fastify plugin for memoize responses by expressive settings.
- [`fastify-permissions`](https://github.com/pckrishnadas88/fastify-permissions)
Route-level permission middleware for Fastify supports
custom permission checks.
- [`fastify-piscina`](https://github.com/piscinajs/fastify-piscina) A worker
thread pool plugin using [Piscina](https://github.com/piscinajs/piscina).
- [`fastify-polyglot`](https://github.com/beliven-it/fastify-polyglot) A plugin to
handle i18n using
- [`fastify-polyglot`](https://github.com/beliven-it/fastify-polyglot) A plugin
to handle i18n using
[node-polyglot](https://www.npmjs.com/package/node-polyglot).
- [`fastify-postgraphile`](https://github.com/alemagio/fastify-postgraphile)
Plugin to integrate [PostGraphile](https://www.graphile.org/postgraphile/) in
@@ -600,6 +623,9 @@ middlewares into Fastify plugins
Fastify Rob-Config integration.
- [`fastify-route-group`](https://github.com/TakNePoidet/fastify-route-group)
Convenient grouping and inheritance of routes.
- [`fastify-route-preset`](https://github.com/inyourtime/fastify-route-preset)
A Fastify plugin that enables you to create route configurations that can be
applied to multiple routes.
- [`fastify-s3-buckets`](https://github.com/kibertoad/fastify-s3-buckets)
Ensure the existence of defined S3 buckets on the application startup.
- [`fastify-schema-constraint`](https://github.com/Eomm/fastify-schema-constraint)
@@ -615,6 +641,8 @@ middlewares into Fastify plugins
- [`fastify-server-session`](https://github.com/jsumners/fastify-server-session)
A session plugin with support for arbitrary backing caches via
`fastify-caching`.
- [`fastify-ses-mailer`](https://github.com/KaranHotwani/fastify-ses-mailer) A
Fastify plugin for sending emails via AWS SES using AWS SDK v3.
- [`fastify-shared-schema`](https://github.com/Adibla/fastify-shared-schema) Plugin
for sharing schemas between different routes.
- [`fastify-slonik`](https://github.com/Unbuttun/fastify-slonik) Fastify Slonik
@@ -656,7 +684,7 @@ middlewares into Fastify plugins
- [`fastify-type-provider-effect-schema`](https://github.com/daotl/fastify-type-provider-effect-schema)
Fastify
[type provider](https://fastify.dev/docs/latest/Reference/Type-Providers/)
for [@effect/schema](https://github.com/effect-ts/schema).
for [@effect/schema](https://github.com/Effect-TS/effect).
- [`fastify-type-provider-zod`](https://github.com/turkerdev/fastify-type-provider-zod)
Fastify
[type provider](https://fastify.dev/docs/latest/Reference/Type-Providers/)
@@ -718,6 +746,7 @@ middlewares into Fastify plugins
- [`typeorm-fastify-plugin`](https://github.com/jclemens24/fastify-typeorm) A simple
and updated Typeorm plugin for use with Fastify.
#### [Community Tools](#community-tools)
- [`@fastify-userland/workflows`](https://github.com/fastify-userland/workflows)
@@ -726,9 +755,13 @@ middlewares into Fastify plugins
generator by directory structure.
- [`fastify-flux`](https://github.com/Jnig/fastify-flux) Tool for building
Fastify APIs using decorators and convert Typescript interface to JSON Schema.
- [`jeasx`](https://www.jeasx.dev)
A flexible server-rendering framework built on Fastify
that leverages asynchronous JSX to simplify web development.
- [`simple-tjscli`](https://github.com/imjuni/simple-tjscli) CLI tool to
generate JSON Schema from TypeScript interfaces.
- [`vite-plugin-fastify`](https://github.com/Vanilla-IceCream/vite-plugin-fastify)
Fastify plugin for Vite with Hot-module Replacement.
- [`vite-plugin-fastify-routes`](https://github.com/Vanilla-IceCream/vite-plugin-fastify-routes)
File-based routing for Fastify applications using Vite.

View File

@@ -55,7 +55,7 @@ fastify.post('/the/url', { schema }, handler)
### Reuse
With `fluent-json-schema` you can manipulate your schemas more easily and
With `fluent-json-schema`, you can manipulate your schemas more easily and
programmatically and then reuse them thanks to the `addSchema()` method. You can
refer to the schema in two different manners that are detailed in the
[Validation and
@@ -122,5 +122,5 @@ const schema = { body: bodyJsonSchema }
fastify.post('/the/url', { schema }, handler)
```
NB You can mix up the `$ref-way` and the `replace-way` when using
`fastify.addSchema`.
> Note: You can mix up the `$ref-way` and the `replace-way`
> when using `fastify.addSchema`.

View File

@@ -106,7 +106,7 @@ of your code.
Fastify offers an easy platform that helps to solve all of the problems outlined
above, and more!
> ## Note
> **Note**
> The above examples, and subsequent examples in this document, default to
> listening *only* on the localhost `127.0.0.1` interface. To listen on all
> available IPv4 interfaces the example should be modified to listen on
@@ -128,6 +128,9 @@ above, and more!
>
> When deploying to a Docker (or another type of) container using `0.0.0.0` or
> `::` would be the easiest method for exposing the application.
>
> Note that when using `0.0.0.0`, the address provided in the callback argument
> above will be the first address the wildcard refers to.
### Your first plugin
<a id="first-plugin"></a>
@@ -143,7 +146,7 @@ declaration](../Reference/Routes.md) docs).
```js
// ESM
import Fastify from 'fastify'
import firstRoute from './our-first-route'
import firstRoute from './our-first-route.js'
/**
* @type {import('fastify').FastifyInstance} Instance of Fastify
*/
@@ -232,8 +235,8 @@ npm i fastify-plugin @fastify/mongodb
```js
// ESM
import Fastify from 'fastify'
import dbConnector from './our-db-connector'
import firstRoute from './our-first-route'
import dbConnector from './our-db-connector.js'
import firstRoute from './our-first-route.js'
/**
* @type {import('fastify').FastifyInstance} Instance of Fastify
@@ -417,7 +420,7 @@ In this way, you will always have access to all of the properties declared in
the current scope.
As discussed previously, Fastify offers a solid encapsulation model, to help you
build your application as single and independent services. If you want to
build your application as independent services. If you want to
register a plugin only for a subset of routes, you just have to replicate the
above structure.
```
@@ -450,8 +453,6 @@ Data validation is extremely important and a core concept of the framework.
To validate incoming requests, Fastify uses [JSON
Schema](https://json-schema.org/).
(JTD schemas are loosely supported, but `jsonShorthand` must be disabled first)
Let's look at an example demonstrating validation for routes:
```js
/**
@@ -554,15 +555,16 @@ an amazing [ecosystem](./Ecosystem.md)!
<a id="test-server"></a>
Fastify does not offer a testing framework, but we do recommend a way to write
your tests that use the features and architecture of Fastify.
your tests that uses the features and architecture of Fastify.
Read the [testing](./Testing.md) documentation to learn more!
### Run your server from CLI
<a id="cli"></a>
Fastify also has CLI integration thanks to
[fastify-cli](https://github.com/fastify/fastify-cli).
Fastify also has CLI integration via
[fastify-cli](https://github.com/fastify/fastify-cli),
a separate tool for scaffolding and managing Fastify projects.
First, install `fastify-cli`:

View File

@@ -15,11 +15,11 @@ This table of contents is in alphabetical order.
met in your application. This guide focuses on solving the problem using
[`Hooks`](../Reference/Hooks.md), [`Decorators`](../Reference/Decorators.md),
and [`Plugins`](../Reference/Plugins.md).
+ [Detecting When Clients Abort](./Detecting-When-Clients-Abort.md): A
+ [Detecting When Clients Abort](./Detecting-When-Clients-Abort.md): A
practical guide on detecting if and when a client aborts a request.
+ [Ecosystem](./Ecosystem.md): Lists all core plugins and many known community
plugins.
+ [Fluent Schema](./Fluent-Schema.md): Shows how writing JSON Schema can be
+ [Fluent Schema](./Fluent-Schema.md): Shows how JSON Schema can be
written with a fluent API and used in Fastify.
+ [Getting Started](./Getting-Started.md): Introduction tutorial for Fastify.
This is where beginners should start.

View File

@@ -9,13 +9,13 @@ work after upgrading.
## Codemods
### Fastify v4 Codemods
To help with the upgrade, weve worked with the team at
To help with the upgrade, weve worked with the team at
[Codemod](https://github.com/codemod-com/codemod) to
publish codemods that will automatically update your code to many of
publish codemods that will automatically update your code to many of
the new APIs and patterns in Fastify v4.
Run the following
[migration recipe](https://go.codemod.com/fastify-4-migration-recipe) to
Run the following
[migration recipe](https://go.codemod.com/fastify-4-migration-recipe) to
automatically update your code to Fastify v4:
```
@@ -30,7 +30,7 @@ This will run the following codemods:
- [`fastify/4/await-register-calls`](https://go.codemod.com/fastify-4-await-register-calls)
Each of these codemods automates the changes listed in the v4 migration guide.
For a complete list of available Fastify codemods and further details,
For a complete list of available Fastify codemods and further details,
see [Codemod Registry](https://go.codemod.com/fastify).
@@ -52,14 +52,14 @@ fastify.register(async fastify => {
console.log(err.message) // 'kaboom'
throw new Error('caught')
})
fastify.get('/encapsulated', async () => {
throw new Error('kaboom')
})
})
fastify.setErrorHandler(async err => {
console.log(err.message) // 'caught'
console.log(err.message) // 'caught'
throw new Error('wrapped')
})
@@ -67,10 +67,10 @@ const res = await fastify.inject('/encapsulated')
console.log(res.json().message) // 'wrapped'
```
>The root error handler is Fastifys generic error handler.
>This error handler will use the headers and status code in the Error object,
>The root error handler is Fastifys generic error handler.
>This error handler will use the headers and status code in the Error object,
>if they exist. **The headers and status code will not be automatically set if
>a custom error handler is provided**.
>a custom error handler is provided**.
### Removed `app.use()` ([#3506](https://github.com/fastify/fastify/pull/3506))
@@ -109,7 +109,8 @@ argument from your router handler.
### `exposeHeadRoutes` true by default
Starting with v4, every `GET` route will create a sibling `HEAD` route.
You can revert this behavior by setting `exposeHeadRoutes: false` in the server options.
You can revert this behavior by setting `exposeHeadRoutes: false` in the server
options.
### Synchronous route definitions ([#2954](https://github.com/fastify/fastify/pull/2954))
@@ -210,7 +211,7 @@ fastify.get('/posts/:id?', (request, reply) => {
The [variadic signature](https://en.wikipedia.org/wiki/Variadic_function) of the
`fastify.listen()` method is now deprecated.
Prior to this release, the following invocations of this method were valid:
Before this release, the following invocations of this method were valid:
- `fastify.listen(8000)`
- `fastify.listen(8000, 127.0.0.1)`
@@ -242,7 +243,7 @@ As such, schemas like below will need to be changed from:
properties: {
api_key: { type: 'string' },
image: { type: ['object', 'array'] }
}
}
}
```

View File

@@ -0,0 +1,727 @@
# V5 Migration Guide
This guide is intended to help with migration from Fastify v4 to v5.
Before migrating to v5, please ensure that you have fixed all deprecation
warnings from v4. All v4 deprecations have been removed and will no longer
work after upgrading.
## Long Term Support Cycle
Fastify v5 will only support Node.js v20+. If you are using an older version of
Node.js, you will need to upgrade to a newer version to use Fastify v5.
Fastify v4 is still supported until June 30, 2025. If you are unable to upgrade,
you should consider buying an end-of-life support plan from HeroDevs.
### Why Node.js v20?
Fastify v5 will only support Node.js v20+ because it has significant differences
compared to v18, such as
better support for `node:test`. This allows us to provide a better developer
experience and streamline maintenance.
Node.js v18 will exit Long Term Support on April 30, 2025, so you should be planning
to upgrade to v20 anyway.
## Breaking Changes
### Full JSON Schema is now required for `querystring`, `params` and `body` and response schemas
Starting with v5, Fastify will require a full JSON schema for the `querystring`,
`params` and `body` schema. Note that the `jsonShortHand` option has been
removed as well.
If the default JSON Schema validator is used, you will need
to provide a full JSON schema for the
`querystring`, `params`, `body`, and `response` schemas,
including the `type` property.
```js
// v4
fastify.get('/route', {
schema: {
querystring: {
name: { type: 'string' }
}
}
}, (req, reply) => {
reply.send({ hello: req.query.name });
});
```
```js
// v5
fastify.get('/route', {
schema: {
querystring: {
type: 'object',
properties: {
name: { type: 'string' }
},
required: ['name']
}
}
}, (req, reply) => {
reply.send({ hello: req.query.name });
});
```
See [#5586](https://github.com/fastify/fastify/pull/5586) for more details
Note that it's still possible to override the JSON Schema validator to
use a different format, such as Zod. This change simplifies that as well.
This change helps with integration of other tools, such as
[`@fastify/swagger`](https://github.com/fastify/fastify-swagger).
### New logger constructor signature
In Fastify v4, Fastify accepted the options to build a pino
logger in the `logger` option, as well as a custom logger instance.
This was the source of significant confusion.
As a result, the `logger` option will not accept a custom logger anymore in v5.
To use a custom logger, you should use the `loggerInstance` option instead:
```js
// v4
const logger = require('pino')();
const fastify = require('fastify')({
logger
});
```
```js
// v5
const loggerInstance = require('pino')();
const fastify = require('fastify')({
loggerInstance
});
```
### `useSemicolonDelimiter` false by default
Starting with v5, Fastify instances will no longer default to supporting the use
of semicolon delimiters in the query string as they did in v4.
This is due to it being non-standard
behavior and not adhering to [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986#section-3.4).
If you still wish to use semicolons as delimiters, you can do so by
setting `useSemicolonDelimiter: true` in the server configuration.
```js
const fastify = require('fastify')({
useSemicolonDelimiter: true
});
```
### The parameters object no longer has a prototype
In v4, the `parameters` object had a prototype. This is no longer the case in v5.
This means that you can no longer access properties inherited from `Object` on
the `parameters` object, such as `toString` or `hasOwnProperty`.
```js
// v4
fastify.get('/route/:name', (req, reply) => {
console.log(req.params.hasOwnProperty('name')); // true
return { hello: req.params.name };
});
```
```js
// v5
fastify.get('/route/:name', (req, reply) => {
console.log(Object.hasOwn(req.params, 'name')); // true
return { hello: req.params.name };
});
```
This increases the security of the application by hardening against prototype
pollution attacks.
### Type Providers now differentiate between validator and serializer schemas
In v4, the type providers had the same types for both validation and serialization.
In v5, the type providers have been split into two separate types: `ValidatorSchema`
and `SerializerSchema`.
[`@fastify/type-provider-json-schema-to-ts`](https://github.com/fastify/fastify-type-provider-json-schema-to-ts)
and
[`@fastify/type-provider-typebox`](https://github.com/fastify/fastify-type-provider-typebox)
have already been updated: upgrade to the latest version to get the new types.
If you are using a custom type provider, you will need to modify it like
the following:
```
--- a/index.ts
+++ b/index.ts
@@ -11,7 +11,8 @@ import {
import { FromSchema, FromSchemaDefaultOptions, FromSchemaOptions, JSONSchema } from 'json-schema-to-ts'
export interface JsonSchemaToTsProvider<
Options extends FromSchemaOptions = FromSchemaDefaultOptions
> extends FastifyTypeProvider {
- output: this['input'] extends JSONSchema ? FromSchema<this['input'], Options> : unknown;
+ validator: this['schema'] extends JSONSchema ? FromSchema<this['schema'], Options> : unknown;
+ serializer: this['schema'] extends JSONSchema ? FromSchema<this['schema'], Options> : unknown;
}
```
### Changes to the .listen() method
The variadic argument signature of the `.listen()` method has been removed.
This means that you can no longer call `.listen()` with a variable number of arguments.
```js
// v4
fastify.listen(8000)
```
Will become:
```js
// v5
fastify.listen({ port: 8000 })
```
This was already deprecated in v4 as `FSTDEP011`, so you should have already updated
your code to use the new signature.
### Direct return of trailers has been removed
In v4, you could directly return trailers from a handler.
This is no longer possible in v5.
```js
// v4
fastify.get('/route', (req, reply) => {
reply.trailer('ETag', function (reply, payload) {
return 'custom-etag'
})
reply.send('')
});
```
```js
// v5
fastify.get('/route', (req, reply) => {
reply.trailer('ETag', async function (reply, payload) {
return 'custom-etag'
})
reply.send('')
});
```
A callback could also be used.
This was already deprecated in v4 as `FSTDEP013`,
so you should have already updated your code to use the new signature.
### Streamlined access to route definition
All deprecated properties relating to accessing the route definition have been removed
and are now accessed via `request.routeOptions`.
| Code | Description | How to solve | Discussion |
| ---- | ----------- | ------------ | ---------- |
| FSTDEP012 | You are trying to access the deprecated `request.context` property. | Use `request.routeOptions.config` or `request.routeOptions.schema`. | [#4216](https://github.com/fastify/fastify/pull/4216) [#5084](https://github.com/fastify/fastify/pull/5084) |
| FSTDEP015 | You are accessing the deprecated `request.routeSchema` property. | Use `request.routeOptions.schema`. | [#4470](https://github.com/fastify/fastify/pull/4470) |
| FSTDEP016 | You are accessing the deprecated `request.routeConfig` property. | Use `request.routeOptions.config`. | [#4470](https://github.com/fastify/fastify/pull/4470) |
| FSTDEP017 | You are accessing the deprecated `request.routerPath` property. | Use `request.routeOptions.url`. | [#4470](https://github.com/fastify/fastify/pull/4470) |
| FSTDEP018 | You are accessing the deprecated `request.routerMethod` property. | Use `request.routeOptions.method`. | [#4470](https://github.com/fastify/fastify/pull/4470) |
| FSTDEP019 | You are accessing the deprecated `reply.context` property. | Use `reply.routeOptions.config` or `reply.routeOptions.schema`. | [#5032](https://github.com/fastify/fastify/pull/5032) [#5084](https://github.com/fastify/fastify/pull/5084) |
See [#5616](https://github.com/fastify/fastify/pull/5616) for more information.
### `reply.redirect()` has a new signature
The `reply.redirect()` method has a new signature:
`reply.redirect(url: string, code?: number)`.
```js
// v4
reply.redirect(301, '/new-route')
```
Change it to:
```js
// v5
reply.redirect('/new-route', 301)
```
This was already deprecated in v4 as `FSTDEP021`, so you should have already
updated your code to use the new signature.
### Modifying `reply.sent` is now forbidden
In v4, you could modify the `reply.sent` property to prevent the response from
being sent.
This is no longer possible in v5, use `reply.hijack()` instead.
```js
// v4
fastify.get('/route', (req, reply) => {
reply.sent = true;
reply.raw.end('hello');
});
```
Change it to:
```js
// v5
fastify.get('/route', (req, reply) => {
reply.hijack();
reply.raw.end('hello');
});
```
This was already deprecated in v4 as `FSTDEP010`, so you should have already
updated your code to use the new signature.
### Constraints for route versioning signature changes
We changed the signature for route versioning constraints.
The `version` and `versioning` options have been removed and you should
use the `constraints` option instead.
| Code | Description | How to solve | Discussion |
| ---- | ----------- | ------------ | ---------- |
| FSTDEP008 | You are using route constraints via the route `{version: "..."}` option. | Use `{constraints: {version: "..."}}` option. | [#2682](https://github.com/fastify/fastify/pull/2682) |
| FSTDEP009 | You are using a custom route versioning strategy via the server `{versioning: "..."}` option. | Use `{constraints: {version: "..."}}` option. | [#2682](https://github.com/fastify/fastify/pull/2682) |
### `HEAD` routes requires to register before `GET` when `exposeHeadRoutes: true`
We have a more strict requirement for custom `HEAD` route when
`exposeHeadRoutes: true`.
When you provides a custom `HEAD` route, you must either explicitly
set `exposeHeadRoutes` to `false`
```js
// v4
fastify.get('/route', {
}, (req, reply) => {
reply.send({ hello: 'world' });
});
fastify.head('/route', (req, reply) => {
// ...
});
```
```js
// v5
fastify.get('/route', {
exposeHeadRoutes: false
}, (req, reply) => {
reply.send({ hello: 'world' });
});
fastify.head('/route', (req, reply) => {
// ...
});
```
or place the `HEAD` route before `GET`.
```js
// v5
fastify.head('/route', (req, reply) => {
// ...
});
fastify.get('/route', {
}, (req, reply) => {
reply.send({ hello: 'world' });
});
```
This was changed in [#2700](https://github.com/fastify/fastify/pull/2700),
and the old behavior was deprecated in v4 as `FSTDEP007`.
### Removed `request.connection`
The `request.connection` property has been removed in v5.
You should use `request.socket` instead.
```js
// v4
fastify.get('/route', (req, reply) => {
console.log(req.connection.remoteAddress);
return { hello: 'world' };
});
```
```js
// v5
fastify.get('/route', (req, reply) => {
console.log(req.socket.remoteAddress);
return { hello: 'world' };
});
```
This was already deprecated in v4 as `FSTDEP05`, so you should
have already updated your code to use the new signature.
### `reply.getResponseTime()` has been removed, use `reply.elapsedTime` instead
The `reply.getResponseTime()` method has been removed in v5.
You should use `reply.elapsedTime` instead.
```js
// v4
fastify.get('/route', (req, reply) => {
console.log(reply.getResponseTime());
return { hello: 'world' };
});
```
```js
// v5
fastify.get('/route', (req, reply) => {
console.log(reply.elapsedTime);
return { hello: 'world' };
});
```
This was already deprecated in v4 as `FSTDEP20`, so you should have already
updated your code to use the new signature.
### `fastify.hasRoute()` now matches the behavior of `find-my-way`
The `fastify.hasRoute()` method now matches the behavior of `find-my-way`
and requires the route definition to be passed as it is defined in the route.
```js
// v4
fastify.get('/example/:file(^\\d+).png', function (request, reply) { })
console.log(fastify.hasRoute({
method: 'GET',
url: '/example/12345.png'
)); // true
```
```js
// v5
fastify.get('/example/:file(^\\d+).png', function (request, reply) { })
console.log(fastify.hasRoute({
method: 'GET',
url: '/example/:file(^\\d+).png'
)); // true
```
### Removal of some non-standard HTTP methods
We have removed the following HTTP methods from Fastify:
- `PROPFIND`
- `PROPPATCH`
- `MKCOL`
- `COPY`
- `MOVE`
- `LOCK`
- `UNLOCK`
- `TRACE`
- `SEARCH`
It's now possible to add them back using the `addHttpMethod` method.
```js
const fastify = Fastify()
// add a new http method on top of the default ones:
fastify.addHttpMethod('REBIND')
// add a new HTTP method that accepts a body:
fastify.addHttpMethod('REBIND', { hasBody: true })
// reads the HTTP methods list:
fastify.supportedMethods // returns a string array
```
See [#5567](https://github.com/fastify/fastify/pull/5567) for more
information.
### Removed support from reference types in decorators
Decorating Request/Reply with a reference type (`Array`, `Object`)
is now prohibited as this reference is shared amongst all requests.
```js
// v4
fastify.decorateRequest('myObject', { hello: 'world' });
```
```js
// v5
fastify.decorateRequest('myObject');
fastify.addHook('onRequest', async (req, reply) => {
req.myObject = { hello: 'world' };
});
```
or turn it into a function
```js
// v5
fastify.decorateRequest('myObject', () => ({ hello: 'world' }));
```
or as a getter
```js
// v5
fastify.decorateRequest('myObject', {
getter () {
return { hello: 'world' }
}
});
```
See [#5462](https://github.com/fastify/fastify/pull/5462) for more information.
### Remove support for DELETE with a `Content-Type: application/json` header and an empty body
In v4, Fastify allowed `DELETE` requests with a `Content-Type: application/json`
header and an empty body was accepted.
This is no longer allowed in v5.
See [#5419](https://github.com/fastify/fastify/pull/5419) for more information.
### Plugins cannot mix callback/promise API anymore
In v4, plugins could mix the callback and promise API, leading to unexpected behavior.
This is no longer allowed in v5.
```js
// v4
fastify.register(async function (instance, opts, done) {
done();
});
```
```js
// v5
fastify.register(async function (instance, opts) {
return;
});
```
or
```js
// v5
fastify.register(function (instance, opts, done) {
done();
});
```
### Requests now have `host`, `hostname`, and `port`, and `hostname` no longer includes the port number
In Fastify v4, `req.hostname` would include both the hostname and the
servers port, so locally it might have the value `localhost:1234`.
With v5, we aligned to the Node.js URL object and now include `host`, `hostname`,
and `port` properties. `req.host` has the same value as `req.hostname` did in v4,
while `req.hostname` includes the hostname _without_ a port if a port is present,
and `req.port` contains just the port number.
See [#4766](https://github.com/fastify/fastify/pull/4766)
and [#4682](https://github.com/fastify/fastify/issues/4682) for more information.
### Removes `getDefaultRoute` and `setDefaultRoute` methods
The `getDefaultRoute` and `setDefaultRoute` methods have been removed in v5.
See [#4485](https://github.com/fastify/fastify/pull/4485)
and [#4480](https://github.com/fastify/fastify/pull/4485)
for more information.
This was already deprecated in v4 as `FSTDEP014`,
so you should have already updated your code.
### `time` and `date-time` formats enforce timezone
The updated AJV compiler updates `ajv-formats` which now
enforce the use of timezone in `time` and `date-time` format.
A workaround is to use `iso-time` and `iso-date-time` formats
which support an optional timezone for backwards compatibility.
See the
[full discussion](https://github.com/fastify/fluent-json-schema/issues/267).
## New Features
### Diagnostic Channel support
Fastify v5 now supports the [Diagnostics Channel](https://nodejs.org/api/diagnostics_channel.html)
API natively
and provides a way to trace the lifecycle of a request.
```js
'use strict'
const diagnostics = require('node:diagnostics_channel')
const Fastify = require('fastify')
diagnostics.subscribe('tracing:fastify.request.handler:start', (msg) => {
console.log(msg.route.url) // '/:id'
console.log(msg.route.method) // 'GET'
})
diagnostics.subscribe('tracing:fastify.request.handler:end', (msg) => {
// msg is the same as the one emitted by the 'tracing:fastify.request.handler:start' channel
console.log(msg)
})
diagnostics.subscribe('tracing:fastify.request.handler:error', (msg) => {
// in case of error
})
const fastify = Fastify()
fastify.route({
method: 'GET',
url: '/:id',
handler: function (req, reply) {
return { hello: 'world' }
}
})
fastify.listen({ port: 0 }, async function () {
const result = await fetch(fastify.listeningOrigin + '/7')
t.assert.ok(result.ok)
t.assert.strictEqual(response.status, 200)
t.assert.deepStrictEqual(await result.json(), { hello: 'world' })
})
```
See the [documentation](https://github.com/fastify/fastify/blob/main/docs/Reference/Hooks.md#diagnostics-channel-hooks)
and [#5252](https://github.com/fastify/fastify/pull/5252) for additional details.
## Contributors
The complete list of contributors, across all of the core
Fastify packages, is provided below. Please consider
contributing to those that are capable of accepting sponsorships.
| Contributor | Sponsor Link | Packages |
| --- | --- | --- |
| 10xLaCroixDrinker | [❤️ sponsor](https://github.com/sponsors/10xLaCroixDrinker) | fastify-cli |
| Bram-dc | | fastify; fastify-swagger |
| BrianValente | | fastify |
| BryanAbate | | fastify-cli |
| Cadienvan | [❤️ sponsor](https://github.com/sponsors/Cadienvan) | fastify |
| Cangit | | fastify |
| Cyberlane | | fastify-elasticsearch |
| Eomm | [❤️ sponsor](https://github.com/sponsors/Eomm) | ajv-compiler; fastify; fastify-awilix; fastify-diagnostics-channel; fastify-elasticsearch; fastify-hotwire; fastify-mongodb; fastify-nextjs; fastify-swagger-ui; under-pressure |
| EstebanDalelR | [❤️ sponsor](https://github.com/sponsors/EstebanDalelR) | fastify-cli |
| Fdawgs | [❤️ sponsor](https://github.com/sponsors/Fdawgs) | aws-lambda-fastify; csrf-protection; env-schema; fastify; fastify-accepts; fastify-accepts-serializer; fastify-auth; fastify-awilix; fastify-basic-auth; fastify-bearer-auth; fastify-caching; fastify-circuit-breaker; fastify-cli; fastify-cookie; fastify-cors; fastify-diagnostics-channel; fastify-elasticsearch; fastify-env; fastify-error; fastify-etag; fastify-express; fastify-flash; fastify-formbody; fastify-funky; fastify-helmet; fastify-hotwire; fastify-http-proxy; fastify-jwt; fastify-kafka; fastify-leveldb; fastify-mongodb; fastify-multipart; fastify-mysql; fastify-nextjs; fastify-oauth2; fastify-passport; fastify-plugin; fastify-postgres; fastify-rate-limit; fastify-redis; fastify-reply-from; fastify-request-context; fastify-response-validation; fastify-routes; fastify-routes-stats; fastify-schedule; fastify-secure-session; fastify-sensible; fastify-swagger-ui; fastify-url-data; fastify-websocket; fastify-zipkin; fluent-json-schema; forwarded; middie; point-of-view; process-warning; proxy-addr; safe-regex2; secure-json-parse; under-pressure |
| Gehbt | | fastify-secure-session |
| Gesma94 | | fastify-routes-stats |
| H4ad | [❤️ sponsor](https://github.com/sponsors/H4ad) | aws-lambda-fastify |
| JohanManders | | fastify-secure-session |
| LiviaMedeiros | | fastify |
| Momy93 | | fastify-secure-session |
| MunifTanjim | | fastify-swagger-ui |
| Nanosync | | fastify-secure-session |
| RafaelGSS | [❤️ sponsor](https://github.com/sponsors/RafaelGSS) | fastify; under-pressure |
| Rantoledo | | fastify |
| SMNBLMRR | | fastify |
| SimoneDevkt | | fastify-cli |
| Tony133 | | fastify |
| Uzlopak | [❤️ sponsor](https://github.com/sponsors/Uzlopak) | fastify; fastify-autoload; fastify-diagnostics-channel; fastify-hotwire; fastify-nextjs; fastify-passport; fastify-plugin; fastify-rate-limit; fastify-routes; fastify-static; fastify-swagger-ui; point-of-view; under-pressure |
| Zamiell | | fastify-secure-session |
| aadito123 | | fastify |
| aaroncadillac | [❤️ sponsor](https://github.com/sponsors/aaroncadillac) | fastify |
| aarontravass | | fastify |
| acro5piano | [❤️ sponsor](https://github.com/sponsors/acro5piano) | fastify-secure-session |
| adamward459 | | fastify-cli |
| adrai | [❤️ sponsor](https://github.com/sponsors/adrai) | aws-lambda-fastify |
| alenap93 | | fastify |
| alexandrucancescu | | fastify-nextjs |
| anthonyringoet | | aws-lambda-fastify |
| arshcodemod | | fastify |
| autopulated | | point-of-view |
| barbieri | | fastify |
| beyazit | | fastify |
| big-kahuna-burger | [❤️ sponsor](https://github.com/sponsors/big-kahuna-burger) | fastify-cli; fastify-compress; fastify-helmet |
| bilalshareef | | fastify-routes |
| blue86321 | | fastify-swagger-ui |
| bodinsamuel | | fastify-rate-limit |
| busybox11 | [❤️ sponsor](https://github.com/sponsors/busybox11) | fastify |
| climba03003 | | csrf-protection; fastify; fastify-accepts; fastify-accepts-serializer; fastify-auth; fastify-basic-auth; fastify-bearer-auth; fastify-caching; fastify-circuit-breaker; fastify-compress; fastify-cors; fastify-env; fastify-etag; fastify-flash; fastify-formbody; fastify-http-proxy; fastify-mongodb; fastify-swagger-ui; fastify-url-data; fastify-websocket; middie |
| dancastillo | [❤️ sponsor](https://github.com/sponsors/dancastillo) | fastify; fastify-basic-auth; fastify-caching; fastify-circuit-breaker; fastify-cors; fastify-helmet; fastify-passport; fastify-response-validation; fastify-routes; fastify-schedule |
| danny-andrews | | fastify-kafka |
| davidcralph | [❤️ sponsor](https://github.com/sponsors/davidcralph) | csrf-protection |
| davideroffo | | under-pressure |
| dhensby | | fastify-cli |
| dmkng | | fastify |
| domdomegg | | fastify |
| faustman | | fastify-cli |
| floridemai | | fluent-json-schema |
| fox1t | | fastify-autoload |
| giuliowaitforitdavide | | fastify |
| gunters63 | | fastify-reply-from |
| gurgunday | | fastify; fastify-circuit-breaker; fastify-cookie; fastify-multipart; fastify-mysql; fastify-rate-limit; fastify-response-validation; fastify-sensible; fastify-swagger-ui; fluent-json-schema; middie; proxy-addr; safe-regex2; secure-json-parse |
| ildella | | under-pressure |
| james-kaguru | | fastify |
| jcbain | | fastify-http-proxy |
| jdhollander | | fastify-swagger-ui |
| jean-michelet | | fastify; fastify-autoload; fastify-cli; fastify-mysql; fastify-sensible |
| johaven | | fastify-multipart |
| jordanebelanger | | fastify-plugin |
| jscheffner | | fastify |
| jsprw | | fastify-secure-session |
| jsumners | [❤️ sponsor](https://github.com/sponsors/jsumners) | ajv-compiler; avvio; csrf-protection; env-schema; fast-json-stringify; fastify; fastify-accepts; fastify-accepts-serializer; fastify-auth; fastify-autoload; fastify-awilix; fastify-basic-auth; fastify-bearer-auth; fastify-caching; fastify-circuit-breaker; fastify-compress; fastify-cookie; fastify-cors; fastify-env; fastify-error; fastify-etag; fastify-express; fastify-flash; fastify-formbody; fastify-funky; fastify-helmet; fastify-http-proxy; fastify-jwt; fastify-kafka; fastify-leveldb; fastify-multipart; fastify-mysql; fastify-oauth2; fastify-plugin; fastify-postgres; fastify-redis; fastify-reply-from; fastify-request-context; fastify-response-validation; fastify-routes; fastify-routes-stats; fastify-schedule; fastify-secure-session; fastify-sensible; fastify-static; fastify-swagger; fastify-swagger-ui; fastify-url-data; fastify-websocket; fastify-zipkin; fluent-json-schema; forwarded; light-my-request; middie; process-warning; proxy-addr; safe-regex2; secure-json-parse; under-pressure |
| karankraina | | under-pressure |
| kerolloz | [❤️ sponsor](https://github.com/sponsors/kerolloz) | fastify-jwt |
| kibertoad | | fastify-rate-limit |
| kukidon-dev | | fastify-passport |
| kunal097 | | fastify |
| lamweili | | fastify-sensible |
| lemonclown | | fastify-mongodb |
| liuhanqu | | fastify |
| matthyk | | fastify-plugin |
| mch-dsk | | fastify |
| mcollina | [❤️ sponsor](https://github.com/sponsors/mcollina) | ajv-compiler; avvio; csrf-protection; fastify; fastify-accepts; fastify-accepts-serializer; fastify-auth; fastify-autoload; fastify-awilix; fastify-basic-auth; fastify-bearer-auth; fastify-caching; fastify-circuit-breaker; fastify-cli; fastify-compress; fastify-cookie; fastify-cors; fastify-diagnostics-channel; fastify-elasticsearch; fastify-env; fastify-etag; fastify-express; fastify-flash; fastify-formbody; fastify-funky; fastify-helmet; fastify-http-proxy; fastify-jwt; fastify-kafka; fastify-leveldb; fastify-multipart; fastify-mysql; fastify-oauth2; fastify-passport; fastify-plugin; fastify-postgres; fastify-rate-limit; fastify-redis; fastify-reply-from; fastify-request-context; fastify-response-validation; fastify-routes; fastify-routes-stats; fastify-schedule; fastify-secure-session; fastify-static; fastify-swagger; fastify-swagger-ui; fastify-url-data; fastify-websocket; fastify-zipkin; fluent-json-schema; light-my-request; middie; point-of-view; proxy-addr; secure-json-parse; under-pressure |
| melroy89 | [❤️ sponsor](https://github.com/sponsors/melroy89) | under-pressure |
| metcoder95 | [❤️ sponsor](https://github.com/sponsors/metcoder95) | fastify-elasticsearch |
| mhamann | | fastify-cli |
| mihaur | | fastify-elasticsearch |
| mikesamm | | fastify |
| mikhael-abdallah | | secure-json-parse |
| miquelfire | [❤️ sponsor](https://github.com/sponsors/miquelfire) | fastify-routes |
| miraries | | fastify-swagger-ui |
| mohab-sameh | | fastify |
| monish001 | | fastify |
| moradebianchetti81 | | fastify |
| mouhannad-sh | | aws-lambda-fastify |
| multivoltage | | point-of-view |
| muya | [❤️ sponsor](https://github.com/sponsors/muya) | under-pressure |
| mweberxyz | | point-of-view |
| nflaig | | fastify |
| nickfla1 | | avvio |
| o-az | | process-warning |
| ojeytonwilliams | | csrf-protection |
| onosendi | | fastify-formbody |
| philippviereck | | fastify |
| pip77 | | fastify-mongodb |
| puskin94 | | fastify |
| remidewitte | | fastify |
| rozzilla | | fastify |
| samialdury | | fastify-cli |
| sknetl | | fastify-cors |
| sourcecodeit | | fastify |
| synapse | | env-schema |
| timursaurus | | secure-json-parse |
| tlhunter | | fastify |
| tlund101 | | fastify-rate-limit |
| ttshivers | | fastify-http-proxy |
| voxpelli | [❤️ sponsor](https://github.com/sponsors/voxpelli) | fastify |
| weixinwu | | fastify-cli |
| zetaraku | | fastify-cli |

View File

@@ -71,8 +71,8 @@ order of plugins. *How?* Glad you asked, check out
[`avvio`](https://github.com/mcollina/avvio)! Fastify starts loading the plugin
__after__ `.listen()`, `.inject()` or `.ready()` are called.
Inside a plugin you can do whatever you want, register routes, utilities (we
will see this in a moment) and do nested registers, just remember to call `done`
Inside a plugin you can do whatever you want, register routes and utilities (we
will see this in a moment), and do nested registers, just remember to call `done`
when everything is set up!
```js
module.exports = function (fastify, options, done) {
@@ -117,7 +117,7 @@ Now you can access your utility just by calling `fastify.util` whenever you need
it - even inside your test.
And here starts the magic; do you remember how just now we were talking about
encapsulation? Well, using `register` and `decorate` in conjunction enable
encapsulation? Well, using `register` and `decorate` in conjunction enables
exactly that, let me show you an example to clarify this:
```js
fastify.register((instance, opts, done) => {
@@ -137,7 +137,7 @@ Inside the second register call `instance.util` will throw an error because
`util` exists only inside the first register context.
Let's step back for a moment and dig deeper into this: every time you use the
`register` API, a new context is created which avoids the negative situations
`register` API, a new context is created that avoids the negative situations
mentioned above.
Do note that encapsulation applies to the ancestors and siblings, but not the
@@ -202,7 +202,7 @@ a utility that also needs access to the `request` and `reply` instance,
a function that is defined using the `function` keyword is needed instead
of an *arrow function expression*.
In the same way you can do this for the `request` object:
You can do the same for the `request` object:
```js
fastify.decorate('getHeader', (req, header) => {
return req.headers[header]
@@ -316,7 +316,7 @@ based on a [route config option](../Reference/Routes.md#routes-options):
```js
fastify.register((instance, opts, done) => {
instance.decorate('util', (request, key, value) => { request[key] = value })
function handler(request, reply, done) {
instance.util(request, 'timestamp', new Date())
done()
@@ -395,7 +395,7 @@ As we mentioned earlier, Fastify starts loading its plugins __after__
have been declared. This means that, even though the plugin may inject variables
to the external Fastify instance via [`decorate`](../Reference/Decorators.md),
the decorated variables will not be accessible before calling `.listen()`,
`.inject()` or `.ready()`.
`.inject()`, or `.ready()`.
In case you rely on a variable injected by a preceding plugin and want to pass
that in the `options` argument of `register`, you can do so by using a function

View File

@@ -8,7 +8,7 @@
<a id="pp"></a>
Based on the article by Eran Hammer,the issue is created by a web security bug.
It is also a perfect illustration of the efforts required to maintain
It is also a perfect illustration of the efforts required to maintain
open-source software and the limitations of existing communication channels.
But first, if we use a JavaScript framework to process incoming JSON data, take
@@ -16,7 +16,7 @@ a moment to read up on [Prototype Poisoning](https://medium.com/intrinsic/javasc
in general, and the specific
[technical details](https://github.com/hapijs/hapi/issues/3916) of this issue.
This could be a critical issue so, we might need to verify your own code first.
It focuses on specific framework however, any solution that uses `JSON.parse()`
It focuses on specific framework however, any solution that uses `JSON.parse()`
to process external data is potentially at risk.
### BOOM
@@ -42,7 +42,7 @@ defect a validation library can have.
To understand this, we need to understand how JavaScript works a bit.
Every object in JavaScript can have a prototype. It is a set of methods and
properties it "inherits" from another object. I have put inherits in quotes
properties it "inherits" from another object. I have put inherits in quotes
because JavaScript isn't really an object-oriented language. It is a prototype-
based object-oriented language.

View File

@@ -212,17 +212,19 @@ server {
# server group via port 3000.
server {
# This listen directive asks NGINX to accept requests
# coming to any address, port 443, with SSL, and HTTP/2
# if possible.
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
# coming to any address, port 443, with SSL.
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
# With a server_name directive you can also ask NGINX to
# use this server block only with matching server name(s)
# listen 443 ssl http2;
# listen [::]:443 ssl http2;
# listen 443 ssl;
# listen [::]:443 ssl;
# server_name example.tld;
# Enable HTTP/2 support
http2 on;
# Your SSL/TLS certificate (chain) and secret key in the PEM format
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/private.pem;
@@ -283,7 +285,7 @@ server {
## Kubernetes
<a id="kubernetes"></a>
The `readinessProbe` uses [(by
The `readinessProbe` uses ([by
default](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#configure-probes))
the pod IP as the hostname. Fastify listens on `127.0.0.1` by default. The probe
will not be able to reach the application in this case. To make it work,
@@ -305,22 +307,22 @@ readinessProbe:
## Capacity Planning For Production
<a id="capacity"></a>
In order to rightsize the production environment for your Fastify application,
it is highly recommended that you perform your own measurements against
In order to rightsize the production environment for your Fastify application,
it is highly recommended that you perform your own measurements against
different configurations of the environment, which may
use real CPU cores, virtual CPU cores (vCPU), or even fractional
vCPU cores. We will use the term vCPU throughout this
recommendation to represent any CPU type.
Tools such as [k6](https://github.com/grafana/k6)
Tools such as [k6](https://github.com/grafana/k6)
or [autocannon](https://github.com/mcollina/autocannon) can be used for
conducting the necessary performance tests.
That said, you may also consider the following as a rule of thumb:
* To have the lowest possible latency, 2 vCPU are recommended per app
instance (e.g., a k8s pod). The second vCPU will mostly be used by the
garbage collector (GC) and libuv threadpool. This will minimize the latency
* To have the lowest possible latency, 2 vCPU are recommended per app
instance (e.g., a k8s pod). The second vCPU will mostly be used by the
garbage collector (GC) and libuv threadpool. This will minimize the latency
for your users, as well as the memory usage, as the GC will be run more
frequently. Also, the main thread won't have to stop to let the GC run.
@@ -328,7 +330,7 @@ frequently. Also, the main thread won't have to stop to let the GC run.
requests per second per vCPU available), consider using a smaller amount of vCPUs
per app instance. It is totally fine to run Node.js applications with 1 vCPU.
* You may experiment with an even smaller amount of vCPU, which may provide
* You may experiment with an even smaller amount of vCPU, which may provide
even better throughput in certain use-cases. There are reports of API gateway
solutions working well with 100m-200m vCPU in Kubernetes.
@@ -345,7 +347,7 @@ would be exposing metrics endpoints on a separate port,
to prevent public access, when using a reverse proxy or an ingress
firewall is not an option.
It is perfectly fine to spin up several Fastify instances within the same
Node.js process and run them concurrently, even in high load systems.
It is perfectly fine to spin up several Fastify instances within the same
Node.js process and run them concurrently, even in high load systems.
Each Fastify instance only generates as much load as the traffic it receives,
plus the memory used for that Fastify instance.

View File

@@ -1,20 +1,20 @@
<h1 align="center">Serverless</h1>
Run serverless applications and REST APIs using your existing Fastify
application. By default, Fastify will not work on your serverless platform of
choice, you will need to make some small changes to fix this. This document
contains a small guide for the most popular serverless providers and how to use
application. You may need to make code changes to work on your
serverless platform of choice. This document contains a small guide
for the most popular serverless providers and how to use
Fastify with them.
#### Should you use Fastify in a serverless platform?
That is up to you! Keep in mind that functions as a service should always use
That is up to you! Keep in mind, functions as a service should always use
small and focused functions, but you can also run an entire web application with
them. It is important to remember that the bigger the application the slower the
initial boot will be. The best way to run Fastify applications in serverless
environments is to use platforms like Google Cloud Run, AWS Fargate, and Azure
Container Instances, where the server can handle multiple requests at the same
time and make full use of Fastify's features.
environments is to use platforms like Google Cloud Run, AWS Fargate, Azure
Container Instances, and Vercel where the server can handle multiple requests
at the same time and make full use of Fastify's features.
One of the best features of using Fastify in serverless applications is the ease
of development. In your local environment, you will always run the Fastify
@@ -25,21 +25,21 @@ snippet of code.
### Contents
- [AWS](#aws)
- [Genezio](#genezio)
- [Google Cloud Functions](#google-cloud-functions)
- [Google Firebase Functions](#google-firebase-functions)
- [Google Cloud Run](#google-cloud-run)
- [Netlify Lambda](#netlify-lambda)
- [Platformatic Cloud](#platformatic-cloud)
- [Vercel](#vercel)
## AWS
To integrate with AWS, you have two choices of library:
- Using [@fastify/aws-lambda](https://github.com/fastify/aws-lambda-fastify)
- Using [@fastify/aws-lambda](https://github.com/fastify/aws-lambda-fastify)
which only adds API Gateway support but has heavy optimizations for fastify.
- Using [@h4ad/serverless-adapter](https://github.com/H4ad/serverless-adapter)
which is a little slower as it creates an HTTP request for each AWS event but
- Using [@h4ad/serverless-adapter](https://github.com/H4ad/serverless-adapter)
which is a little slower as it creates an HTTP request for each AWS event but
has support for more AWS services such as: AWS SQS, AWS SNS and others.
So you can decide which option is best for you, but you can test both libraries.
@@ -129,6 +129,13 @@ If you need to integrate with more AWS services, take a look at
[@h4ad/serverless-adapter](https://viniciusl.com.br/serverless-adapter/docs/main/frameworks/fastify)
on Fastify to find out how to integrate.
## Genezio
[Genezio](https://genezio.com/) is a platform designed to simplify the deployment
of serverless applications to the cloud.
[Genezio has a dedicated guide for deploying a Fastify application.](https://genezio.com/docs/frameworks/fastify/)
## Google Cloud Functions
### Creation of Fastify instance
@@ -230,14 +237,13 @@ npx @google-cloud/functions-framework --target=fastifyFunction
Or add this command to your `package.json` scripts:
```json
"scripts": {
...
"dev": "npx @google-cloud/functions-framework --target=fastifyFunction"
...
...
"dev": "npx @google-cloud/functions-framework --target=fastifyFunction"
...
}
```
and run it with `npm run dev`.
### Deploy
```bash
gcloud functions deploy fastifyFunction \
@@ -263,7 +269,7 @@ curl -X POST https://$GOOGLE_REGION-$GOOGLE_PROJECT.cloudfunctions.net/me \
## Google Firebase Functions
Follow this guide if you want to use Fastify as the HTTP framework for
Follow this guide if you want to use Fastify as the HTTP framework for
Firebase Functions instead of the vanilla JavaScript router provided with
`onRequest(async (req, res) => {}`.
@@ -280,8 +286,8 @@ const { onRequest } = require("firebase-functions/v2/https")
### Creation of Fastify instance
Create the Fastify instance and encapsulate the returned application instance
in a function which will register routes, await the server's processing of
plugins, hooks and other settings. As follows:
in a function that will register routes, await the server's processing of
plugins, hooks, and other settings. As follows:
```js
const fastify = require("fastify")({
@@ -297,10 +303,10 @@ const fastifyApp = async (request, reply) => {
### Add Custom `contentTypeParser` to Fastify instance and define endpoints
Firebase Function's HTTP layer already parses the request
and makes a JSON payload available. It also provides access
to the raw body, unparsed, which is useful in order to calculate
request signatures to validate HTTP webhooks.
Firebase Function's HTTP layer already parses the request and makes a JSON
payload available through the property `payload.body` below. It also provides
access to the raw body, unparsed, which is useful for calculating request
signatures to validate HTTP webhooks.
Add as follows to the `registerRoutes()` function:
@@ -318,7 +324,7 @@ async function registerRoutes (fastify) {
})
// define your endpoints here...
fastify.post("/some-route-here", async (request, reply) => {}
fastify.post("/some-route-here", async (request, reply) => {})
fastify.get('/', async (request, reply) => {
reply.send({message: 'Hello World!'})
@@ -326,6 +332,24 @@ async function registerRoutes (fastify) {
}
```
**Failing to add this `ContentTypeParser` may lead to the Fastify process
remaining stuck and not processing any other requests after receiving one with
the Content-Type `application/json`.**
When using Typescript, since the type of `payload` is a native `IncomingMessage`
that gets modified by Firebase, it won't be able to find the property
`payload.body`.
In order to suppress the error, you can use the following signature:
```ts
declare module 'http' {
interface IncomingMessage {
body?: unknown;
}
}
```
### Export the function using Firebase onRequest
Final step is to export the Fastify app instance to Firebase's own
@@ -369,7 +393,6 @@ firebase functions:log
- [Fastify on Firebase Functions](https://github.com/lirantal/lemon-squeezy-firebase-webhook-fastify/blob/main/package.json)
- [An article about HTTP webhooks on Firebase Functions and Fastify: A Practical Case Study with Lemon Squeezy](https://lirantal.com/blog/http-webhooks-firebase-functions-fastify-practical-case-study-lemon-squeezy)
## Google Cloud Run
Unlike AWS Lambda or Google Cloud Functions, Google Cloud Run is a serverless
@@ -384,7 +407,7 @@ familiar with gcloud or just follow their
### Adjust Fastify server
In order for Fastify to properly listen for requests within the container, be
For Fastify to properly listen for requests within the container, be
sure to set the correct port and address:
```js
@@ -455,7 +478,7 @@ CMD [ "npm", "start" ]
To keep build artifacts out of your container (which keeps it small and improves
build times) add a `.dockerignore` file like the one below:
```.dockerignore
```dockerignore
Dockerfile
README.md
node_modules
@@ -482,12 +505,11 @@ gcloud beta run deploy --image gcr.io/PROJECT-ID/APP-NAME --platform managed
Your app will be accessible from the URL GCP provides.
## netlify-lambda
First, please perform all preparation steps related to **AWS Lambda**.
Create a folder called `functions`, then create `server.js` (and your endpoint
Create a folder called `functions`, then create `server.js` (and your endpoint
path will be `server.js`) inside the `functions` folder.
### functions/server.js
@@ -556,106 +578,27 @@ Add this command to your `package.json` *scripts*
```json
"scripts": {
...
"build:functions": "netlify-lambda build functions --config ./webpack.config.netlify.js"
...
...
"build:functions": "netlify-lambda build functions --config ./webpack.config.netlify.js"
...
}
```
Then it should work fine
## Platformatic Cloud
[Platformatic](https://platformatic.dev) provides zero-configuration deployment
for Node.js applications.
To use it now, you should wrap your existing Fastify application inside a
[Platformatic Service](https://oss.platformatic.dev/docs/reference/service/introduction),
by running the following:
```bash
npm create platformatic@latest -- service
```
The wizard would ask you to fill in a few answers:
```
? Where would you like to create your project? .
? Do you want to run npm install? yes
? Do you want to use TypeScript? no
? What port do you want to use? 3042
[13:04:14] INFO: Configuration file platformatic.service.json successfully created.
[13:04:14] INFO: Environment file .env successfully created.
[13:04:14] INFO: Plugins folder "plugins" successfully created.
[13:04:14] INFO: Routes folder "routes" successfully created.
? Do you want to create the github action to deploy this application to Platformatic Cloud dynamic workspace? no
? Do you want to create the github action to deploy this application to Platformatic Cloud static workspace? no
```
Then, head to [Platformatic Cloud](https://platformatic.cloud) and sign in
with your GitHub account.
Create your first application and a static workspace: be careful to download the
API key as an env file, e.g. `yourworkspace.txt`.
Then, you can easily deploy your application with the following command:
```bash
platformatic deploy --keys `yourworkspace.txt`
```
Check out the [Full Guide](https://blog.platformatic.dev/how-to-migrate-a-fastify-app-to-platformatic-service)
on how to wrap Fastify application in Platformatic.
Then it should work fine.
## Vercel
[Vercel](https://vercel.com) provides zero-configuration deployment for Node.js
applications. To use it now, it is as simple as configuring your `vercel.json`
file like the following:
[Vercel](https://vercel.com) fully supports deploying Fastify applications.
Additionally, with Vercel's
[Fluid compute](https://vercel.com/docs/functions/fluid-compute), you can combine
server-like concurrency with the autoscaling properties of traditional
serverless functions.
```json
{
"rewrites": [
{
"source": "/(.*)",
"destination": "/api/serverless.js"
}
]
}
```
Get started with the
[Fastify template on Vercel](
https://vercel.com/templates/backend/fastify-on-vercel).
Then, write `api/serverless.js` like so:
```js
"use strict";
// Read the .env file.
import * as dotenv from "dotenv";
dotenv.config();
// Require the framework
import Fastify from "fastify";
// Instantiate Fastify with some config
const app = Fastify({
logger: true,
});
// Register your application as a normal plugin.
app.register(import("../src/app.js"));
export default async (req, res) => {
await app.ready();
app.server.emit('request', req, res);
}
```
In `src/app.js` define the plugin.
```js
async function routes (fastify, options) {
fastify.get('/', async (request, reply) => {
return { hello: 'world' }
})
}
export default routes;
```
[Fluid compute](https://vercel.com/docs/functions/fluid-compute) currently
requires an explicit opt-in. Learn more about enabling Fluid compute
[here](
https://vercel.com/docs/functions/fluid-compute#how-to-enable-fluid-compute).

View File

@@ -83,7 +83,7 @@ Result:
Make sure you avoid copying other people's work. Keep it as original as
possible. You can learn from what they have done and reference where it is from
if you used a particular quote from their work.
if you use a particular quote from their work.
## Word Choice
@@ -217,7 +217,7 @@ Styles](https://medium.com/better-programming/string-case-styles-camel-pascal-sn
### Hyperlinks
Hyperlinks should have a clear title of what it references. Here is how your
Hyperlinks should have a clear title of what they reference. Here is how your
hyperlink should look:
```MD

View File

@@ -5,15 +5,15 @@
Testing is one of the most important parts of developing an application. Fastify
is very flexible when it comes to testing and is compatible with most testing
frameworks (such as [Tap](https://www.npmjs.com/package/tap), which is used in
the examples below).
frameworks (such as [Node Test Runner](https://nodejs.org/api/test.html),
which is used in the examples below).
## Application
Let's `cd` into a fresh directory called 'testing-example' and type `npm init
-y` in our terminal.
Run `npm i fastify && npm i tap pino-pretty -D`
Run `npm i fastify && npm i pino-pretty -D`
### Separating concerns makes testing easy
@@ -113,24 +113,25 @@ Now we can replace our `console.log` calls with actual tests!
In your `package.json` change the "test" script to:
`"test": "tap --reporter=list --watch"`
`"test": "node --test --watch"`
**app.test.js**:
```js
'use strict'
const { test } = require('tap')
const { test } = require('node:test')
const build = require('./app')
test('requests the "/" route', async t => {
t.plan(1)
const app = build()
const response = await app.inject({
method: 'GET',
url: '/'
})
t.equal(response.statusCode, 200, 'returns a status code of 200')
t.assert.strictEqual(response.statusCode, 200, 'returns a status code of 200')
})
```
@@ -214,26 +215,26 @@ module.exports = buildFastify
**test.js**
```js
const tap = require('tap')
const { test } = require('node:test')
const buildFastify = require('./app')
tap.test('GET `/` route', t => {
test('GET `/` route', t => {
t.plan(4)
const fastify = buildFastify()
// At the end of your tests it is highly recommended to call `.close()`
// to ensure that all connections to external services get closed.
t.teardown(() => fastify.close())
t.after(() => fastify.close())
fastify.inject({
method: 'GET',
url: '/'
}, (err, response) => {
t.error(err)
t.equal(response.statusCode, 200)
t.equal(response.headers['content-type'], 'application/json; charset=utf-8')
t.same(response.json(), { hello: 'world' })
t.assert.ifError(err)
t.assert.strictEqual(response.statusCode, 200)
t.assert.strictEqual(response.headers['content-type'], 'application/json; charset=utf-8')
t.assert.deepStrictEqual(response.json(), { hello: 'world' })
})
})
```
@@ -248,11 +249,11 @@ Uses **app.js** from the previous example.
**test-listen.js** (testing with [`undici`](https://www.npmjs.com/package/undici))
```js
const tap = require('tap')
const { test } = require('node:test')
const { Client } = require('undici')
const buildFastify = require('./app')
tap.test('should work with undici', async t => {
test('should work with undici', async t => {
t.plan(2)
const fastify = buildFastify()
@@ -263,63 +264,64 @@ tap.test('should work with undici', async t => {
'http://localhost:' + fastify.server.address().port, {
keepAliveTimeout: 10,
keepAliveMaxTimeout: 10
}
}
)
t.teardown(() => {
t.after(() => {
fastify.close()
client.close()
})
const response = await client.request({ method: 'GET', path: '/' })
t.equal(await response.body.text(), '{"hello":"world"}')
t.equal(response.statusCode, 200)
t.assert.strictEqual(await response.body.text(), '{"hello":"world"}')
t.assert.strictEqual(response.statusCode, 200)
})
```
Alternatively, starting with Node.js 18,
[`fetch`](https://nodejs.org/docs/latest-v18.x/api/globals.html#fetch)
Alternatively, starting with Node.js 18,
[`fetch`](https://nodejs.org/docs/latest-v18.x/api/globals.html#fetch)
may be used without requiring any extra dependencies:
**test-listen.js**
```js
const tap = require('tap')
const { test } = require('node:test')
const buildFastify = require('./app')
tap.test('should work with fetch', async t => {
test('should work with fetch', async t => {
t.plan(3)
const fastify = buildFastify()
t.teardown(() => fastify.close())
t.after(() => fastify.close())
await fastify.listen()
const response = await fetch(
'http://localhost:' + fastify.server.address().port
)
t.equal(response.status, 200)
t.equal(
t.assert.strictEqual(response.status, 200)
t.assert.strictEqual(
response.headers.get('content-type'),
'application/json; charset=utf-8'
)
t.has(await response.json(), { hello: 'world' })
const jsonResult = await response.json()
t.assert.strictEqual(jsonResult.hello, 'world')
})
```
**test-ready.js** (testing with
[`SuperTest`](https://www.npmjs.com/package/supertest))
```js
const tap = require('tap')
const { test } = require('node:test')
const supertest = require('supertest')
const buildFastify = require('./app')
tap.test('GET `/` route', async (t) => {
test('GET `/` route', async (t) => {
const fastify = buildFastify()
t.teardown(() => fastify.close())
t.after(() => fastify.close())
await fastify.ready()
@@ -327,22 +329,21 @@ tap.test('GET `/` route', async (t) => {
.get('/')
.expect(200)
.expect('Content-Type', 'application/json; charset=utf-8')
t.same(response.body, { hello: 'world' })
t.assert.deepStrictEqual(response.body, { hello: 'world' })
})
```
### How to inspect tap tests
### How to inspect node tests
1. Isolate your test by passing the `{only: true}` option
```javascript
test('should ...', {only: true}, t => ...)
```
2. Run `tap` using `npx`
2. Run `node --test`
```bash
> npx tap -O -T --node-arg=--inspect-brk test/<test-file.test.js>
> node --test --test-only --inspect-brk test/<test-file.test.js>
```
- `-O` specifies to run tests with the `only` option enabled
- `-T` specifies not to timeout (while you're debugging)
- `--node-arg=--inspect-brk` will launch the node debugger
- `--test-only` specifies to run tests with the `only` option enabled
- `--inspect-brk` will launch the node debugger
3. In VS Code, create and launch a `Node.js: Attach` debug configuration. No
modification should be necessary.
@@ -352,10 +353,10 @@ Now you should be able to step through your test file (and the rest of
## Plugins
Let's `cd` into a fresh directory called 'testing-plugin-example' and type `npm init
-y` in our terminal.
Let's `cd` into a fresh directory called 'testing-plugin-example' and type
`npm init -y` in our terminal.
Run `npm i fastify fastify-plugin && npm i tap -D`
Run `npm i fastify fastify-plugin`
**plugin/myFirstPlugin.js**:
@@ -376,16 +377,16 @@ A basic example of a Plugin. See [Plugin Guide](./Plugins-Guide.md)
```js
const Fastify = require("fastify");
const tap = require("tap");
const { test } = require("node:test");
const myPlugin = require("../plugin/myFirstPlugin");
tap.test("Test the Plugin Route", async t => {
test("Test the Plugin Route", async t => {
// Create a mock fastify application to test the plugin
const fastify = Fastify()
fastify.register(myPlugin)
// Add an endpoint of your choice
// Add an endpoint of your choice
fastify.get("/", async (request, reply) => {
return ({ message: request.helloRequest })
})
@@ -395,7 +396,7 @@ tap.test("Test the Plugin Route", async t => {
method: "GET",
url: "/"
})
console.log('status code: ', fastifyResponse.statusCode)
console.log('body: ', fastifyResponse.body)
})
@@ -412,18 +413,18 @@ Now we can replace our `console.log` calls with actual tests!
In your `package.json` change the "test" script to:
`"test": "tap --reporter=list --watch"`
`"test": "node --test --watch"`
Create the tap test for the endpoint.
Create the test for the endpoint.
**test/myFirstPlugin.test.js**:
```js
const Fastify = require("fastify");
const tap = require("tap");
const { test } = require("node:test");
const myPlugin = require("../plugin/myFirstPlugin");
tap.test("Test the Plugin Route", async t => {
test("Test the Plugin Route", async t => {
// Specifies the number of test
t.plan(2)
@@ -439,9 +440,9 @@ tap.test("Test the Plugin Route", async t => {
method: "GET",
url: "/"
})
t.equal(fastifyResponse.statusCode, 200)
t.same(JSON.parse(fastifyResponse.body), { message: "Hello World" })
t.assert.strictEqual(fastifyResponse.statusCode, 200)
t.assert.deepStrictEqual(JSON.parse(fastifyResponse.body), { message: "Hello World" })
})
```
@@ -453,10 +454,10 @@ Test the ```.decorate()``` and ```.decorateRequest()```.
```js
const Fastify = require("fastify");
const tap = require("tap");
const { test }= require("node:test");
const myPlugin = require("../plugin/myFirstPlugin");
tap.test("Test the Plugin Route", async t => {
test("Test the Plugin Route", async t => {
t.plan(5)
const fastify = Fastify()
@@ -464,9 +465,9 @@ tap.test("Test the Plugin Route", async t => {
fastify.get("/", async (request, reply) => {
// Testing the fastify decorators
t.not(request.helloRequest, null)
t.ok(request.helloRequest, "Hello World")
t.ok(fastify.helloInstance, "Hello Fastify Instance")
t.assert.ifError(request.helloRequest)
t.assert.ok(request.helloRequest, "Hello World")
t.assert.ok(fastify.helloInstance, "Hello Fastify Instance")
return ({ message: request.helloRequest })
})
@@ -474,7 +475,7 @@ tap.test("Test the Plugin Route", async t => {
method: "GET",
url: "/"
})
t.equal(fastifyResponse.statusCode, 200)
t.same(JSON.parse(fastifyResponse.body), { message: "Hello World" })
t.assert.strictEqual(fastifyResponse.statusCode, 200)
t.assert.deepStrictEqual(JSON.parse(fastifyResponse.body), { message: "Hello World" })
})
```
```

View File

@@ -14,7 +14,7 @@ suggestion"](https://github.com/fastify/fastify/issues?q=is%3Aissue+is%3Aopen+la
in our issue tracker!*
## Code
Fastify uses different techniques to optimize its code, many of them are
Fastify uses different techniques to optimize its code, many of which are
documented in our Guides. We highly recommend you read [the hitchhiker's guide
to plugins](./Plugins-Guide.md) to discover all the APIs you can use to build
your plugin and learn how to use them.
@@ -53,17 +53,16 @@ Always put an example file in your repository. Examples are very helpful for
users and give a very fast way to test your plugin. Your users will be grateful.
## Test
It is extremely important that a plugin is thoroughly tested to verify that is
working properly.
A plugin **must** be thoroughly tested to verify that is working properly.
A plugin without tests will not be accepted to the ecosystem list. A lack of
tests does not inspire trust nor guarantee that the code will continue to work
among different versions of its dependencies.
We do not enforce any testing library. We use [`tap`](https://www.node-tap.org/)
We do not enforce any testing library. We use [`node:test`](https://nodejs.org/api/test.html)
since it offers out-of-the-box parallel testing and code coverage, but it is up
to you to choose your library of preference.
We highly recommend you read the [Plugin Testing](./Testing.md#plugins) to
We highly recommend you read the [Plugin Testing](./Testing.md#plugins) to
learn about how to test your plugins.
## Code Linter

View File

@@ -10,16 +10,17 @@ Whereas exhaustive type narrowing checks normally rely on `never` to represent
an unreachable state, reduction in type provider interfaces should only be done
up to `unknown`.
The reasoning is that certain methods of `FastifyInstance` are
contravariant on `TypeProvider`, which can lead to TypeScript surfacing
assignability issues unless the custom type provider interface is
The reasoning is that certain methods of `FastifyInstance` are
contravariant on `TypeProvider`, which can lead to TypeScript surfacing
assignability issues unless the custom type provider interface is
substitutable with `FastifyTypeProviderDefault`.
For example, `FastifyTypeProviderDefault` will not be assignable to the following:
```ts
export interface NotSubstitutableTypeProvider extends FastifyTypeProvider {
// bad, nothing is assignable to `never` (except for itself)
output: this['input'] extends /** custom check here**/ ? /** narrowed type here **/ : never;
validator: this['schema'] extends /** custom check here**/ ? /** narrowed type here **/ : never;
serializer: this['schema'] extends /** custom check here**/ ? /** narrowed type here **/ : never;
}
```
@@ -27,6 +28,7 @@ Unless changed to:
```ts
export interface SubstitutableTypeProvider extends FastifyTypeProvider {
// good, anything can be assigned to `unknown`
output: this['input'] extends /** custom check here**/ ? /** narrowed type here **/ : unknown;
validator: this['schema'] extends /** custom check here**/ ? /** narrowed type here **/ : unknown;
serializer: this['schema'] extends /** custom check here**/ ? /** narrowed type here **/ : unknown;
}
```