fastify
Version:
Fast and low overhead web framework, for Node.js
1,558 lines (1,242 loc) • 66.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)
- [`ignoreTrailingSlash`](#ignoretrailingslash)
- [`ignoreDuplicateSlashes`](#ignoreduplicateslashes)
- [`maxParamLength`](#maxparamlength)
- [`bodyLimit`](#bodylimit)
- [`onProtoPoisoning`](#onprotopoisoning)
- [`onConstructorPoisoning`](#onconstructorpoisoning)
- [`logger`](#logger)
- [`disableRequestLogging`](#disablerequestlogging)
- [`serverFactory`](#serverfactory)
- [`jsonShorthand`](#jsonshorthand)
- [`caseSensitive`](#casesensitive)
- [`allowUnsafeRegex`](#allowunsaferegex)
- [`requestIdHeader`](#requestidheader)
- [`requestIdLogLabel`](#requestidloglabel)
- [`genReqId`](#genreqid)
- [`trustProxy`](#trustproxy)
- [`pluginTimeout`](#plugintimeout)
- [`querystringParser`](#querystringparser)
- [`exposeHeadRoutes`](#exposeheadroutes)
- [`constraints`](#constraints)
- [`return503OnClosing`](#return503onclosing)
- [`ajv`](#ajv)
- [`serializerOpts`](#serializeropts)
- [`http2SessionTimeout`](#http2sessiontimeout)
- [`frameworkErrors`](#frameworkerrors)
- [`clientErrorHandler`](#clienterrorhandler)
- [`rewriteUrl`](#rewriteurl)
- [`useSemicolonDelimiter`](#usesemicolondelimiter)
- [Instance](#instance)
- [Server Methods](#server-methods)
- [server](#server)
- [after](#after)
- [ready](#ready)
- [listen](#listen)
- [`listenTextResolver`](#listentextresolver)
- [addresses](#addresses)
- [getDefaultRoute](#getdefaultroute)
- [setDefaultRoute](#setdefaultroute)
- [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)
- [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/dist/latest-v14.x/docs/api/http.html#http_http_createserver_options_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-v14.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-v14.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).
> **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
### `ignoreTrailingSlash`
<a id="factory-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')({
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')
})
```
### `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')({
ignoreDuplicateSlashes: true
})
// registers "/foo/bar/"
fastify.get('///foo//bar//', function (req, reply) {
reply.send('foo')
})
```
### `maxParamLength`
<a id="factory-max-param-length"></a>
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).
### `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.
+ `pinoInstance`: a previously instantiated instance of Pino. The internal
logger will point to this 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 custom logger instance. The logger must 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')({logger: 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.
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.
### `jsonShorthand`
<a id="schema-json-shorthand"></a>
+ Default: `true`
By default, Fastify will automatically infer the root properties
of JSON Schemas if it does not find valid root properties according to the JSON
Schema spec. If you wish to implement your own schema validation compiler, to
parse schemas as JTD instead of JSON Schema for example, then you can explicitly
set this option to `false` to make sure the schemas you receive are unmodified
and are not being treated internally as JSON Schema.
Fastify does not throw on invalid schemas so if this option is set to `false`
in an existing project, check that none of your existing schemas become
invalid as a result, as they will be treated as catch-alls.
```js
const AjvJTD = require('ajv/dist/jtd'/* only valid for AJV v7+ */)
const ajv = new AjvJTD({
// This would let you throw at start for invalid JTD schema objects
allErrors: process.env.NODE_ENV === 'development'
})
const fastify = Fastify({ jsonShorthand: false })
fastify.setValidatorCompiler(({ schema }) => {
return ajv.compile(schema)
})
fastify.post('/', {
schema: {
body: {
properties: {
foo: { type: 'uint8' }
}
}
},
handler (req, reply) { reply.send({ ok: 1 }) }
})
```
### `caseSensitive`
<a id="factory-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'
})
```
### `allowUnsafeRegex`
<a id="factory-allow-unsafe-regex"></a>
+ Default `false`
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
})
```
### `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 `false` will always use [genReqId](#genreqid).
```js
const fastify = require('fastify')({
requestIdHeader: 'x-custom-id', // -> use 'X-Custom-Id' header if available
//requestIdHeader: false, // -> always use genReqId
})
```
### `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
[`proxy-addr`](https://www.npmjs.com/package/proxy-addr) package.
You may access the `ip`, `ips`, `hostname` 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.hostname)
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 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')({
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')({
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.
### `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')({
constraints: {
version: customVersionStrategy
}
})
```
### `return503OnClosing`
<a id="factory-return-503-on-closing"></a>
+ Default: `true`
Returns 503 after calling `close` server method. If `false`, the server routes
the incoming request as usual.
### `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
]
}
})
```
### `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;
}
}
```
### `useSemicolonDelimiter`
<a id="use-semicolon-delimiter"></a>
+ Default `true`
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 disable support for splitting
on `;` set `useSemicolonDelimiter` to `false`.
```js
const fastify = require('fastify')({
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
})
```
## 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`
<a id="listen-text-resolver"></a>
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 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.
#### getDefaultRoute
<a id="getDefaultRoute"></a>
> **Warning**
> This method is deprecated and will be removed in the next Fastify
> major version.
The `defaultRoute` handler handles requests that do not match any URL specified
by your Fastify application. This defaults to the 404 handler, but can be
overridden with [setDefaultRoute](#setdefaultroute). Method to get the
`defaultRoute` for the server:
```js
const defaultRoute = fastify.getDefaultRoute()
```
#### setDefaultRoute
<a id="setDefaultRoute"></a>
> **Warning**
> This method is deprecated and will be removed in the next Fastify
> major version. Please, consider using `setNotFoundHandler` or a wildcard
> matching route.
The default 404 handler, or one set using `setNotFoundHandler`, will
never trigger if the default route is overridden. This sets the handler for the
Fastify application, not just the current instance context. Use
[setNotFoundHandler](#setnotfoundhandler) if you want to customize 404 handling
instead.
This method sets the `defaultRoute` for the server. Note that, its purpose is
to interact with the underlying raw requests. Unlike other Fastify handlers, the
arguments received are of type [RawRequest](./TypeScript.md#rawrequest) and
[RawReply](./TypeScript.md#rawreply) respectively.
```js
const defaultRoute = function (req, res) {
// req = RawRequest
// res = RawReply
res.end('hello world')
}
fastify.setDefaultRoute(defaultRoute)
```
#### 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)
})
```
#### 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).
#### 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](./Validation-and-Serialization.md) documentation.
#### getSchemas
<a id="get-schemas"></a>
`fastify.getSchemas()`, returns a hash of all schemas added via `.addSchema`.
The keys of the hash are the `$id`s of the JSON Schema provided.
#### getSchema
<a id="get-schema"></a>
`fastify.getSchema(id)`, return the JSON schema added with `.addSchema` and the
matching `id`. It returns `undefined` if it is not found.
#### setReplySerializer
<a id="set-reply-serializer"></a>
Set the reply serializer for all the routes. This will be used as default if a
[Reply.serializer(func)](./Reply.md#serializerfunc) has not been set. The
handler is fully encapsulated, so different plugins can set different error
handlers. Note: the function parameter is called only for status `2xx`. Check
out the [`setErrorHandler`](#seterrorhandler) for errors.
```js
fastify.setReplySerializer(function (payload, statusCode){
// serialize the payload with a sync function
return `my serialized ${statusCode} content: ${payload}`
})
```
#### setValidatorCompiler
<a id="set-validator-compiler"></a>
Set the schema validator compiler for all routes. See
[#schema-validator](./Validation-and-Serialization.md#schema-validator).
#### setSchemaErrorFormatter
<a id="set-schema-error-formatter"></a>
Set the schema error formatter for all routes. See
[#error-handling](./Validation-and-Serialization.md#schemaerrorformatter).
#### setSerializerCompiler
<a id="set-serializer-resolver"></a>
Set the schema serializer compiler for all routes. See
[#schema-serializer](./Validation-and-Serialization.md#schema-serializer).
> **Note**
> [`setReplySerializer`](#set-reply-serializer) has priority if set!
#### validatorCompiler
<a id="validator-compiler"></a>
This property can be used to get the schema validator. If not set, it will be
`null` until the server starts, then it will be a function with the signature
`function ({ schema, method, url, httpPart })` that returns the input `schema`
compiled to a function for validating data. The input `schema` can access all
the shared schemas added with [`.addSchema`](#add-schema) function.
#### serializerCompiler
<a id="serializer-compiler"></a>
This property can be used to get the schema serializer. If not set, it will be
`null` until the server starts, then it will be a function with the signature
`function ({ schema, method, url, httpPart })` that returns the input `schema`
compiled to a function for validating data. The input `schema` can access all
the shared schemas added with [`.addSchema`](#add-schema) function.
#### schemaErrorFormatter
<a id="schema-error-formatter"></a>
This property can be used to set a function to format errors that happen while
the `validationCompiler` fails to validate the schema. See
[#error-handling](./Validation-and-Serialization.md#schemaerrorformatter).
#### schemaController
<a id="schema-controller"></a>
This property can be used to fully manage:
- `bucket`: where the schemas of your application will be stored
- `compilersFactory`: what module must compile the JSON schemas
It can be useful when your schemas are stored in another data structure that is
unknown to Fastify.
Another use case is to tweak all the schemas processing. Doing so it is possible
to use Ajv v8 JTD or Standalone feature. To use such as JTD or the Standalone
mode, refers to the [`@fastify/ajv-compiler`
documentation](https://github.com/fastify/ajv-compiler#usage).
```js
const fastify = Fastify({
schemaController: {
/**
* This factory is called whenever `fastify.register()` is called.
* It may receive as input the schemas of the parent context if some schemas have been added.
* @param {object} parentSchemas these schemas will be returned by the
* `getSchemas()` method function of the returned `bucket`.
*/
bucket: function factory (parentSchemas) {
return {
add (inputSchema) {
// This function must store the schema added by the user.
// This function is invoked when `fastify.addSchema()` is called.
},
getSchema (schema$id) {
// This function must return the raw schema requested by the `schema$id`.
// This function is invoked when `fastify.getSchema(id)` is called.
return aSchema
},
getSchemas () {
// This function must return all the schemas referenced by the routes schemas' $ref
// It must return a JSON where the property is the schema `$id` and the value is the raw JSON Schema.
const allTheSchemaStored = {
'schema$id1': schema1,
'schema$id2': schema2
}
return allTheSchemaStored
}
}
},
/**
* The compilers factory lets you fully control the validator and serializer
* in the Fastify's lifecycle, providing the encapsulation to your compilers.
*/
compilersFactory: {
/**
* This factory is called whenever a new validator instance is needed.
* It may be called whenever `fastify.register()` is called only if new schemas have been added to the
* encapsulation context.
* It may receive as input the schemas of the parent context if some schemas have been added.
* @param {object} externalSchemas these schemas will be returned by the
* `bucket.getSchemas()`. Needed to resolve the external references $ref.
* @param {object} ajvServerOption the server `ajv` options to build your compilers accordingly
*/
buildValidator: function factory (externalSchemas, ajvServerOption) {
// This factory function must return a schema validator compiler.
// See [#schema-validator](./Validation-and-Serialization.md#schema-validator) for details.
const yourAjvInstance = new Ajv(ajvServerOption.customOptions)
return function validatorCompiler ({ schema, method, url, httpPart }) {
return yourAjvInstance.compile(schema)
}
},
/**
* This factory is called whenever a new serializer instance is needed.
* It may be called whenever `fastify.register()` is called only if new schemas have been added to the
* encapsulation context.
* It may receive as input the schemas of the parent context if some schemas have been added.
* @param {object} externalSchemas these schemas will be returned by the
* `bucket.getSchemas()`. Needed to resolve the external references $ref.
* @param {object} serializerOptsServerOption the server `serializerOpts`
* options to build your compilers accordingly
*/
buildSerializer: function factory (externalSchemas, serializerOptsServerOption) {
// This factory function must return a schema serializer compiler.
// See [#schema-serializer](./Validation-and-Serialization.md#schema-serializer) for details.
return function serializerCompiler ({ schema, method, url, httpStatus, contentType }) {
return data => JSON.stringify(data)
}
}
}
}
});
```
#### setNotFoundHandler
<a id="set-not-found-handler"></a>
`fastify.setNotFoundHandler(handler(request, reply))`: set the 404 handler. This
call is encapsulated by prefix, so different plugins can set different not found
handlers if a different [`prefix` option](./Plugins.md#route-prefixing-option)
is passed to `fastify.register()`. The handler is treated as a regular route
handler so requests will go through the full [Fastify
lifecycle](./Lifecycle.md#lifecycle). *async-await* is supported as well.
You can also register [`preValidation`](./Hooks.md#route-hooks) and
[`preHandler`](./Hooks.md#route-hooks) hooks for the 404 handler.
> **Note**
> The `preValidation` hook registered using this method will run for a
> route that Fastify does not recognize and **not** when a route handler manually
> calls [`reply.callNotFound`](./Reply.md#call-not-found). In which case, only
> preHandler will be run.
```js
fastify.setNotFoundHandler({
preValidation: (req, reply, done) => {
// your code
done()
},
preHandler: (req, reply, done) => {
// your code
done()
}
}, function (request, reply) {
// Default not found handler with preValidation and preHandler hooks
})
fastify.register(function (instance, options, done) {
instance.setNotFoundHandler(funct