fastify
Version:
Fast and low overhead web framework, for Node.js
1,611 lines (1,281 loc) • 76.7 kB
Markdown
<h1 align="center">Fastify</h1>
## Factory
<a id="factory"></a>
The Fastify module exports a factory function that is used to create new
<code><b>Fastify server</b></code> instances. This factory function accepts an
options object which is used to customize the resulting instance. This document
describes the properties available in that options object.
- [Factory](#factory)
- [`http`](#http)
- [`http2`](#http2)
- [`https`](#https)
- [`connectionTimeout`](#connectiontimeout)
- [`keepAliveTimeout`](#keepalivetimeout)
- [`forceCloseConnections`](#forcecloseconnections)
- [`maxRequestsPerSocket`](#maxrequestspersocket)
- [`requestTimeout`](#requesttimeout)
- [`bodyLimit`](#bodylimit)
- [`onProtoPoisoning`](#onprotopoisoning)
- [`onConstructorPoisoning`](#onconstructorpoisoning)
- [`logger`](#logger)
- [`loggerInstance`](#loggerInstance)
- [`disableRequestLogging`](#disablerequestlogging)
- [`serverFactory`](#serverfactory)
- [`requestIdHeader`](#requestidheader)
- [`requestIdLogLabel`](#requestidloglabel)
- [`genReqId`](#genreqid)
- [`trustProxy`](#trustproxy)
- [`pluginTimeout`](#plugintimeout)
- [`exposeHeadRoutes`](#exposeheadroutes)
- [`return503OnClosing`](#return503onclosing)
- [`ajv`](#ajv)
- [`serializerOpts`](#serializeropts)
- [`http2SessionTimeout`](#http2sessiontimeout)
- [`frameworkErrors`](#frameworkerrors)
- [`clientErrorHandler`](#clienterrorhandler)
- [`rewriteUrl`](#rewriteurl)
- [`allowErrorHandlerOverride`](#allowerrorhandleroverride)
- [RouterOptions](#routeroptions)
- [`allowUnsafeRegex`](#allowunsaferegex)
- [`buildPrettyMeta`](#buildprettymeta)
- [`caseSensitive`](#casesensitive)
- [`constraints`](#constraints)
- [`defaultRoute`](#defaultroute)
- [`ignoreDuplicateSlashes`](#ignoreduplicateslashes)
- [`ignoreTrailingSlash`](#ignoretrailingslash)
- [`maxParamLength`](#maxparamlength)
- [`onBadUrl`](#onbadurl)
- [`querystringParser`](#querystringparser)
- [`useSemicolonDelimiter`](#usesemicolondelimiter)
- [Instance](#instance)
- [Server Methods](#server-methods)
- [server](#server)
- [after](#after)
- [ready](#ready)
- [listen](#listen)
- [addresses](#addresses)
- [routing](#routing)
- [route](#route)
- [hasRoute](#hasroute)
- [findRoute](#findroute)
- [close](#close)
- [decorate\*](#decorate)
- [register](#register)
- [addHook](#addhook)
- [prefix](#prefix)
- [pluginName](#pluginname)
- [hasPlugin](#hasplugin)
- [listeningOrigin](#listeningorigin)
- [log](#log)
- [version](#version)
- [inject](#inject)
- [addHttpMethod](#addHttpMethod)
- [addSchema](#addschema)
- [getSchemas](#getschemas)
- [getSchema](#getschema)
- [setReplySerializer](#setreplyserializer)
- [setValidatorCompiler](#setvalidatorcompiler)
- [setSchemaErrorFormatter](#setschemaerrorformatter)
- [setSerializerCompiler](#setserializercompiler)
- [validatorCompiler](#validatorcompiler)
- [serializerCompiler](#serializercompiler)
- [schemaErrorFormatter](#schemaerrorformatter)
- [schemaController](#schemacontroller)
- [setNotFoundHandler](#setnotfoundhandler)
- [setErrorHandler](#seterrorhandler)
- [setChildLoggerFactory](#setchildloggerfactory)
- [setGenReqId](#setGenReqId)
- [addConstraintStrategy](#addconstraintstrategy)
- [hasConstraintStrategy](#hasconstraintstrategy)
- [printRoutes](#printroutes)
- [printPlugins](#printplugins)
- [addContentTypeParser](#addcontenttypeparser)
- [hasContentTypeParser](#hascontenttypeparser)
- [removeContentTypeParser](#removecontenttypeparser)
- [removeAllContentTypeParsers](#removeallcontenttypeparsers)
- [getDefaultJsonParser](#getdefaultjsonparser)
- [defaultTextParser](#defaulttextparser)
- [errorHandler](#errorhandler)
- [childLoggerFactory](#childloggerfactory)
- [Symbol.asyncDispose](#symbolasyncdispose)
- [initialConfig](#initialconfig)
### `http`
<a id="factory-http"></a>
+ Default: `null`
An object used to configure the server's listening socket. The options
are the same as the Node.js core [`createServer`
method](https://nodejs.org/docs/latest-v20.x/api/http.html#httpcreateserveroptions-requestlistener).
This option is ignored if options [`http2`](#factory-http2) or
[`https`](#factory-https) are set.
### `http2`
<a id="factory-http2"></a>
+ Default: `false`
If `true` Node.js core's
[HTTP/2](https://nodejs.org/dist/latest-v20.x/docs/api/http2.html) module is
used for binding the socket.
### `https`
<a id="factory-https"></a>
+ Default: `null`
An object used to configure the server's listening socket for TLS. The options
are the same as the Node.js core [`createServer`
method](https://nodejs.org/dist/latest-v20.x/docs/api/https.html#https_https_createserver_options_requestlistener).
When this property is `null`, the socket will not be configured for TLS.
This option also applies when the [`http2`](#factory-http2) option is set.
### `connectionTimeout`
<a id="factory-connection-timeout"></a>
+ Default: `0` (no timeout)
Defines the server timeout in milliseconds. See documentation for
[`server.timeout`
property](https://nodejs.org/api/http.html#http_server_timeout) to understand
the effect of this option.
When `serverFactory` option is specified this option is ignored.
### `keepAliveTimeout`
<a id="factory-keep-alive-timeout"></a>
+ Default: `72000` (72 seconds)
Defines the server keep-alive timeout in milliseconds. See documentation for
[`server.keepAliveTimeout`
property](https://nodejs.org/api/http.html#http_server_keepalivetimeout) to
understand the effect of this option. This option only applies when HTTP/1 is in
use.
When `serverFactory` option is specified this option is ignored.
### `forceCloseConnections`
<a id="forcecloseconnections"></a>
+ Default: `"idle"` if the HTTP server allows it, `false` otherwise
When set to `true`, upon [`close`](#close) the server will iterate the current
persistent connections and [destroy their
sockets](https://nodejs.org/dist/latest-v16.x/docs/api/net.html#socketdestroyerror).
When used with HTTP/2 server, it will also close all active HTTP/2 sessions.
> ℹ️ Note:
> Since Node.js v24 active sessions are closed by default
> ⚠ Warning:
> Connections are not inspected to determine if requests have
> been completed.
Fastify will prefer the HTTP server's
[`closeAllConnections`](https://nodejs.org/dist/latest-v18.x/docs/api/http.html#servercloseallconnections)
method if supported, otherwise, it will use internal connection tracking.
When set to `"idle"`, upon [`close`](#close) the server will iterate the current
persistent connections which are not sending a request or waiting for a response
and destroy their sockets. The value is only supported if the HTTP server
supports the
[`closeIdleConnections`](https://nodejs.org/dist/latest-v18.x/docs/api/http.html#servercloseidleconnections)
method, otherwise attempting to set it will throw an exception.
### `maxRequestsPerSocket`
<a id="factory-max-requests-per-socket"></a>
+ Default: `0` (no limit)
Defines the maximum number of requests a socket can handle before closing keep
alive connection. See [`server.maxRequestsPerSocket`
property](https://nodejs.org/dist/latest/docs/api/http.html#http_server_maxrequestspersocket)
to understand the effect of this option. This option only applies when HTTP/1.1
is in use. Also, when `serverFactory` option is specified, this option is
ignored.
> ℹ️ Note:
> At the time of writing, only node >= v16.10.0 supports this option.
### `requestTimeout`
<a id="factory-request-timeout"></a>
+ Default: `0` (no limit)
Defines the maximum number of milliseconds for receiving the entire request from
the client. See [`server.requestTimeout`
property](https://nodejs.org/dist/latest/docs/api/http.html#http_server_requesttimeout)
to understand the effect of this option.
When `serverFactory` option is specified, this option is ignored.
It must be set to a non-zero value (e.g. 120 seconds) to protect against potential
Denial-of-Service attacks in case the server is deployed without a reverse proxy
in front.
> ℹ️ Note:
> At the time of writing, only node >= v14.11.0 supports this option
### `handlerTimeout`
<a id="factory-handler-timeout"></a>
+ Default: `0` (no timeout)
Defines the maximum number of milliseconds allowed for processing a request
through the entire route lifecycle (from routing through onRequest, parsing,
validation, handler execution, and serialization). If the response is not sent
within this time, a `503 Service Unavailable` error is returned and
`request.signal` is aborted.
Unlike `connectionTimeout` and `requestTimeout` (which operate at the socket
level), `handlerTimeout` is an application-level timeout that works correctly
with HTTP keep-alive connections. It can be overridden per-route via
[route options](./Routes.md#routes-options). When set at both levels, the
route-level value takes precedence. Routes without an explicit `handlerTimeout`
inherit the server default. Once a server-level timeout is set, individual
routes cannot opt out of it — they can only override it with a different
positive integer.
The timeout is **cooperative**: when it fires, Fastify sends the 503 error
response, but the handler's async work continues to run. Use
[`request.signal`](./Request.md) to detect cancellation and stop ongoing work
(database queries, HTTP requests, etc.). APIs that accept a `signal` option
(`fetch()`, database drivers, `stream.pipeline()`) will cancel automatically.
The timeout error (`FST_ERR_HANDLER_TIMEOUT`) is sent through the route's
[error handler](./Routes.md#routes-options), which can be customized per-route
to change the status code or response body.
When `reply.hijack()` is called, the timeout timer is cleared — the handler
takes full responsibility for the response lifecycle.
> ℹ️ Note:
> `handlerTimeout` does not apply to 404 handlers or custom not-found handlers
> set via `setNotFoundHandler()`, as they bypass the route handler lifecycle.
```js
const fastify = require('fastify')({
handlerTimeout: 10000 // 10s default for all routes
})
// Override per-route
fastify.get('/slow-report', { handlerTimeout: 120000 }, async (request) => {
// Use request.signal for cooperative cancellation
const data = await db.query(longQuery, { signal: request.signal })
return data
})
// Customize the timeout response
fastify.get('/custom-timeout', {
handlerTimeout: 5000,
errorHandler: (error, request, reply) => {
if (error.code === 'FST_ERR_HANDLER_TIMEOUT') {
reply.code(504).send({ error: 'Gateway Timeout' })
} else {
reply.send(error)
}
}
}, async (request) => {
const result = await externalService.call({ signal: request.signal })
return result
})
```
### `bodyLimit`
<a id="factory-body-limit"></a>
+ Default: `1048576` (1MiB)
Defines the maximum payload, in bytes, the server is allowed to accept.
The default body reader sends [`FST_ERR_CTP_BODY_TOO_LARGE`](./Errors.md#fst_err_ctp_body_too_large)
reply, if the size of the body exceeds this limit.
If [`preParsing` hook](./Hooks.md#preparsing) is provided, this limit is applied
to the size of the stream the hook returns (i.e. the size of "decoded" body).
### `onProtoPoisoning`
<a id="factory-on-proto-poisoning"></a>
+ Default: `'error'`
Defines what action the framework must take when parsing a JSON object with
`__proto__`. This functionality is provided by
[secure-json-parse](https://github.com/fastify/secure-json-parse). See
[Prototype Poisoning](../Guides/Prototype-Poisoning.md) for more details about
prototype poisoning attacks.
Possible values are `'error'`, `'remove'`, or `'ignore'`.
### `onConstructorPoisoning`
<a id="factory-on-constructor-poisoning"></a>
+ Default: `'error'`
Defines what action the framework must take when parsing a JSON object with
`constructor`. This functionality is provided by
[secure-json-parse](https://github.com/fastify/secure-json-parse). See
[Prototype Poisoning](../Guides/Prototype-Poisoning.md) for more details about
prototype poisoning attacks.
Possible values are `'error'`, `'remove'`, or `'ignore'`.
### `logger`
<a id="factory-logger"></a>
Fastify includes built-in logging via the [Pino](https://getpino.io/) logger.
This property is used to configure the internal logger instance.
The possible values this property may have are:
+ Default: `false`. The logger is disabled. All logging methods will point to a
null logger [abstract-logging](https://npm.im/abstract-logging) instance.
+ `object`: a standard Pino [options
object](https://github.com/pinojs/pino/blob/c77d8ec5ce/docs/API.md#constructor).
This will be passed directly to the Pino constructor. If the following
properties are not present on the object, they will be added accordingly:
* `level`: the minimum logging level. If not set, it will be set to
`'info'`.
* `serializers`: a hash of serialization functions. By default, serializers
are added for `req` (incoming request objects), `res` (outgoing response
objects), and `err` (standard `Error` objects). When a log method receives
an object with any of these properties then the respective serializer will
be used for that property. For example:
```js
fastify.get('/foo', function (req, res) {
req.log.info({req}) // log the serialized request object
res.send('foo')
})
```
Any user-supplied serializer will override the default serializer of the
corresponding property.
### `loggerInstance`
<a id="factory-logger-instance"></a>
+ Default: `null`
A custom logger instance. The logger must be a Pino instance or conform to the
Pino interface by having the following methods: `info`, `error`, `debug`,
`fatal`, `warn`, `trace`, `child`. For example:
```js
const pino = require('pino')();
const customLogger = {
info: function (o, ...n) {},
warn: function (o, ...n) {},
error: function (o, ...n) {},
fatal: function (o, ...n) {},
trace: function (o, ...n) {},
debug: function (o, ...n) {},
child: function() {
const child = Object.create(this);
child.pino = pino.child(...arguments);
return child;
},
};
const fastify = require('fastify')({ loggerInstance: customLogger });
```
### `disableRequestLogging`
<a id="factory-disable-request-logging"></a>
+ Default: `false`
When logging is enabled, Fastify will issue an `info` level log
message when a request is received and when the response for that request has
been sent. By setting this option to `true`, these log messages will be
disabled. This allows for more flexible request start and end logging by
attaching custom `onRequest` and `onResponse` hooks.
This option can also be a function that receives the Fastify request object
and returns a boolean. This allows for conditional request logging based on the
request properties (e.g., URL, headers, decorations).
```js
const fastify = require('fastify')({
logger: true,
disableRequestLogging: (request) => {
// Disable logging for health check endpoints
return request.url === '/health' || request.url === '/ready'
}
})
```
The other log entries that will be disabled are:
- an error log written by the default `onResponse` hook on reply callback errors
- the error and info logs written by the `defaultErrorHandler`
on error management
- the info log written by the `fourOhFour` handler when a
non existent route is requested
Other log messages emitted by Fastify will stay enabled,
like deprecation warnings and messages
emitted when requests are received while the server is closing.
```js
// Examples of hooks to replicate the disabled functionality.
fastify.addHook('onRequest', (req, reply, done) => {
req.log.info({ url: req.raw.url, id: req.id }, 'received request')
done()
})
fastify.addHook('onResponse', (req, reply, done) => {
req.log.info({ url: req.raw.originalUrl, statusCode: reply.raw.statusCode }, 'request completed')
done()
})
```
### `serverFactory`
<a id="custom-http-server"></a>
You can pass a custom HTTP server to Fastify by using the `serverFactory`
option.
`serverFactory` is a function that takes a `handler` parameter, which takes the
`request` and `response` objects as parameters, and an options object, which is
the same you have passed to Fastify.
```js
const serverFactory = (handler, opts) => {
const server = http.createServer((req, res) => {
handler(req, res)
})
return server
}
const fastify = Fastify({ serverFactory })
fastify.get('/', (req, reply) => {
reply.send({ hello: 'world' })
})
fastify.listen({ port: 3000 })
```
Internally Fastify uses the API of Node core HTTP server, so if you are using a
custom server you must be sure to have the same API exposed. If not, you can
enhance the server instance inside the `serverFactory` function before the
`return` statement.
### `requestIdHeader`
<a id="factory-request-id-header"></a>
+ Default: `'request-id'`
The header name used to set the request-id. See [the
request-id](./Logging.md#logging-request-id) section.
Setting `requestIdHeader` to `true` will set the `requestIdHeader` to
`"request-id"`.
Setting `requestIdHeader` to a non-empty string will use
the specified string as the `requestIdHeader`.
By default `requestIdHeader` is set to `false` and will immediately use [genReqId](#genreqid).
Setting `requestIdHeader` to an empty String (`""`) will set the
requestIdHeader to `false`.
+ Default: `false`
```js
const fastify = require('fastify')({
requestIdHeader: 'x-custom-id', // -> use 'X-Custom-Id' header if available
//requestIdHeader: false, // -> always use genReqId
})
```
> ⚠ Warning:
> Enabling this allows any callers to set `reqId` to a
> value of their choosing.
> No validation is performed on `requestIdHeader`.
### `requestIdLogLabel`
<a id="factory-request-id-log-label"></a>
+ Default: `'reqId'`
Defines the label used for the request identifier when logging the request.
### `genReqId`
<a id="factory-gen-request-id"></a>
+ Default: `value of 'request-id' header if provided or monotonically increasing
integers`
Function for generating the request-id. It will receive the _raw_ incoming
request as a parameter. This function is expected to be error-free.
Especially in distributed systems, you may want to override the default ID
generation behavior as shown below. For generating `UUID`s you may want to check
out [hyperid](https://github.com/mcollina/hyperid).
> ℹ️ Note:
> `genReqId` will be not called if the header set in
> <code>[requestIdHeader](#requestidheader)</code> is available (defaults to
> 'request-id').
```js
let i = 0
const fastify = require('fastify')({
genReqId: function (req) { return i++ }
})
```
### `trustProxy`
<a id="factory-trust-proxy"></a>
+ Default: `false`
+ `true/false`: Trust all proxies (`true`) or do not trust any proxies
(`false`).
+ `string`: Trust only given IP/CIDR (e.g. `'127.0.0.1'`). May be a list of
comma separated values (e.g. `'127.0.0.1,192.168.1.1/24'`).
+ `Array<string>`: Trust only given IP/CIDR list (e.g. `['127.0.0.1']`).
+ `number`: Trust the nth hop from the front-facing proxy server as the client.
+ `Function`: Custom trust function that takes `address` as first argument
```js
function myTrustFn(address, hop) {
return address === '1.2.3.4' || hop === 1
}
```
By enabling the `trustProxy` option, Fastify will know that it is sitting behind
a proxy and that the `X-Forwarded-*` header fields may be trusted, which
otherwise may be easily spoofed.
```js
const fastify = Fastify({ trustProxy: true })
```
For more examples, refer to the
[`@fastify/proxy-addr`](https://www.npmjs.com/package/@fastify/proxy-addr) package.
You may access the `ip`, `ips`, `host` and `protocol` values on the
[`request`](./Request.md) object.
```js
fastify.get('/', (request, reply) => {
console.log(request.ip)
console.log(request.ips)
console.log(request.host)
console.log(request.protocol)
})
```
> ℹ️ Note:
> If a request contains multiple `x-forwarded-host` or `x-forwarded-proto`
> headers, it is only the last one that is used to derive `request.hostname`
> and `request.protocol`.
### `pluginTimeout`
<a id="plugin-timeout"></a>
+ Default: `10000`
The maximum amount of time in *milliseconds* in which a plugin can load. If not,
[`ready`](#ready) will complete with an `Error` with code
`'ERR_AVVIO_PLUGIN_TIMEOUT'`. When set to `0`, disables this check. This
controls [avvio](https://www.npmjs.com/package/avvio) 's `timeout` parameter.
### `querystringParser`
<a id="factory-querystring-parser"></a>
The default query string parser that Fastify uses is a more performant fork
of Node.js's core `querystring` module called
[`fast-querystring`](https://github.com/anonrig/fast-querystring).
You can use this option to use a custom parser, such as
[`qs`](https://www.npmjs.com/package/qs).
If you only want the keys (and not the values) to be case insensitive we
recommend using a custom parser to convert only the keys to lowercase.
```js
const qs = require('qs')
const fastify = require('fastify')({
routerOptions: {
querystringParser: str => qs.parse(str)
}
})
```
You can also use Fastify's default parser but change some handling behavior,
like the example below for case insensitive keys and values:
```js
const querystring = require('fast-querystring')
const fastify = require('fastify')({
routerOptions: {
querystringParser: str => querystring.parse(str.toLowerCase())
}
})
```
### `exposeHeadRoutes`
<a id="exposeHeadRoutes"></a>
+ Default: `true`
Automatically creates a sibling `HEAD` route for each `GET` route defined. If
you want a custom `HEAD` handler without disabling this option, make sure to
define it before the `GET` route.
### `return503OnClosing`
<a id="factory-return-503-on-closing"></a>
+ Default: `true`
When `true`, any request arriving after [`close`](#close) has been called will
receive a `503 Service Unavailable` response with `Connection: close` header
(HTTP/1.1). This lets load balancers detect that the server is shutting down and
stop routing traffic to it.
When `false`, requests arriving during the closing phase are routed and
processed normally. They will still receive a `Connection: close` header so that
clients do not attempt to reuse the connection.
### `ajv`
<a id="factory-ajv"></a>
Configure the Ajv v8 instance used by Fastify without providing a custom one.
The default configuration is explained in the
[#schema-validator](./Validation-and-Serialization.md#schema-validator) section.
```js
const fastify = require('fastify')({
ajv: {
customOptions: {
removeAdditional: 'all' // Refer to [ajv options](https://ajv.js.org/options.html#removeadditional)
},
plugins: [
require('ajv-merge-patch'),
[require('ajv-keywords'), 'instanceof']
// Usage: [plugin, pluginOptions] - Plugin with options
// Usage: plugin - Plugin without options
],
onCreate: (ajv) => {
// Modify the ajv instance as you need.
ajv.addFormat('myFormat', (data) => typeof data === 'string')
}
}
})
```
### `serializerOpts`
<a id="serializer-opts"></a>
Customize the options of the default
[`fast-json-stringify`](https://github.com/fastify/fast-json-stringify#options)
instance that serializes the response's payload:
```js
const fastify = require('fastify')({
serializerOpts: {
rounding: 'ceil'
}
})
```
### `http2SessionTimeout`
<a id="http2-session-timeout"></a>
+ Default: `72000`
Set a default
[timeout](https://nodejs.org/api/http2.html#http2sessionsettimeoutmsecs-callback)
to every incoming HTTP/2 session in milliseconds. The session will be closed on
the timeout.
This option is needed to offer a graceful "close" experience when using
HTTP/2. The low default has been chosen to mitigate denial of service attacks.
When the server is behind a load balancer or can scale automatically this value
can be increased to fit the use case. Node core defaults this to `0`.
### `frameworkErrors`
<a id="framework-errors"></a>
+ Default: `null`
Fastify provides default error handlers for the most common use cases. It is
possible to override one or more of those handlers with custom code using this
option.
> ℹ️ Note:
> Only `FST_ERR_BAD_URL` and `FST_ERR_ASYNC_CONSTRAINT` are implemented at present.
```js
const fastify = require('fastify')({
frameworkErrors: function (error, req, res) {
if (error instanceof FST_ERR_BAD_URL) {
res.code(400)
return res.send("Provided url is not valid")
} else if(error instanceof FST_ERR_ASYNC_CONSTRAINT) {
res.code(400)
return res.send("Provided header is not valid")
} else {
res.send(err)
}
}
})
```
### `clientErrorHandler`
<a id="client-error-handler"></a>
Set a
[clientErrorHandler](https://nodejs.org/api/http.html#http_event_clienterror)
that listens to `error` events emitted by client connections and responds with a
`400`.
It is possible to override the default `clientErrorHandler` using this option.
+ Default:
```js
function defaultClientErrorHandler (err, socket) {
if (err.code === 'ECONNRESET') {
return
}
const body = JSON.stringify({
error: http.STATUS_CODES['400'],
message: 'Client Error',
statusCode: 400
})
this.log.trace({ err }, 'client error')
if (socket.writable) {
socket.end([
'HTTP/1.1 400 Bad Request',
`Content-Length: ${body.length}`,
`Content-Type: application/json\r\n\r\n${body}`
].join('\r\n'))
}
}
```
> ℹ️ Note:
> `clientErrorHandler` operates with raw sockets. The handler is expected to
> return a properly formed HTTP response that includes a status line, HTTP headers
> and a message body. Before attempting to write the socket, the handler should
> check if the socket is still writable as it may have already been destroyed.
```js
const fastify = require('fastify')({
clientErrorHandler: function (err, socket) {
const body = JSON.stringify({
error: {
message: 'Client error',
code: '400'
}
})
// `this` is bound to fastify instance
this.log.trace({ err }, 'client error')
// the handler is responsible for generating a valid HTTP response
socket.end([
'HTTP/1.1 400 Bad Request',
`Content-Length: ${body.length}`,
`Content-Type: application/json\r\n\r\n${body}`
].join('\r\n'))
}
})
```
### `rewriteUrl`
<a id="rewrite-url"></a>
Set a sync callback function that must return a string that allows rewriting
URLs. This is useful when you are behind a proxy that changes the URL.
Rewriting a URL will modify the `url` property of the `req` object.
Note that `rewriteUrl` is called _before_ routing, it is not encapsulated and it
is an instance-wide configuration.
```js
// @param {object} req The raw Node.js HTTP request, not the `FastifyRequest` object.
// @this Fastify The root Fastify instance (not an encapsulated instance).
// @returns {string} The path that the request should be mapped to.
function rewriteUrl (req) {
if (req.url === '/hi') {
this.log.debug({ originalUrl: req.url, url: '/hello' }, 'rewrite url');
return '/hello'
} else {
return req.url;
}
}
```
## RouterOptions
<a id="routeroptions"></a>
Fastify uses [`find-my-way`](https://github.com/delvedor/find-my-way) for its
HTTP router. The `routerOptions` parameter allows passing
[`find-my-way` options](https://github.com/delvedor/find-my-way?tab=readme-ov-file#findmywayoptions)
to customize the HTTP router within Fastify.
### `allowUnsafeRegex`
<a id="allow-unsafe-regex"></a>
+ Default `false`
Fastify uses [find-my-way](https://github.com/delvedor/find-my-way) which is,
disabled by default, so routes only allow safe regular expressions. To use
unsafe expressions, set `allowUnsafeRegex` to `true`.
```js
fastify.get('/user/:id(^([0-9]+){4}$)', (request, reply) => {
// Throws an error without allowUnsafeRegex = true
})
```
### `buildPrettyMeta`
<a id="build-pretty-meta"></a>
Fastify uses [find-my-way](https://github.com/delvedor/find-my-way) which
supports, `buildPrettyMeta` where you can assign a `buildPrettyMeta`
function to sanitize a route's store object to use with the `prettyPrint`
functions. This function should accept a single object and return an object.
```js
fastify.get('/user/:username', (request, reply) => {
routerOptions: {
buildPrettyMeta: route => {
const cleanMeta = Object.assign({}, route.store)
// remove private properties
Object.keys(cleanMeta).forEach(k => {
if (typeof k === 'symbol') delete cleanMeta[k]
})
return cleanMeta // this will show up in the pretty print output!
})
}
})
```
### `caseSensitive`
<a id="case-sensitive"></a>
+ Default: `true`
When `true` routes are registered as case-sensitive. That is, `/foo`
is not equal to `/Foo`.
When `false` then routes are case-insensitive.
Please note that setting this option to `false` goes against
[RFC3986](https://datatracker.ietf.org/doc/html/rfc3986#section-6.2.2.1).
By setting `caseSensitive` to `false`, all paths will be matched as lowercase,
but the route parameters or wildcards will maintain their original letter
casing.
This option does not affect query strings, please refer to
[`querystringParser`](#querystringparser) to change their handling.
```js
fastify.get('/user/:username', (request, reply) => {
// Given the URL: /USER/NodeJS
console.log(request.params.username) // -> 'NodeJS'
})
```
### `constraints`
<a id="constraints"></a>
Fastify's built-in route constraints are provided by `find-my-way`, which
allows constraining routes by `version` or `host`. You can add new constraint
strategies, or override the built-in strategies, by providing a `constraints`
object with strategies for `find-my-way`. You can find more information on
constraint strategies in the
[find-my-way](https://github.com/delvedor/find-my-way) documentation.
```js
const customVersionStrategy = {
storage: function () {
const versions = {}
return {
get: (version) => { return versions[version] || null },
set: (version, store) => { versions[version] = store }
}
},
deriveVersion: (req, ctx) => {
return req.headers['accept']
}
}
const fastify = require('fastify')({
routerOptions: {
constraints: {
version: customVersionStrategy
}
}
})
```
### `defaultRoute`
<a id="on-bad-url"></a>
Fastify uses [find-my-way](https://github.com/delvedor/find-my-way) which supports,
can pass a default route with the option defaultRoute.
```js
const fastify = require('fastify')({
routerOptions: {
defaultRoute: (req, res) => {
res.statusCode = 404
res.end()
}
}
})
```
> ℹ️ Note:
> The `req` and `res` objects passed to `defaultRoute` are the raw Node.js
> `IncomingMessage` and `ServerResponse` instances. They do **not** expose the
> Fastify-specific methods available on `FastifyRequest`/`FastifyReply` (for
> example, `res.send`).
### `ignoreDuplicateSlashes`
<a id="factory-ignore-duplicate-slashes"></a>
+ Default: `false`
Fastify uses [find-my-way](https://github.com/delvedor/find-my-way) to handle
routing. You can use `ignoreDuplicateSlashes` option to remove duplicate slashes
from the path. It removes duplicate slashes in the route path and the request
URL. This option applies to *all* route registrations for the resulting server
instance.
When `ignoreTrailingSlash` and `ignoreDuplicateSlashes` are both set
to `true` Fastify will remove duplicate slashes, and then trailing slashes,
meaning `//a//b//c//` will be converted to `/a/b/c`.
```js
const fastify = require('fastify')({
routerOptions: {
ignoreDuplicateSlashes: true
}
})
// registers "/foo/bar/"
fastify.get('///foo//bar//', function (req, reply) {
reply.send('foo')
})
```
### `ignoreTrailingSlash`
<a id="ignore-slash"></a>
+ Default: `false`
Fastify uses [find-my-way](https://github.com/delvedor/find-my-way) to handle
routing. By default, Fastify will take into account the trailing slashes.
Paths like `/foo` and `/foo/` are treated as different paths. If you want to
change this, set this flag to `true`. That way, both `/foo` and `/foo/` will
point to the same route. This option applies to *all* route registrations for
the resulting server instance.
```js
const fastify = require('fastify')({
routerOptions: {
ignoreTrailingSlash: true
}
})
// registers both "/foo" and "/foo/"
fastify.get('/foo/', function (req, reply) {
reply.send('foo')
})
// registers both "/bar" and "/bar/"
fastify.get('/bar', function (req, reply) {
reply.send('bar')
})
```
### `maxParamLength`
<a id="max-param-length"></a>
+ Default: `100`
You can set a custom length for parameters in parametric (standard, regex, and
multi) routes by using `maxParamLength` option; the default value is 100
characters. If the maximum length limit is reached, the not found route will
be invoked.
This can be useful especially if you have a regex-based route, protecting you
against [ReDoS
attacks](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS).
### `onBadUrl`
<a id="on-bad-url"></a>
Fastify uses [find-my-way](https://github.com/delvedor/find-my-way) which supports,
the use case of a badly formatted url (eg: /hello/%world), by default find-my-way
will invoke the defaultRoute, unless you specify the onBadUrl option.
```js
const fastify = require('fastify')({
routerOptions: {
onBadUrl: (path, req, res) => {
res.statusCode = 400
res.end(`Bad path: ${path}`)
}
}
})
```
As with `defaultRoute`, `req` and `res` are the raw Node.js request/response
objects and do not provide Fastify's decorated helpers.
### `querystringParser`
<a id="querystringparser"></a>
The default query string parser that Fastify uses is the Node.js's core
`querystring` module.
You can use this option to use a custom parser, such as
[`qs`](https://www.npmjs.com/package/qs).
If you only want the keys (and not the values) to be case insensitive we
recommend using a custom parser to convert only the keys to lowercase.
```js
const qs = require('qs')
const fastify = require('fastify')({
routerOptions: {
querystringParser: str => qs.parse(str)
}
})
```
You can also use Fastify's default parser but change some handling behavior,
like the example below for case insensitive keys and values:
```js
const querystring = require('node:querystring')
const fastify = require('fastify')({
routerOptions: {
querystringParser: str => querystring.parse(str.toLowerCase())
}
})
```
### `useSemicolonDelimiter`
<a id="use-semicolon-delimiter"></a>
+ Default `false`
Fastify uses [find-my-way](https://github.com/delvedor/find-my-way) which supports,
separating the path and query string with a `;` character (code 59), e.g. `/dev;foo=bar`.
This decision originated from [delvedor/find-my-way#76]
(https://github.com/delvedor/find-my-way/issues/76). Thus, this option will support
backwards compatibility for the need to split on `;`. To enable support for splitting
on `;` set `useSemicolonDelimiter` to `true`.
```js
const fastify = require('fastify')({
routerOptions: {
useSemicolonDelimiter: true
}
})
fastify.get('/dev', async (request, reply) => {
// An example request such as `/dev;foo=bar`
// Will produce the following query params result `{ foo = 'bar' }`
return request.query
})
```
### `allowErrorHandlerOverride`
<a id="allow-error-handler-override"></a>
* **Default:** `true`
> ⚠ Warning:
> This option will be set to `false` by default
> in the next major release.
When set to `false`, it prevents `setErrorHandler` from being called
multiple times within the same scope, ensuring that the previous error
handler is not unintentionally overridden.
#### Example of incorrect usage:
```js
app.setErrorHandler(function freeSomeResources () {
// Never executed, memory leaks
})
app.setErrorHandler(function anotherErrorHandler () {
// Overrides the previous handler
})
```
## Instance
### Server Methods
#### server
<a id="server"></a>
`fastify.server`: The Node core
[server](https://nodejs.org/api/http.html#http_class_http_server) object as
returned by the [**`Fastify factory function`**](#factory).
> ⚠ Warning:
> If utilized improperly, certain Fastify features could be disrupted.
> It is recommended to only use it for attaching listeners.
#### after
<a id="after"></a>
Invoked when the current plugin and all the plugins that have been registered
within it have finished loading. It is always executed before the method
`fastify.ready`.
```js
fastify
.register((instance, opts, done) => {
console.log('Current plugin')
done()
})
.after(err => {
console.log('After current plugin')
})
.register((instance, opts, done) => {
console.log('Next plugin')
done()
})
.ready(err => {
console.log('Everything has been loaded')
})
```
In case `after()` is called without a function, it returns a `Promise`:
```js
fastify.register(async (instance, opts) => {
console.log('Current plugin')
})
await fastify.after()
console.log('After current plugin')
fastify.register(async (instance, opts) => {
console.log('Next plugin')
})
await fastify.ready()
console.log('Everything has been loaded')
```
#### ready
<a id="ready"></a>
Function called when all the plugins have been loaded. It takes an error
parameter if something went wrong.
```js
fastify.ready(err => {
if (err) throw err
})
```
If it is called without any arguments, it will return a `Promise`:
```js
fastify.ready().then(() => {
console.log('successfully booted!')
}, (err) => {
console.log('an error happened', err)
})
```
#### listen
<a id="listen"></a>
Starts the server and internally waits for the `.ready()` event. The signature
is `.listen([options][, callback])`. Both the `options` object and the
`callback` parameters extend the [Node.js
core](https://nodejs.org/api/net.html#serverlistenoptions-callback) options
object. Thus, all core options are available with the following additional
Fastify specific options:
* listenTextResolver: Set an optional resolver for the text to log after server
has been successfully started. It is possible to override the default
`Server listening at [address]` log entry using this option.
```js
server.listen({
port: 9080,
listenTextResolver: (address) => { return `Prometheus metrics server is listening at ${address}` }
})
```
By default, the server will listen on the address(es) resolved by `localhost`
when no specific host is provided. If listening on any available interface is
desired, then specifying `0.0.0.0` for the address will listen on all IPv4
addresses. The address argument provided above will then return the first such
IPv4 address. The following table details the possible values for `host` when
targeting `localhost`, and what the result of those values for `host` will be.
Host | IPv4 | IPv6
--------------|------|-------
`::` | ✅<sup>*</sup> | ✅
`::` + [`ipv6Only`](https://nodejs.org/api/net.html#serverlistenoptions-callback) | 🚫 | ✅
`0.0.0.0` | ✅ | 🚫
`localhost` | ✅ | ✅
`127.0.0.1` | ✅ | 🚫
`::1` | 🚫 | ✅
<sup>*</sup> Using `::` for the address will listen on all IPv6 addresses and,
depending on OS, may also listen on [all IPv4
addresses](https://nodejs.org/api/net.html#serverlistenport-host-backlog-callback).
Be careful when deciding to listen on all interfaces; it comes with inherent
[security
risks](https://web.archive.org/web/20170831174611/https://snyk.io/blog/mongodb-hack-and-secure-defaults/).
The default is to listen on `port: 0` (which picks the first available open
port) and `host: 'localhost'`:
```js
fastify.listen((err, address) => {
if (err) {
fastify.log.error(err)
process.exit(1)
}
})
```
Specifying an address is also supported:
```js
fastify.listen({ port: 3000, host: '127.0.0.1' }, (err, address) => {
if (err) {
fastify.log.error(err)
process.exit(1)
}
})
```
If no callback is provided a Promise is returned:
```js
fastify.listen({ port: 3000 })
.then((address) => console.log(`server listening on ${address}`))
.catch(err => {
console.log('Error starting server:', err)
process.exit(1)
})
```
When deploying to a Docker, and potentially other, containers, it is advisable
to listen on `0.0.0.0` because they do not default to exposing mapped ports to
`localhost`:
```js
fastify.listen({ port: 3000, host: '0.0.0.0' }, (err, address) => {
if (err) {
fastify.log.error(err)
process.exit(1)
}
})
```
If the `port` is omitted (or is set to zero), a random available port is
automatically chosen (available via `fastify.server.address().port`).
The default options of listen are:
```js
fastify.listen({
port: 0,
host: 'localhost',
exclusive: false,
readableAll: false,
writableAll: false,
ipv6Only: false
}, (err) => {})
```
#### addresses
<a id="addresses"></a>
This method returns an array of addresses that the server is listening on. If
you call it before `listen()` is called or after the `close()` function, it will
return an empty array.
```js
await fastify.listen({ port: 8080 })
const addresses = fastify.addresses()
// [
// { port: 8080, family: 'IPv6', address: '::1' },
// { port: 8080, family: 'IPv4', address: '127.0.0.1' }
// ]
```
Note that the array contains the `fastify.server.address()` too.
#### routing
<a id="routing"></a>
Method to access the `lookup` method of the internal router and match the
request to the appropriate handler:
```js
fastify.routing(req, res)
```
#### route
<a id="route"></a>
Method to add routes to the server, it also has shorthand functions, check
[here](./Routes.md).
#### hasRoute
<a id="hasRoute"></a>
Method to check if a route is already registered to the internal router. It
expects an object as the payload. `url` and `method` are mandatory fields. It
is possible to also specify `constraints`. The method returns `true` if the
route is registered or `false` if not.
```js
const routeExists = fastify.hasRoute({
url: '/',
method: 'GET',
constraints: { version: '1.0.0' } // optional
})
if (routeExists === false) {
// add route
}
```
#### findRoute
<a id="findRoute"></a>
Method to retrieve a route already registered to the internal router. It
expects an object as the payload. `url` and `method` are mandatory fields. It
is possible to also specify `constraints`.
The method returns a route object or `null` if the route cannot be found.
```js
const route = fastify.findRoute({
url: '/artists/:artistId',
method: 'GET',
constraints: { version: '1.0.0' } // optional
})
if (route !== null) {
// perform some route checks
console.log(route.params) // `{artistId: ':artistId'}`
}
```
#### close
<a id="close"></a>
`fastify.close(callback)`: call this function to close the server instance and
run the [`'onClose'`](./Hooks.md#on-close) hook.
Calling `close` will also cause the server to respond to every new incoming
request with a `503` error and destroy that request. See [`return503OnClosing`
flags](#factory-return-503-on-closing) for changing this behavior.
If it is called without any arguments, it will return a Promise:
```js
fastify.close().then(() => {
console.log('successfully closed!')
}, (err) => {
console.log('an error happened', err)
})
```
##### Shutdown lifecycle
When `fastify.close()` is called, the following steps happen in order:
1. The server is flagged as **closing**. New incoming requests receive a
`Connection: close` header (HTTP/1.1) and are handled according to
[`return503OnClosing`](#factory-return-503-on-closing).
2. [`preClose`](./Hooks.md#pre-close) hooks execute. The server is still
processing in-flight requests at this point.
3. **Connection draining** based on the
[`forceCloseConnections`](#forcecloseconnections) option:
- `"idle"` — idle keep-alive connections are closed; in-flight requests
continue.
- `true` — all persistent connections are destroyed immediately.
- `false` — no forced closure; idle connections remain open until they time
out naturally (see [`keepAliveTimeout`](#keepalivetimeout)).
4. The HTTP server **stops accepting** new TCP connections
(`server.close()`). Node.js waits for all in-flight requests to complete
before invoking the callback.
5. [`onClose`](./Hooks.md#on-close) hooks execute. All in-flight requests have
completed and the server is no longer listening.
6. The `close` callback (or the returned Promise) resolves.
```
fastify.close() called
│
├─▶ closing = true (new requests receive 503)
│
├─▶ preClose hooks
│ (in-flight requests still active)
│
├─▶ Connection draining (forceCloseConnections)
│
├─▶ server.close()
│ (waits for in-flight requests to complete)
│
├─▶ onClose hooks
│ (server stopped, all requests done)
│
└─▶ close callback / Promise resolves
```
> ℹ️ Note:
> Upgraded connections (such as WebSocket) are not tracked by the HTTP
> server and will prevent `server.close()` from completing. Close them
> explicitly in a [`preClose`](./Hooks.md#pre-close) hook.
#### decorate*
<a id="decorate"></a>
Function useful if you need to decorate the fastify instance, Reply or Request,
check [here](./Decorators.md).
#### register
<a id="register"></a>
Fastify allows the user to extend its functionality with plugins. A plugin can
be a set of routes, a server decorator, or whatever, check [here](./Plugins.md).
#### addHook
<a id="addHook"></a>
Function to add a specific hook in the lifecycle of Fastify, check
[here](./Hooks.md).
#### prefix
<a id="prefix"></a>
The full path that will be prefixed to a route.
Example:
```js
fastify.register(function (instance, opts, done) {
instance.get('/foo', function (request, reply) {
// Will log "prefix: /v1"
request.log.info('prefix: %s', instance.prefix)
reply.send({ prefix: instance.prefix })
})
instance.register(function (instance, opts, done) {
instance.get('/bar', function (request, reply) {
// Will log "prefix: /v1/v2"
request.log.info('prefix: %s', instance.prefix)
reply.send({ prefix: instance.prefix })
})
done()
}, { prefix: '/v2' })
done()
}, { prefix: '/v1' })
```
#### pluginName
<a id="pluginName"></a>
Name of the current plugin. The root plugin is called `'fastify'`. There are
different ways to define a name (in order).
1. If you use [fastify-plugin](https://github.com/fastify/fastify-plugin) the
metadata `name` is used.
2. If the exported plugin has the `Symbol.for('fastify.display-name')` property,
then the value of that property is used.
Example: `pluginFn[Symbol.for('fastify.display-name')] = "Custom Name"`
3. If you `module.exports` a plugin the filename is used.
4. If you use a regular [function
declaration](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions#defining_functions)
the function name is used.
*Fallback*: The first two lines of your plugin will represent the plugin name.
Newlines are replaced by ` -- `. This will help to identify the root cause when
you deal with many plugins.
> ⚠ Warning:
> If you have to deal with nested plugins, the name differs with the usage of
> the [fastify-plugin](https://github.com/fastify/fastify-plugin) because
> no new scope is created and therefore we have no place to attach contextual
> data. In that case, the plugin name will represent the boot order of all
> involved plugins in the format of `fastify -> plugin-A -> plugin-B`.
#### hasPlugin
<a id="hasPlugin"></a>
Method to check if a specific plugin has been registered. Relies on the plugin
metadata name. Returns `true` if the plugin is registered. Otherwise, returns
`false`.
```js
const fastify = require('fastify')()
fastify.register(require('@fastify/cookie'), {
secret: 'my-secret',
parseOptions: {}
})
fastify.ready(() => {
fastify.hasPlugin('@fastify/cookie') // true
})
```
#### listeningOrigin
<a id="listeningOrigin"></a>
The current origin the server is listening to.
For example, a TCP socket based server returns
a base address like `http://127.0.0.1:3000`,
and a Unix socket server will return the socket
path, e.g. `fastify.temp.sock`.
#### log
<a id="log"></a>
The logger instance, check [here](./Logging.md).
#### version
<a id="version"></a>
Fastify version of the instance. Used for plugin support. See
[Plugins](./Plugins.md#handle-the-scope) for information on how the version is
used by plugins.
#### inject
<a id="inject"></a>
Fake HTTP injection (for testing purposes)
[here](../Guides/Testing.md#benefits-of-using-fastifyinject).
#### addHttpMethod
<a id="addHttpMethod"></a>
Fastify supports the `GET`, `HEAD`, `TRACE`, `DELETE`, `OPTIONS`,
`PATCH`, `PUT` and `POST` HTTP methods by default.
The `addHttpMethod` method allows to add any non standard HTTP
methods to the server that are [supported by Node.js](https://nodejs.org/api/http.html#httpmethods).
```js
// Add a new HTTP method called 'MKCOL' that supports a request body
fastify.addHttpMethod('MKCOL', { hasBody: true, })
// Add a new HTTP method called 'COPY' that does not support a request body
fastify.addHttpMethod('COPY')
```
After calling `addHttpMethod`, it is possible to use the route shorthand
methods to define routes for the new HTTP method:
```js
fastify.addHttpMethod('MKCOL', { hasBody: true })
fastify.mkcol('/', (req, reply) => {
// Handle the 'MKCOL' request
})
```
> ⚠ Warning:
> `addHttpMethod` overrides existing methods.
#### addSchema
<a id="add-schema"></a>
`fastify.addSchema(schemaObj)`, adds a JSON schema to the Fastify instance. This
allows you to reuse it everywhere in your application just by using the standard
`$ref` keyword.
To learn more, read the [Validation and
Serialization](./V