fastify 6.0.0-alpha.5 → 6.0.0-alpha.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/build/build-validation.js +2 -0
- package/docs/Guides/Ecosystem.md +4 -0
- package/docs/Guides/Migration-Guide-V5.md +2 -2
- package/docs/Guides/Serverless.md +33 -10
- package/docs/Reference/Errors.md +13 -0
- package/docs/Reference/Hooks.md +13 -0
- package/docs/Reference/Reply.md +786 -697
- package/docs/Reference/Request.md +303 -107
- package/docs/Reference/Server.md +39 -2
- package/docs/Reference/Validation-and-Serialization.md +15 -1
- package/fastify.d.ts +1 -0
- package/fastify.js +35 -1
- package/lib/config-validator.js +102 -73
- package/lib/content-type-parser.js +14 -2
- package/lib/context.js +2 -1
- package/lib/decorate.js +4 -3
- package/lib/error-handler.js +21 -4
- package/lib/error-status.js +4 -2
- package/lib/errors.js +15 -9
- package/lib/reply.js +12 -11
- package/lib/request.js +3 -2
- package/lib/route.js +34 -5
- package/lib/schemas.js +44 -32
- package/package.json +8 -3
- package/test/close-disposable.test.js +154 -0
- package/test/constrained-routes.test.js +4 -2
- package/test/content-parser.test.js +39 -0
- package/test/decorator.test.js +29 -0
- package/test/diagnostics-channel/error-status.test.js +35 -2
- package/test/handler-timeout.test.js +224 -0
- package/test/internals/all.test.js +5 -0
- package/test/internals/errors.test.js +18 -9
- package/test/internals/initial-config.test.js +2 -0
- package/test/internals/server.test.js +6 -4
- package/test/reply-error.test.js +82 -0
- package/test/reply-trailers.test.js +159 -1
- package/test/router-compile.test.js +241 -0
- package/test/schema-serialization.test.js +120 -7
- package/test/types/fastify.tst.ts +4 -0
- package/test/types/instance.tst.ts +1 -1
- package/test/types/route.tst.ts +16 -0
- package/test/types/using.tst.ts +20 -0
- package/test/validation-error-handling.test.js +21 -1
- package/types/instance.d.ts +5 -1
- package/types/route.d.ts +1 -0
package/docs/Reference/Reply.md
CHANGED
|
@@ -1,45 +1,52 @@
|
|
|
1
1
|
<h1 align="center">Fastify</h1>
|
|
2
2
|
|
|
3
3
|
## Reply
|
|
4
|
-
- [
|
|
5
|
-
|
|
6
|
-
- [
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
- [
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
- [
|
|
33
|
-
- [
|
|
34
|
-
- [
|
|
35
|
-
- [
|
|
36
|
-
- [
|
|
37
|
-
- [
|
|
38
|
-
- [
|
|
39
|
-
- [
|
|
40
|
-
- [
|
|
41
|
-
- [
|
|
42
|
-
|
|
4
|
+
- [Introduction](#introduction)
|
|
5
|
+
- [Reply](#reply-object)
|
|
6
|
+
- [Properties](#properties)
|
|
7
|
+
- [.statusCode](#statuscode)
|
|
8
|
+
- [.sent](#sent)
|
|
9
|
+
- [.request](#request)
|
|
10
|
+
- [.log](#log)
|
|
11
|
+
- [.raw](#raw)
|
|
12
|
+
- [.server](#server)
|
|
13
|
+
- [.routeOptions](#routeoptions)
|
|
14
|
+
- [.mediaType](#mediatype)
|
|
15
|
+
- [.elapsedTime](#elapsedtime)
|
|
16
|
+
- [Methods](#methods)
|
|
17
|
+
- [.send(data)](#senddata)
|
|
18
|
+
- [Objects](#objects)
|
|
19
|
+
- [Strings](#strings)
|
|
20
|
+
- [Buffers](#buffers)
|
|
21
|
+
- [TypedArrays](#typedarrays)
|
|
22
|
+
- [Streams](#streams)
|
|
23
|
+
- [ReadableStream](#readablestream)
|
|
24
|
+
- [Response](#response)
|
|
25
|
+
- [Errors](#errors)
|
|
26
|
+
- [Async-Await and Promises](#async-await-and-promises)
|
|
27
|
+
- [Type of the final payload](#type-of-the-final-payload)
|
|
28
|
+
- [.code(statusCode)](#codestatuscode)
|
|
29
|
+
- [.header(key, value)](#headerkey-value)
|
|
30
|
+
- [.headers(object)](#headersobject)
|
|
31
|
+
- [.type(contentType)](#typecontenttype)
|
|
32
|
+
- [.redirect(dest, [code])](#redirectdest-code)
|
|
33
|
+
- [.getHeader(key)](#getheaderkey)
|
|
34
|
+
- [.getHeaders()](#getheaders)
|
|
35
|
+
- [.hasHeader(key)](#hasheaderkey)
|
|
36
|
+
- [.removeHeader(key)](#removeheaderkey)
|
|
37
|
+
- [.callNotFound()](#callnotfound)
|
|
38
|
+
- [.hijack()](#hijack)
|
|
39
|
+
- [.serializer(func)](#serializerfunc)
|
|
40
|
+
- [.serialize(payload)](#serializepayload)
|
|
41
|
+
- [.trailer(key, function)](#trailerkey-function)
|
|
42
|
+
- [.hasTrailer(key)](#hastrailerkey)
|
|
43
|
+
- [.removeTrailer(key)](#removetrailerkey)
|
|
44
|
+
- [.writeEarlyHints(hints, callback)](#writeearlyhintshints-callback)
|
|
45
|
+
- [.then(fulfilled, rejected)](#thenfulfilled-rejected)
|
|
46
|
+
- [.getDecorator(name)](#getdecoratorname)
|
|
47
|
+
- [.getSerializationFunction(schema | httpStatus, [contentType])](#getserializationfunctionschema--httpstatus-contenttype)
|
|
48
|
+
- [.compileSerializationSchema(schema, [httpStatus], [contentType])](#compileserializationschemaschema-httpstatus-contenttype)
|
|
49
|
+
- [.serializeInput(data, [schema | httpStatus], [httpStatus], [contentType])](#serializeinputdata-schema--httpstatus-httpstatus-contenttype)
|
|
43
50
|
|
|
44
51
|
### Introduction
|
|
45
52
|
<a id="introduction"></a>
|
|
@@ -66,7 +73,7 @@ since the request was received by Fastify.
|
|
|
66
73
|
- `.hasTrailer(key)` - Determine if a trailer has been set.
|
|
67
74
|
- `.removeTrailer(key)` - Remove the value of a previously set trailer.
|
|
68
75
|
- `.type(value)` - Sets the header `Content-Type`.
|
|
69
|
-
- `.redirect(dest, [code
|
|
76
|
+
- `.redirect(dest, [code])` - Redirect to the specified URL, the status code is
|
|
70
77
|
optional (defaults to `302`).
|
|
71
78
|
- `.callNotFound()` - Invokes the custom not found handler.
|
|
72
79
|
- `.serialize(payload)` - Serializes the specified payload using the default
|
|
@@ -95,6 +102,7 @@ since the request was received by Fastify.
|
|
|
95
102
|
from Node core.
|
|
96
103
|
- `.log` - The logger instance of the incoming request.
|
|
97
104
|
- `.request` - The incoming request.
|
|
105
|
+
- `.getDecorator(name)` - Returns the value of a reply decorator.
|
|
98
106
|
|
|
99
107
|
```js
|
|
100
108
|
fastify.get('/', options, function (request, reply) {
|
|
@@ -106,22 +114,13 @@ fastify.get('/', options, function (request, reply) {
|
|
|
106
114
|
})
|
|
107
115
|
```
|
|
108
116
|
|
|
109
|
-
###
|
|
110
|
-
<a id="
|
|
111
|
-
|
|
112
|
-
If not set via `reply.code`, the resulting `statusCode` will be `200`.
|
|
113
|
-
|
|
114
|
-
### .elapsedTime
|
|
115
|
-
<a id="elapsedTime"></a>
|
|
116
|
-
|
|
117
|
-
Invokes the custom response time getter to calculate the amount of time passed
|
|
118
|
-
since the request was received by Fastify.
|
|
117
|
+
### Reply
|
|
118
|
+
<a id="reply-object"></a>
|
|
119
119
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
```
|
|
120
|
+
#### Properties
|
|
121
|
+
<a id="properties"></a>
|
|
123
122
|
|
|
124
|
-
|
|
123
|
+
##### .statusCode
|
|
125
124
|
<a id="statusCode"></a>
|
|
126
125
|
|
|
127
126
|
This property reads and sets the HTTP status code. It is an alias for
|
|
@@ -131,20 +130,69 @@ if (reply.statusCode >= 299) {
|
|
|
131
130
|
reply.statusCode = 500
|
|
132
131
|
}
|
|
133
132
|
```
|
|
134
|
-
### .mediaType
|
|
135
|
-
<a id="mediatype"></a>
|
|
136
133
|
|
|
137
|
-
|
|
138
|
-
|
|
134
|
+
##### .sent
|
|
135
|
+
<a id="sent"></a>
|
|
136
|
+
|
|
137
|
+
As the name suggests, `.sent` is a property to indicate if a response has been
|
|
138
|
+
sent via `reply.send()`. It will also be `true` in case `reply.hijack()` was
|
|
139
|
+
used.
|
|
140
|
+
|
|
141
|
+
In case a route handler is defined as an async function or it returns a promise,
|
|
142
|
+
it is possible to call `reply.hijack()` to indicate that the automatic
|
|
143
|
+
invocation of `reply.send()` once the handler promise resolve should be skipped.
|
|
144
|
+
By calling `reply.hijack()`, an application claims full responsibility for the
|
|
145
|
+
low-level request and response. Moreover, hooks will not be invoked.
|
|
146
|
+
|
|
147
|
+
##### .request
|
|
148
|
+
<a id="request"></a>
|
|
149
|
+
|
|
150
|
+
The [`Request`](./Request.md) object of the incoming request this reply belongs
|
|
151
|
+
to.
|
|
139
152
|
|
|
140
153
|
```js
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
}
|
|
154
|
+
fastify.addHook('onSend', async function (request, reply, payload) {
|
|
155
|
+
reply.header('x-request-url', reply.request.url)
|
|
156
|
+
})
|
|
145
157
|
```
|
|
146
158
|
|
|
147
|
-
|
|
159
|
+
##### .log
|
|
160
|
+
<a id="log"></a>
|
|
161
|
+
|
|
162
|
+
The logger instance of the incoming request. It is the same instance as
|
|
163
|
+
`request.log`, so every log line includes the request id. See
|
|
164
|
+
[Logging](./Logging.md) for more information.
|
|
165
|
+
|
|
166
|
+
```js
|
|
167
|
+
fastify.get('/', function (request, reply) {
|
|
168
|
+
reply.log.info('sending the response')
|
|
169
|
+
reply.send({ hello: 'world' })
|
|
170
|
+
})
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
##### .raw
|
|
174
|
+
<a id="raw"></a>
|
|
175
|
+
|
|
176
|
+
This is the
|
|
177
|
+
[`http.ServerResponse`](https://nodejs.org/dist/latest-v20.x/docs/api/http.html#http_class_http_serverresponse)
|
|
178
|
+
from Node core. Whilst you are using the Fastify `Reply` object, the use of
|
|
179
|
+
`Reply.raw` functions is at your own risk as you are skipping all the Fastify
|
|
180
|
+
logic of handling the HTTP response. e.g.:
|
|
181
|
+
|
|
182
|
+
```js
|
|
183
|
+
app.get('/cookie-2', (req, reply) => {
|
|
184
|
+
reply.setCookie('session', 'value', { secure: false }) // this will not be used
|
|
185
|
+
|
|
186
|
+
// in this case we are using only the nodejs http server response object
|
|
187
|
+
reply.raw.writeHead(200, { 'Content-Type': 'text/plain' })
|
|
188
|
+
reply.raw.write('ok')
|
|
189
|
+
reply.raw.end()
|
|
190
|
+
})
|
|
191
|
+
```
|
|
192
|
+
Another example of the misuse of `Reply.raw` is explained in
|
|
193
|
+
[Reply](#getheaders).
|
|
194
|
+
|
|
195
|
+
##### .server
|
|
148
196
|
<a id="server"></a>
|
|
149
197
|
|
|
150
198
|
The Fastify server instance, scoped to the current [encapsulation
|
|
@@ -160,440 +208,571 @@ fastify.get('/', async function (req, rep) {
|
|
|
160
208
|
})
|
|
161
209
|
```
|
|
162
210
|
|
|
163
|
-
|
|
164
|
-
<a id="
|
|
165
|
-
|
|
166
|
-
Sets a response header. If the value is omitted or undefined, it is coerced to
|
|
167
|
-
`''`.
|
|
168
|
-
|
|
169
|
-
> ℹ️ Note:
|
|
170
|
-
> The header's value must be properly encoded using
|
|
171
|
-
> [`encodeURI`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI)
|
|
172
|
-
> or similar modules such as
|
|
173
|
-
> [`encodeurl`](https://www.npmjs.com/package/encodeurl). Invalid characters
|
|
174
|
-
> will result in a 500 `TypeError` response.
|
|
175
|
-
|
|
176
|
-
For more information, see
|
|
177
|
-
[`http.ServerResponse#setHeader`](https://nodejs.org/dist/latest-v20.x/docs/api/http.html#http_response_setheader_name_value).
|
|
178
|
-
|
|
179
|
-
- ### set-cookie
|
|
180
|
-
<a id="set-cookie"></a>
|
|
181
|
-
|
|
182
|
-
- When sending different values as a cookie with `set-cookie` as the key,
|
|
183
|
-
every value will be sent as a cookie instead of replacing the previous
|
|
184
|
-
value.
|
|
185
|
-
|
|
186
|
-
```js
|
|
187
|
-
reply.header('set-cookie', 'foo');
|
|
188
|
-
reply.header('set-cookie', 'bar');
|
|
189
|
-
```
|
|
190
|
-
- The browser will only consider the latest reference of a key for the
|
|
191
|
-
`set-cookie` header. This is done to avoid parsing the `set-cookie` header
|
|
192
|
-
when added to a reply and speeds up the serialization of the reply.
|
|
193
|
-
|
|
194
|
-
- To reset the `set-cookie` header, you need to make an explicit call to
|
|
195
|
-
`reply.removeHeader('set-cookie')`, read more about `.removeHeader(key)`
|
|
196
|
-
[here](#removeheaderkey).
|
|
197
|
-
|
|
211
|
+
##### .routeOptions
|
|
212
|
+
<a id="routeoptions"></a>
|
|
198
213
|
|
|
214
|
+
A read-only reference to the route options of the incoming request. It is the
|
|
215
|
+
same object as [`request.routeOptions`](./Request.md).
|
|
199
216
|
|
|
200
|
-
### .headers(object)
|
|
201
|
-
<a id="headers"></a>
|
|
202
|
-
|
|
203
|
-
Sets all the keys of the object as response headers.
|
|
204
|
-
[`.header`](#headerkey-value) will be called under the hood.
|
|
205
217
|
```js
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
'x-bar': 'bar'
|
|
218
|
+
fastify.get('/', { config: { foo: 'bar' } }, function (request, reply) {
|
|
219
|
+
reply.send(reply.routeOptions.config.foo) // bar
|
|
209
220
|
})
|
|
210
221
|
```
|
|
211
222
|
|
|
212
|
-
|
|
213
|
-
<a id="
|
|
223
|
+
##### .mediaType
|
|
224
|
+
<a id="mediatype"></a>
|
|
225
|
+
|
|
226
|
+
Returns the media type extracted from `Content-Type` header. When `Content-Type`
|
|
227
|
+
header is missing, it will return `undefined`.
|
|
214
228
|
|
|
215
|
-
Retrieves the value of a previously set header.
|
|
216
229
|
```js
|
|
217
|
-
reply.
|
|
218
|
-
reply.
|
|
230
|
+
if (reply.mediaType === 'image/gif') {
|
|
231
|
+
const versionBuffer = new Uint8Array(reply.payload, 3, 3)
|
|
232
|
+
reply.header('x-gif-version', new TextDecoder().decode(versionBuffer))
|
|
233
|
+
}
|
|
219
234
|
```
|
|
220
235
|
|
|
221
|
-
|
|
222
|
-
<a id="
|
|
236
|
+
##### .elapsedTime
|
|
237
|
+
<a id="elapsedTime"></a>
|
|
223
238
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
over those set via `http.ServerResponse`.
|
|
239
|
+
Invokes the custom response time getter to calculate the amount of time passed
|
|
240
|
+
since the request was received by Fastify.
|
|
227
241
|
|
|
228
242
|
```js
|
|
229
|
-
reply.
|
|
230
|
-
reply.header('x-bar', 'bar')
|
|
231
|
-
reply.raw.setHeader('x-foo', 'foo2')
|
|
232
|
-
reply.getHeaders() // { 'x-foo': 'foo', 'x-bar': 'bar' }
|
|
243
|
+
const milliseconds = reply.elapsedTime
|
|
233
244
|
```
|
|
234
245
|
|
|
235
|
-
|
|
236
|
-
<a id="
|
|
246
|
+
#### Methods
|
|
247
|
+
<a id="methods"></a>
|
|
237
248
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
reply.header('x-foo', 'foo')
|
|
241
|
-
reply.removeHeader('x-foo')
|
|
242
|
-
reply.getHeader('x-foo') // undefined
|
|
243
|
-
```
|
|
249
|
+
##### .send(data)
|
|
250
|
+
<a id="send"></a>
|
|
244
251
|
|
|
245
|
-
|
|
246
|
-
|
|
252
|
+
As the name suggests, `.send()` is the function that sends the payload to the
|
|
253
|
+
end user.
|
|
247
254
|
|
|
248
|
-
|
|
255
|
+
###### Objects
|
|
256
|
+
<a id="send-object"></a>
|
|
249
257
|
|
|
250
|
-
|
|
251
|
-
|
|
258
|
+
As noted above, if you are sending JSON objects, `send` will serialize the
|
|
259
|
+
object with
|
|
260
|
+
[fast-json-stringify](https://www.npmjs.com/package/fast-json-stringify) if you
|
|
261
|
+
set an output schema, otherwise, `JSON.stringify()` will be used.
|
|
262
|
+
```js
|
|
263
|
+
fastify.get('/json', options, function (request, reply) {
|
|
264
|
+
reply.send({ hello: 'world' })
|
|
265
|
+
})
|
|
266
|
+
```
|
|
252
267
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
This can improve performance by allowing the client to preload
|
|
256
|
-
or preconnect to resources while the server is still generating the response.
|
|
268
|
+
###### Strings
|
|
269
|
+
<a id="send-string"></a>
|
|
257
270
|
|
|
258
|
-
|
|
271
|
+
If you pass a string to `send` without a `Content-Type`, it will be sent as
|
|
272
|
+
`text/plain; charset=utf-8`. If you set the `Content-Type` header and pass a
|
|
273
|
+
string to `send`, it will be serialized with the custom serializer if one is
|
|
274
|
+
set, otherwise, it will be sent unmodified.
|
|
259
275
|
|
|
260
|
-
|
|
276
|
+
> ℹ️ Note:
|
|
277
|
+
> Even when the `Content-Type` header is set to `application/json`,
|
|
278
|
+
> strings are sent unmodified by default. To serialize a string as JSON, you
|
|
279
|
+
> must set a custom serializer:
|
|
261
280
|
|
|
262
281
|
```js
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
282
|
+
fastify.get('/json-string', async function (request, reply) {
|
|
283
|
+
reply
|
|
284
|
+
.type('application/json; charset=utf-8')
|
|
285
|
+
.serializer(JSON.stringify)
|
|
286
|
+
.send('Hello') // Returns "Hello" (JSON-encoded string)
|
|
287
|
+
})
|
|
288
|
+
```
|
|
289
|
+
```js
|
|
290
|
+
fastify.get('/json', options, function (request, reply) {
|
|
291
|
+
reply.send('plain string')
|
|
292
|
+
})
|
|
266
293
|
```
|
|
267
294
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
### .trailer(key, function)
|
|
272
|
-
<a id="trailer"></a>
|
|
273
|
-
|
|
274
|
-
Sets a response trailer. Trailer is usually used when you need a header that
|
|
275
|
-
requires heavy resources to be sent after the `data`, for example,
|
|
276
|
-
`Server-Timing` and `Etag`. It can ensure the client receives the response data
|
|
277
|
-
as soon as possible.
|
|
295
|
+
###### Buffers
|
|
296
|
+
<a id="send-buffers"></a>
|
|
278
297
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
> once you use a trailer. HTTP/2 does not use chunked transfer encoding and
|
|
282
|
-
> sends trailers using its native trailing headers support.
|
|
298
|
+
If you are sending a buffer and you have not set a `'Content-Type'` header,
|
|
299
|
+
*send* will set it to `'application/octet-stream'`.
|
|
283
300
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
> in the error, you can turn on `debug` level logging.
|
|
301
|
+
As noted above, Buffers are considered to be pre-serialized, so they will be
|
|
302
|
+
sent unmodified without response validation.
|
|
287
303
|
|
|
288
304
|
```js
|
|
289
|
-
|
|
290
|
-
return 'db;dur=53, app;dur=47.2'
|
|
291
|
-
})
|
|
305
|
+
const fs = require('node:fs')
|
|
292
306
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
// @param {function} done callback to set trailer value
|
|
298
|
-
reply.trailer('content-md5', function(reply, payload, done) {
|
|
299
|
-
const hash = createHash('md5')
|
|
300
|
-
hash.update(payload)
|
|
301
|
-
done(null, hash.digest('hex'))
|
|
307
|
+
fastify.get('/streams', function (request, reply) {
|
|
308
|
+
fs.readFile('some-file', (err, fileBuffer) => {
|
|
309
|
+
reply.send(err || fileBuffer)
|
|
310
|
+
})
|
|
302
311
|
})
|
|
312
|
+
```
|
|
303
313
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
314
|
+
When using async-await you will need to return or await the reply object:
|
|
315
|
+
```js
|
|
316
|
+
const fs = require('node:fs')
|
|
317
|
+
|
|
318
|
+
fastify.get('/streams', async function (request, reply) {
|
|
319
|
+
fs.readFile('some-file', (err, fileBuffer) => {
|
|
320
|
+
reply.send(err || fileBuffer)
|
|
321
|
+
})
|
|
322
|
+
return reply
|
|
309
323
|
})
|
|
310
324
|
```
|
|
311
325
|
|
|
312
|
-
|
|
313
|
-
<a id="
|
|
326
|
+
###### TypedArrays
|
|
327
|
+
<a id="send-typedarrays"></a>
|
|
314
328
|
|
|
315
|
-
|
|
329
|
+
`send` manages TypedArray like a Buffer, and sets the `'Content-Type'`
|
|
330
|
+
header to `'application/octet-stream'` if not already set.
|
|
316
331
|
|
|
317
|
-
|
|
318
|
-
|
|
332
|
+
As noted above, TypedArray/Buffers are considered to be pre-serialized, so they
|
|
333
|
+
will be sent unmodified without response validation.
|
|
319
334
|
|
|
320
|
-
Remove the value of a previously set trailer.
|
|
321
335
|
```js
|
|
322
|
-
|
|
323
|
-
|
|
336
|
+
const fs = require('node:fs')
|
|
337
|
+
|
|
338
|
+
fastify.get('/streams', function (request, reply) {
|
|
339
|
+
const typedArray = new Uint16Array(10)
|
|
340
|
+
reply.send(typedArray)
|
|
324
341
|
})
|
|
325
|
-
reply.removeTrailer('server-timing')
|
|
326
|
-
reply.hasTrailer('server-timing') // false
|
|
327
342
|
```
|
|
328
343
|
|
|
344
|
+
###### Streams
|
|
345
|
+
<a id="send-streams"></a>
|
|
329
346
|
|
|
330
|
-
|
|
331
|
-
|
|
347
|
+
If you are sending a stream and you have not set a `'Content-Type'` header,
|
|
348
|
+
*send* will set it to `'application/octet-stream'`.
|
|
332
349
|
|
|
333
|
-
|
|
334
|
-
|
|
350
|
+
As noted above, streams are considered to be pre-serialized, so they will be
|
|
351
|
+
sent unmodified without response validation.
|
|
335
352
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
> [`encodeurl`](https://www.npmjs.com/package/encodeurl). Invalid URLs will
|
|
341
|
-
> result in a 500 `TypeError` response.
|
|
353
|
+
When sending streams over HTTP/2, Fastify does not change the chunks emitted by
|
|
354
|
+
the stream. If a stream can emit very large chunks, split them in your
|
|
355
|
+
application code, for example by using `fs.createReadStream()` or a transform
|
|
356
|
+
stream that emits smaller chunks.
|
|
342
357
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
> nor `encodeurl` escapes `/`, so a caller-supplied target such as
|
|
346
|
-
> `//evil.com` or `/\evil.com` survives encoding and is resolved by the
|
|
347
|
-
> browser as a new host (a protocol-relative, authority-opening
|
|
348
|
-
> reference). When `dest` can be influenced by request input
|
|
349
|
-
> (`req.query`, `req.body`, `req.params`, cookies, or headers), validate
|
|
350
|
-
> that the resolved target is same-origin or on an explicit allowlist
|
|
351
|
-
> instead of relying on encoding:
|
|
352
|
-
>
|
|
353
|
-
> ```js
|
|
354
|
-
> const target = new URL(dest, 'https://your-site.example')
|
|
355
|
-
> if (target.origin !== 'https://your-site.example') {
|
|
356
|
-
> return reply.code(400).send()
|
|
357
|
-
> }
|
|
358
|
-
> ```
|
|
358
|
+
See special note about error handling for streams in
|
|
359
|
+
[`setErrorHandler`](./Server.md#seterrorhandler).
|
|
359
360
|
|
|
360
|
-
Example (no `reply.code()` call) sets status code to `302` and redirects to
|
|
361
|
-
`/home`
|
|
362
361
|
```js
|
|
363
|
-
|
|
364
|
-
```
|
|
362
|
+
const fs = require('node:fs')
|
|
365
363
|
|
|
366
|
-
|
|
367
|
-
|
|
364
|
+
fastify.get('/streams', function (request, reply) {
|
|
365
|
+
const stream = fs.createReadStream('some-file', 'utf8')
|
|
366
|
+
reply.header('Content-Type', 'application/octet-stream')
|
|
367
|
+
reply.send(stream)
|
|
368
|
+
})
|
|
369
|
+
```
|
|
370
|
+
When using async-await you will need to return or await the reply object:
|
|
368
371
|
```js
|
|
369
|
-
|
|
372
|
+
const fs = require('node:fs')
|
|
373
|
+
|
|
374
|
+
fastify.get('/streams', async function (request, reply) {
|
|
375
|
+
const stream = fs.createReadStream('some-file', 'utf8')
|
|
376
|
+
reply.header('Content-Type', 'application/octet-stream')
|
|
377
|
+
return reply.send(stream)
|
|
378
|
+
})
|
|
370
379
|
```
|
|
371
380
|
|
|
372
|
-
|
|
381
|
+
###### ReadableStream
|
|
382
|
+
<a id="send-readablestream"></a>
|
|
383
|
+
|
|
384
|
+
`ReadableStream` will be treated as a node stream mentioned above,
|
|
385
|
+
the content is considered to be pre-serialized, so they will be
|
|
386
|
+
sent unmodified without response validation.
|
|
387
|
+
|
|
373
388
|
```js
|
|
374
|
-
|
|
389
|
+
const fs = require('node:fs')
|
|
390
|
+
const { ReadableStream } = require('node:stream/web')
|
|
391
|
+
|
|
392
|
+
fastify.get('/streams', function (request, reply) {
|
|
393
|
+
const stream = fs.createReadStream('some-file')
|
|
394
|
+
reply.header('Content-Type', 'application/octet-stream')
|
|
395
|
+
reply.send(ReadableStream.from(stream))
|
|
396
|
+
})
|
|
375
397
|
```
|
|
376
398
|
|
|
377
|
-
|
|
399
|
+
###### Response
|
|
400
|
+
<a id="send-response"></a>
|
|
401
|
+
|
|
402
|
+
`Response` allows to manage the reply payload, status code and
|
|
403
|
+
headers in one place. The payload provided inside `Response` is
|
|
404
|
+
considered to be pre-serialized, so they will be sent unmodified
|
|
405
|
+
without response validation.
|
|
406
|
+
|
|
407
|
+
Please be aware when using `Response`, the status code and headers
|
|
408
|
+
will not directly reflect to `reply.statusCode` and `reply.getHeaders()`.
|
|
409
|
+
Such behavior is based on `Response` only allow `readonly` status
|
|
410
|
+
code and headers. The data is not allow to be bi-direction editing,
|
|
411
|
+
and may confuse when checking the `payload` in `onSend` hooks.
|
|
412
|
+
|
|
378
413
|
```js
|
|
379
|
-
|
|
414
|
+
const fs = require('node:fs')
|
|
415
|
+
const { ReadableStream } = require('node:stream/web')
|
|
416
|
+
|
|
417
|
+
fastify.get('/streams', function (request, reply) {
|
|
418
|
+
const stream = fs.createReadStream('some-file')
|
|
419
|
+
const readableStream = ReadableStream.from(stream)
|
|
420
|
+
const response = new Response(readableStream, {
|
|
421
|
+
status: 200,
|
|
422
|
+
headers: { 'content-type': 'application/octet-stream' }
|
|
423
|
+
})
|
|
424
|
+
reply.send(response)
|
|
425
|
+
})
|
|
380
426
|
```
|
|
381
427
|
|
|
382
|
-
### .callNotFound()
|
|
383
|
-
<a id="call-not-found"></a>
|
|
384
428
|
|
|
385
|
-
|
|
386
|
-
|
|
429
|
+
###### Errors
|
|
430
|
+
<a id="errors"></a>
|
|
431
|
+
|
|
432
|
+
If you pass to *send* an object that is an instance of *Error*, Fastify will
|
|
433
|
+
automatically create an error structured as the following:
|
|
387
434
|
|
|
388
435
|
```js
|
|
389
|
-
|
|
436
|
+
{
|
|
437
|
+
error: String // the HTTP error message
|
|
438
|
+
code: String // the Fastify error code
|
|
439
|
+
message: String // the user error message
|
|
440
|
+
statusCode: Number // the HTTP status code
|
|
441
|
+
}
|
|
390
442
|
```
|
|
391
443
|
|
|
392
|
-
|
|
393
|
-
|
|
444
|
+
You can add custom properties to the Error object, such as `headers`, that will
|
|
445
|
+
be used to enhance the HTTP response.
|
|
394
446
|
|
|
395
|
-
|
|
396
|
-
`
|
|
447
|
+
> ℹ️ Note:
|
|
448
|
+
> If you are passing an error to `send` and the statusCode is less than
|
|
449
|
+
> 400, Fastify will automatically set it at 500.
|
|
450
|
+
|
|
451
|
+
Tip: you can simplify errors by using the
|
|
452
|
+
[`http-errors`](https://www.npmjs.com/package/http-errors) module or
|
|
453
|
+
[`@fastify/sensible`](https://github.com/fastify/fastify-sensible) plugin to
|
|
454
|
+
generate errors:
|
|
397
455
|
|
|
398
456
|
```js
|
|
399
|
-
|
|
457
|
+
fastify.get('/', function (request, reply) {
|
|
458
|
+
reply.send(httpErrors.Gone())
|
|
459
|
+
})
|
|
400
460
|
```
|
|
401
|
-
If the `Content-Type` has a JSON subtype, and the charset parameter is not set,
|
|
402
|
-
`utf-8` will be used as the charset by default. For other content types, the
|
|
403
|
-
charset must be set explicitly.
|
|
404
461
|
|
|
405
|
-
|
|
406
|
-
<a id="getserializationfunction"></a>
|
|
462
|
+
To customize the JSON error output you can do it by:
|
|
407
463
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
that can be used to serialize diverse inputs. It returns `undefined` if no
|
|
411
|
-
serialization function was found using either of the provided inputs.
|
|
464
|
+
- setting a response JSON schema for the status code you need
|
|
465
|
+
- add the additional properties to the `Error` instance
|
|
412
466
|
|
|
413
|
-
|
|
414
|
-
|
|
467
|
+
Notice that if the returned status code is not in the response schema list, the
|
|
468
|
+
default behavior will be applied.
|
|
415
469
|
|
|
416
470
|
```js
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
471
|
+
fastify.get('/', {
|
|
472
|
+
schema: {
|
|
473
|
+
response: {
|
|
474
|
+
501: {
|
|
475
|
+
type: 'object',
|
|
476
|
+
properties: {
|
|
477
|
+
statusCode: { type: 'number' },
|
|
478
|
+
code: { type: 'string' },
|
|
479
|
+
error: { type: 'string' },
|
|
480
|
+
message: { type: 'string' },
|
|
481
|
+
time: { type: 'string' }
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}, function (request, reply) {
|
|
487
|
+
const error = new Error('This endpoint has not been implemented')
|
|
488
|
+
error.time = 'it will be implemented in two weeks'
|
|
489
|
+
reply.code(501).send(error)
|
|
490
|
+
})
|
|
491
|
+
```
|
|
427
492
|
|
|
428
|
-
|
|
493
|
+
If you want to customize error handling, check out
|
|
494
|
+
[`setErrorHandler`](./Server.md#seterrorhandler) API.
|
|
429
495
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
serialize({ foo: 'bar' }) // '{"foo":"bar"}'
|
|
496
|
+
> ℹ️ Note:
|
|
497
|
+
> You are responsible for logging when customizing the error handler.
|
|
433
498
|
|
|
434
|
-
|
|
499
|
+
API:
|
|
435
500
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
501
|
+
```js
|
|
502
|
+
fastify.setErrorHandler(function (error, request, reply) {
|
|
503
|
+
request.log.warn(error)
|
|
504
|
+
const statusCode = error.statusCode >= 400 ? error.statusCode : 500
|
|
505
|
+
reply
|
|
506
|
+
.code(statusCode)
|
|
507
|
+
.type('text/plain')
|
|
508
|
+
.send(statusCode >= 500 ? 'Internal server error' : error.message)
|
|
509
|
+
})
|
|
439
510
|
```
|
|
440
511
|
|
|
441
|
-
|
|
442
|
-
|
|
512
|
+
Beware that calling `reply.send(error)` in your custom error handler will send
|
|
513
|
+
the error to the default error handler.
|
|
514
|
+
Check out the [Reply Lifecycle](./Lifecycle.md#reply-lifecycle)
|
|
515
|
+
for more information.
|
|
443
516
|
|
|
444
|
-
|
|
445
|
-
|
|
517
|
+
The not found errors generated by the router will use the
|
|
518
|
+
[`setNotFoundHandler`](./Server.md#setnotfoundhandler)
|
|
446
519
|
|
|
447
|
-
|
|
448
|
-
return a function that can be used to serialize data.
|
|
449
|
-
The function returned (a.k.a. _serialization function_) returned is compiled
|
|
450
|
-
by using the provided `SerializerCompiler`. Also this is cached by using
|
|
451
|
-
a `WeakMap` for reducing compilation calls.
|
|
520
|
+
API:
|
|
452
521
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
522
|
+
```js
|
|
523
|
+
fastify.setNotFoundHandler(function (request, reply) {
|
|
524
|
+
reply
|
|
525
|
+
.code(404)
|
|
526
|
+
.type('text/plain')
|
|
527
|
+
.send('a custom not found')
|
|
528
|
+
})
|
|
529
|
+
```
|
|
456
530
|
|
|
457
|
-
|
|
458
|
-
|
|
531
|
+
###### Async-Await and Promises
|
|
532
|
+
<a id="async-await-promise"></a>
|
|
533
|
+
|
|
534
|
+
Fastify natively handles promises and supports async-await.
|
|
459
535
|
|
|
536
|
+
*Note that in the following examples we are not using reply.send.*
|
|
460
537
|
```js
|
|
461
|
-
const
|
|
462
|
-
|
|
463
|
-
type: 'object',
|
|
464
|
-
properties: {
|
|
465
|
-
foo: {
|
|
466
|
-
type: 'string'
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
})
|
|
470
|
-
serialize({ foo: 'bar' }) // '{"foo":"bar"}'
|
|
538
|
+
const { promisify } = require('node:util')
|
|
539
|
+
const delay = promisify(setTimeout)
|
|
471
540
|
|
|
472
|
-
|
|
541
|
+
fastify.get('/promises', options, function (request, reply) {
|
|
542
|
+
return delay(200).then(() => { return { hello: 'world' }})
|
|
543
|
+
})
|
|
473
544
|
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
type: 'string'
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
}, 200)
|
|
483
|
-
serialize({ foo: 'bar' }) // '{"foo":"bar"}'
|
|
545
|
+
fastify.get('/async-await', options, async function (request, reply) {
|
|
546
|
+
await delay(200)
|
|
547
|
+
return { hello: 'world' }
|
|
548
|
+
})
|
|
549
|
+
```
|
|
484
550
|
|
|
485
|
-
|
|
551
|
+
Rejected promises default to a `500` HTTP status code. Reject the promise, or
|
|
552
|
+
`throw` in an `async function`, with an object that has `statusCode` (or
|
|
553
|
+
`status`) and `message` properties to modify the reply.
|
|
486
554
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
}, '3xx', 'application/json')
|
|
500
|
-
serialize({ name: 'Jone', phone: 201090909090 }) // '{"name":"Jone", "phone":201090909090}'
|
|
555
|
+
```js
|
|
556
|
+
fastify.get('/teapot', async function (request, reply) {
|
|
557
|
+
const err = new Error()
|
|
558
|
+
err.statusCode = 418
|
|
559
|
+
err.message = 'short and stout'
|
|
560
|
+
throw err
|
|
561
|
+
})
|
|
562
|
+
|
|
563
|
+
fastify.get('/botnet', async function (request, reply) {
|
|
564
|
+
throw { statusCode: 418, message: 'short and stout' }
|
|
565
|
+
// will return to the client the same json
|
|
566
|
+
})
|
|
501
567
|
```
|
|
502
568
|
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
schemas provided is mutated or changed, the serialization functions will not
|
|
506
|
-
detect that the schema has been altered and for instance it will reuse the
|
|
507
|
-
previously compiled serialization function based on the reference of the schema
|
|
508
|
-
previously provided.
|
|
569
|
+
If you want to know more please review
|
|
570
|
+
[Routes#async-await](./Routes.md#async-await).
|
|
509
571
|
|
|
510
|
-
|
|
511
|
-
a
|
|
512
|
-
mechanism.
|
|
572
|
+
###### Type of the final payload
|
|
573
|
+
<a id="payload-type"></a>
|
|
513
574
|
|
|
514
|
-
|
|
575
|
+
The type of the sent payload (after serialization and going through any
|
|
576
|
+
[`onSend` hooks](./Hooks.md#onsend)) must be one of the following types,
|
|
577
|
+
otherwise, an error will be thrown:
|
|
578
|
+
|
|
579
|
+
- `string`
|
|
580
|
+
- `Buffer`
|
|
581
|
+
- `stream`
|
|
582
|
+
- `undefined`
|
|
583
|
+
- `null`
|
|
584
|
+
|
|
585
|
+
##### .code(statusCode)
|
|
586
|
+
<a id="code"></a>
|
|
587
|
+
|
|
588
|
+
If not set via `reply.code`, the resulting `statusCode` will be `200`.
|
|
589
|
+
|
|
590
|
+
`.status(statusCode)` is an alias of `.code(statusCode)`.
|
|
591
|
+
|
|
592
|
+
##### .header(key, value)
|
|
593
|
+
<a id="header"></a>
|
|
594
|
+
|
|
595
|
+
Sets a response header. If the value is omitted or undefined, it is coerced to
|
|
596
|
+
`''`.
|
|
597
|
+
|
|
598
|
+
> ℹ️ Note:
|
|
599
|
+
> The header's value must be properly encoded using
|
|
600
|
+
> [`encodeURI`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI)
|
|
601
|
+
> or similar modules such as
|
|
602
|
+
> [`encodeurl`](https://www.npmjs.com/package/encodeurl). Invalid characters
|
|
603
|
+
> will result in a 500 `TypeError` response.
|
|
604
|
+
|
|
605
|
+
For more information, see
|
|
606
|
+
[`http.ServerResponse#setHeader`](https://nodejs.org/dist/latest-v20.x/docs/api/http.html#http_response_setheader_name_value).
|
|
607
|
+
|
|
608
|
+
- ###### set-cookie
|
|
609
|
+
<a id="set-cookie"></a>
|
|
610
|
+
|
|
611
|
+
- When sending different values as a cookie with `set-cookie` as the key,
|
|
612
|
+
every value will be sent as a cookie instead of replacing the previous
|
|
613
|
+
value.
|
|
614
|
+
|
|
615
|
+
```js
|
|
616
|
+
reply.header('set-cookie', 'foo');
|
|
617
|
+
reply.header('set-cookie', 'bar');
|
|
618
|
+
```
|
|
619
|
+
- The browser will only consider the latest reference of a key for the
|
|
620
|
+
`set-cookie` header. This is done to avoid parsing the `set-cookie` header
|
|
621
|
+
when added to a reply and speeds up the serialization of the reply.
|
|
622
|
+
|
|
623
|
+
- To reset the `set-cookie` header, you need to make an explicit call to
|
|
624
|
+
`reply.removeHeader('set-cookie')`, read more about `.removeHeader(key)`
|
|
625
|
+
[here](#removeheaderkey).
|
|
626
|
+
|
|
627
|
+
##### .headers(object)
|
|
628
|
+
<a id="headers"></a>
|
|
629
|
+
|
|
630
|
+
Sets all the keys of the object as response headers.
|
|
631
|
+
[`.header`](#headerkey-value) will be called under the hood.
|
|
515
632
|
```js
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
type: 'string'
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
}
|
|
633
|
+
reply.headers({
|
|
634
|
+
'x-foo': 'foo',
|
|
635
|
+
'x-bar': 'bar'
|
|
636
|
+
})
|
|
524
637
|
```
|
|
525
638
|
|
|
526
|
-
|
|
639
|
+
##### .type(contentType)
|
|
640
|
+
<a id="type"></a>
|
|
641
|
+
|
|
642
|
+
Sets the content type for the response. This is a shortcut for
|
|
643
|
+
`reply.header('Content-Type', 'the/type')`.
|
|
644
|
+
|
|
527
645
|
```js
|
|
528
|
-
|
|
646
|
+
reply.type('text/html')
|
|
647
|
+
```
|
|
648
|
+
If the `Content-Type` has a JSON subtype, and the charset parameter is not set,
|
|
649
|
+
`utf-8` will be used as the charset by default. For other content types, the
|
|
650
|
+
charset must be set explicitly.
|
|
529
651
|
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
const newSerialize = reply.compileSerializationSchema(schema1)
|
|
652
|
+
##### .redirect(dest, [code])
|
|
653
|
+
<a id="redirect"></a>
|
|
533
654
|
|
|
534
|
-
|
|
655
|
+
Redirects a request to the specified URL, the status code is optional, default
|
|
656
|
+
to `302` (if status code is not already set by calling `code`).
|
|
657
|
+
|
|
658
|
+
> ℹ️ Note:
|
|
659
|
+
> The input URL must be properly encoded using
|
|
660
|
+
> [`encodeURI`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI)
|
|
661
|
+
> or similar modules such as
|
|
662
|
+
> [`encodeurl`](https://www.npmjs.com/package/encodeurl). Invalid URLs will
|
|
663
|
+
> result in a 500 `TypeError` response.
|
|
664
|
+
|
|
665
|
+
> ⚠️ Security:
|
|
666
|
+
> Encoding alone does **not** prevent open redirects. Neither `encodeURI`
|
|
667
|
+
> nor `encodeurl` escapes `/`, so a caller-supplied target such as
|
|
668
|
+
> `//evil.com` or `/\evil.com` survives encoding and is resolved by the
|
|
669
|
+
> browser as a new host (a protocol-relative, authority-opening
|
|
670
|
+
> reference). When `dest` can be influenced by request input
|
|
671
|
+
> (`req.query`, `req.body`, `req.params`, cookies, or headers), validate
|
|
672
|
+
> that the resolved target is same-origin or on an explicit allowlist
|
|
673
|
+
> instead of relying on encoding:
|
|
674
|
+
>
|
|
675
|
+
> ```js
|
|
676
|
+
> const target = new URL(dest, 'https://your-site.example')
|
|
677
|
+
> if (target.origin !== 'https://your-site.example') {
|
|
678
|
+
> return reply.code(400).send()
|
|
679
|
+
> }
|
|
680
|
+
> ```
|
|
681
|
+
|
|
682
|
+
Example (no `reply.code()` call) sets status code to `302` and redirects to
|
|
683
|
+
`/home`
|
|
684
|
+
```js
|
|
685
|
+
reply.redirect('/home')
|
|
535
686
|
```
|
|
536
687
|
|
|
537
|
-
|
|
688
|
+
Example (no `reply.code()` call) sets status code to `303` and redirects to
|
|
689
|
+
`/home`
|
|
538
690
|
```js
|
|
539
|
-
|
|
691
|
+
reply.redirect('/home', 303)
|
|
692
|
+
```
|
|
540
693
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
694
|
+
Example (`reply.code()` call) sets status code to `303` and redirects to `/home`
|
|
695
|
+
```js
|
|
696
|
+
reply.code(303).redirect('/home')
|
|
697
|
+
```
|
|
544
698
|
|
|
545
|
-
|
|
699
|
+
Example (`reply.code()` call) sets status code to `302` and redirects to `/home`
|
|
700
|
+
```js
|
|
701
|
+
reply.code(303).redirect('/home', 302)
|
|
702
|
+
```
|
|
546
703
|
|
|
547
|
-
|
|
704
|
+
##### .getHeader(key)
|
|
705
|
+
<a id="getHeader"></a>
|
|
706
|
+
|
|
707
|
+
Retrieves the value of a previously set header.
|
|
708
|
+
```js
|
|
709
|
+
reply.header('x-foo', 'foo') // setHeader: key, value
|
|
710
|
+
reply.getHeader('x-foo') // 'foo'
|
|
548
711
|
```
|
|
549
712
|
|
|
550
|
-
|
|
551
|
-
<a id="
|
|
713
|
+
##### .getHeaders()
|
|
714
|
+
<a id="getHeaders"></a>
|
|
552
715
|
|
|
553
|
-
|
|
554
|
-
|
|
716
|
+
Gets a shallow copy of all current response headers, including those set via the
|
|
717
|
+
raw `http.ServerResponse`. Note that headers set via Fastify take precedence
|
|
718
|
+
over those set via `http.ServerResponse`.
|
|
555
719
|
|
|
556
|
-
|
|
557
|
-
|
|
720
|
+
```js
|
|
721
|
+
reply.header('x-foo', 'foo')
|
|
722
|
+
reply.header('x-bar', 'bar')
|
|
723
|
+
reply.raw.setHeader('x-foo', 'foo2')
|
|
724
|
+
reply.getHeaders() // { 'x-foo': 'foo', 'x-bar': 'bar' }
|
|
725
|
+
```
|
|
726
|
+
|
|
727
|
+
##### .hasHeader(key)
|
|
728
|
+
<a id="hasHeader"></a>
|
|
729
|
+
|
|
730
|
+
Returns a boolean indicating if the specified header has been set.
|
|
731
|
+
|
|
732
|
+
##### .removeHeader(key)
|
|
733
|
+
<a id="removeHeader"></a>
|
|
558
734
|
|
|
735
|
+
Remove the value of a previously set header.
|
|
559
736
|
```js
|
|
560
|
-
reply
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
foo: {
|
|
565
|
-
type: 'string'
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
}) // '{"foo":"bar"}'
|
|
737
|
+
reply.header('x-foo', 'foo')
|
|
738
|
+
reply.removeHeader('x-foo')
|
|
739
|
+
reply.getHeader('x-foo') // undefined
|
|
740
|
+
```
|
|
569
741
|
|
|
570
|
-
|
|
742
|
+
##### .callNotFound()
|
|
743
|
+
<a id="call-not-found"></a>
|
|
571
744
|
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
type: 'object',
|
|
575
|
-
properties: {
|
|
576
|
-
foo: {
|
|
577
|
-
type: 'string'
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
}, 200) // '{"foo":"bar"}'
|
|
745
|
+
Invokes the custom not found handler. Note that it will only call `preHandler`
|
|
746
|
+
hook specified in [`setNotFoundHandler`](./Server.md#set-not-found-handler).
|
|
581
747
|
|
|
582
|
-
|
|
748
|
+
```js
|
|
749
|
+
reply.callNotFound()
|
|
750
|
+
```
|
|
583
751
|
|
|
584
|
-
|
|
585
|
-
|
|
752
|
+
##### .hijack()
|
|
753
|
+
<a name="hijack"></a>
|
|
586
754
|
|
|
587
|
-
|
|
755
|
+
Sometimes you might need to halt the execution of the normal request lifecycle
|
|
756
|
+
and handle sending the response manually.
|
|
588
757
|
|
|
589
|
-
reply
|
|
590
|
-
|
|
758
|
+
To achieve this, Fastify provides the `reply.hijack()` method that can be called
|
|
759
|
+
during the request lifecycle (At any point before `reply.send()` is called), and
|
|
760
|
+
allows you to prevent Fastify from sending the response, and from running the
|
|
761
|
+
remaining hooks (and user handler if the reply was hijacked before).
|
|
762
|
+
|
|
763
|
+
```js
|
|
764
|
+
app.get('/', (req, reply) => {
|
|
765
|
+
reply.hijack()
|
|
766
|
+
reply.raw.end('hello world')
|
|
767
|
+
|
|
768
|
+
return Promise.resolve('this will be skipped')
|
|
769
|
+
})
|
|
591
770
|
```
|
|
592
771
|
|
|
593
|
-
|
|
594
|
-
|
|
772
|
+
If `reply.raw` is used to send a response back to the user, the `onResponse`
|
|
773
|
+
hooks will still be executed.
|
|
595
774
|
|
|
596
|
-
|
|
775
|
+
##### .serializer(func)
|
|
597
776
|
<a id="serializer"></a>
|
|
598
777
|
|
|
599
778
|
By default, `.send()` will JSON-serialize any value that is not one of `Buffer`,
|
|
@@ -621,415 +800,325 @@ reply
|
|
|
621
800
|
See [`.send()`](#send) for more information on sending different types of
|
|
622
801
|
values.
|
|
623
802
|
|
|
624
|
-
|
|
625
|
-
<a id="
|
|
803
|
+
##### .serialize(payload)
|
|
804
|
+
<a id="serialize"></a>
|
|
626
805
|
|
|
627
|
-
|
|
628
|
-
[`
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
logic of handling the HTTP response. e.g.:
|
|
806
|
+
Serializes the specified payload using the custom serializer set via
|
|
807
|
+
[`.serializer()`](#serializerfunc), if any. Otherwise, it uses the default
|
|
808
|
+
serializer of the route, which takes into account the response schema for the
|
|
809
|
+
current status code. It returns the serialized payload.
|
|
632
810
|
|
|
633
811
|
```js
|
|
634
|
-
|
|
635
|
-
reply.
|
|
636
|
-
|
|
637
|
-
// in this case we are using only the nodejs http server response object
|
|
638
|
-
reply.raw.writeHead(200, { 'Content-Type': 'text/plain' })
|
|
639
|
-
reply.raw.write('ok')
|
|
640
|
-
reply.raw.end()
|
|
812
|
+
fastify.get('/', function (request, reply) {
|
|
813
|
+
const payload = reply.serialize({ hello: 'world' })
|
|
814
|
+
reply.type('application/json').send(payload)
|
|
641
815
|
})
|
|
642
816
|
```
|
|
643
|
-
Another example of the misuse of `Reply.raw` is explained in
|
|
644
|
-
[Reply](#getheaders).
|
|
645
|
-
|
|
646
|
-
### .sent
|
|
647
|
-
<a id="sent"></a>
|
|
648
|
-
|
|
649
|
-
As the name suggests, `.sent` is a property to indicate if a response has been
|
|
650
|
-
sent via `reply.send()`. It will also be `true` in case `reply.hijack()` was
|
|
651
|
-
used.
|
|
652
817
|
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
invocation of `reply.send()` once the handler promise resolve should be skipped.
|
|
656
|
-
By calling `reply.hijack()`, an application claims full responsibility for the
|
|
657
|
-
low-level request and response. Moreover, hooks will not be invoked.
|
|
818
|
+
##### .trailer(key, function)
|
|
819
|
+
<a id="trailer"></a>
|
|
658
820
|
|
|
659
|
-
|
|
660
|
-
|
|
821
|
+
Sets a response trailer. Trailer is usually used when you need a header that
|
|
822
|
+
requires heavy resources to be sent after the `data`, for example,
|
|
823
|
+
`Server-Timing` and `Etag`. It can ensure the client receives the response data
|
|
824
|
+
as soon as possible.
|
|
661
825
|
|
|
662
|
-
|
|
663
|
-
|
|
826
|
+
> ℹ️ Note:
|
|
827
|
+
> For HTTP/1 responses, the header `Transfer-Encoding: chunked` will be added
|
|
828
|
+
> once you use a trailer. HTTP/2 does not use chunked transfer encoding and
|
|
829
|
+
> sends trailers using its native trailing headers support.
|
|
664
830
|
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
remaining hooks (and user handler if the reply was hijacked before).
|
|
831
|
+
> ℹ️ Note:
|
|
832
|
+
> Any error passed to `done` callback will be ignored. If you are interested
|
|
833
|
+
> in the error, you can turn on `debug` level logging.
|
|
669
834
|
|
|
670
835
|
```js
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
reply.raw.end('hello world')
|
|
674
|
-
|
|
675
|
-
return Promise.resolve('this will be skipped')
|
|
836
|
+
reply.trailer('server-timing', async function () {
|
|
837
|
+
return 'db;dur=53, app;dur=47.2'
|
|
676
838
|
})
|
|
677
|
-
```
|
|
678
|
-
|
|
679
|
-
If `reply.raw` is used to send a response back to the user, the `onResponse`
|
|
680
|
-
hooks will still be executed.
|
|
681
839
|
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
840
|
+
const { createHash } = require('node:crypto')
|
|
841
|
+
// trailer function also receive two argument
|
|
842
|
+
// @param {object} reply fastify reply
|
|
843
|
+
// @param {string|Buffer|null} payload payload that already sent, note that it will be null when stream is sent
|
|
844
|
+
// @param {function} done callback to set trailer value
|
|
845
|
+
reply.trailer('content-md5', function(reply, payload, done) {
|
|
846
|
+
const hash = createHash('md5')
|
|
847
|
+
hash.update(payload)
|
|
848
|
+
done(null, hash.digest('hex'))
|
|
849
|
+
})
|
|
690
850
|
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
fastify.get('/json', options, function (request, reply) {
|
|
697
|
-
reply.send({ hello: 'world' })
|
|
851
|
+
// when you prefer async-await
|
|
852
|
+
reply.trailer('content-md5', async function(reply, payload) {
|
|
853
|
+
const hash = createHash('md5')
|
|
854
|
+
hash.update(payload)
|
|
855
|
+
return hash.digest('hex')
|
|
698
856
|
})
|
|
699
857
|
```
|
|
700
858
|
|
|
701
|
-
|
|
702
|
-
<a id="
|
|
859
|
+
##### .hasTrailer(key)
|
|
860
|
+
<a id="hasTrailer"></a>
|
|
703
861
|
|
|
704
|
-
|
|
705
|
-
`text/plain; charset=utf-8`. If you set the `Content-Type` header and pass a
|
|
706
|
-
string to `send`, it will be serialized with the custom serializer if one is
|
|
707
|
-
set, otherwise, it will be sent unmodified.
|
|
862
|
+
Returns a boolean indicating if the specified trailer has been set.
|
|
708
863
|
|
|
709
|
-
|
|
710
|
-
>
|
|
711
|
-
> strings are sent unmodified by default. To serialize a string as JSON, you
|
|
712
|
-
> must set a custom serializer:
|
|
864
|
+
##### .removeTrailer(key)
|
|
865
|
+
<a id="removeTrailer"></a>
|
|
713
866
|
|
|
867
|
+
Remove the value of a previously set trailer.
|
|
714
868
|
```js
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
.type('application/json; charset=utf-8')
|
|
718
|
-
.serializer(JSON.stringify)
|
|
719
|
-
.send('Hello') // Returns "Hello" (JSON-encoded string)
|
|
720
|
-
})
|
|
721
|
-
```
|
|
722
|
-
```js
|
|
723
|
-
fastify.get('/json', options, function (request, reply) {
|
|
724
|
-
reply.send('plain string')
|
|
869
|
+
reply.trailer('server-timing', async function () {
|
|
870
|
+
return 'db;dur=53, app;dur=47.2'
|
|
725
871
|
})
|
|
872
|
+
reply.removeTrailer('server-timing')
|
|
873
|
+
reply.hasTrailer('server-timing') // false
|
|
726
874
|
```
|
|
727
875
|
|
|
728
|
-
|
|
729
|
-
<a id="
|
|
730
|
-
|
|
731
|
-
If you are sending a stream and you have not set a `'Content-Type'` header,
|
|
732
|
-
*send* will set it to `'application/octet-stream'`.
|
|
733
|
-
|
|
734
|
-
As noted above, streams are considered to be pre-serialized, so they will be
|
|
735
|
-
sent unmodified without response validation.
|
|
876
|
+
##### .writeEarlyHints(hints, callback)
|
|
877
|
+
<a id="writeEarlyHints"></a>
|
|
736
878
|
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
879
|
+
Sends early hints to the client. Early hints allow the client to
|
|
880
|
+
start processing resources before the final response is sent.
|
|
881
|
+
This can improve performance by allowing the client to preload
|
|
882
|
+
or preconnect to resources while the server is still generating the response.
|
|
741
883
|
|
|
742
|
-
|
|
743
|
-
[`setErrorHandler`](./Server.md#seterrorhandler).
|
|
884
|
+
The hints parameter is an object containing the early hint key-value pairs.
|
|
744
885
|
|
|
745
|
-
|
|
746
|
-
const fs = require('node:fs')
|
|
886
|
+
Example:
|
|
747
887
|
|
|
748
|
-
fastify.get('/streams', function (request, reply) {
|
|
749
|
-
const stream = fs.createReadStream('some-file', 'utf8')
|
|
750
|
-
reply.header('Content-Type', 'application/octet-stream')
|
|
751
|
-
reply.send(stream)
|
|
752
|
-
})
|
|
753
|
-
```
|
|
754
|
-
When using async-await you will need to return or await the reply object:
|
|
755
888
|
```js
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
const stream = fs.createReadStream('some-file', 'utf8')
|
|
760
|
-
reply.header('Content-Type', 'application/octet-stream')
|
|
761
|
-
return reply.send(stream)
|
|
762
|
-
})
|
|
889
|
+
reply.writeEarlyHints({
|
|
890
|
+
Link: '</styles.css>; rel=preload; as=style'
|
|
891
|
+
});
|
|
763
892
|
```
|
|
764
893
|
|
|
765
|
-
|
|
766
|
-
|
|
894
|
+
The optional callback parameter is a function that will be called
|
|
895
|
+
once the hint is sent or if an error occurs.
|
|
767
896
|
|
|
768
|
-
|
|
769
|
-
|
|
897
|
+
##### .then(fulfilled, rejected)
|
|
898
|
+
<a id="then"></a>
|
|
770
899
|
|
|
771
|
-
As
|
|
772
|
-
sent
|
|
900
|
+
As the name suggests, a `Reply` object can be awaited upon, i.e. `await reply`
|
|
901
|
+
will wait until the reply is sent. The `await` syntax calls the `reply.then()`.
|
|
773
902
|
|
|
774
|
-
|
|
775
|
-
const fs = require('node:fs')
|
|
903
|
+
`reply.then(fulfilled, rejected)` accepts two parameters:
|
|
776
904
|
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
})
|
|
781
|
-
})
|
|
782
|
-
```
|
|
905
|
+
- `fulfilled` will be called when a response has been fully sent,
|
|
906
|
+
- `rejected` will be called if the underlying stream had an error, e.g. the
|
|
907
|
+
socket has been destroyed.
|
|
783
908
|
|
|
784
|
-
|
|
785
|
-
```js
|
|
786
|
-
const fs = require('node:fs')
|
|
909
|
+
For more details, see:
|
|
787
910
|
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
return reply
|
|
793
|
-
})
|
|
794
|
-
```
|
|
911
|
+
- https://github.com/fastify/fastify/issues/1864 for the discussion about this
|
|
912
|
+
feature
|
|
913
|
+
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then
|
|
914
|
+
for the signature
|
|
795
915
|
|
|
796
|
-
|
|
797
|
-
<a id="send-typedarrays"></a>
|
|
916
|
+
##### .getDecorator(name)
|
|
798
917
|
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
918
|
+
Returns the value of a reply decorator declared with
|
|
919
|
+
[`decorateReply`](./Decorators.md#decoratereplyname-value-dependencies). If the
|
|
920
|
+
decorator is a function, it is returned bound to the reply. It throws an
|
|
921
|
+
`FST_ERR_DEC_UNDECLARED` error if the decorator has not been declared. See
|
|
922
|
+
[`getDecorator`](./Decorators.md#getdecoratorname) for more details.
|
|
804
923
|
|
|
805
924
|
```js
|
|
806
|
-
|
|
925
|
+
fastify.decorateReply('helper', function () {
|
|
926
|
+
return this.statusCode
|
|
927
|
+
})
|
|
807
928
|
|
|
808
|
-
fastify.get('/
|
|
809
|
-
const
|
|
810
|
-
reply.send(
|
|
929
|
+
fastify.get('/', function (request, reply) {
|
|
930
|
+
const helper = reply.getDecorator('helper')
|
|
931
|
+
reply.code(201).send({ statusCode: helper() }) // { statusCode: 201 }
|
|
811
932
|
})
|
|
812
933
|
```
|
|
813
934
|
|
|
814
|
-
|
|
815
|
-
<a id="
|
|
935
|
+
##### .getSerializationFunction(schema | httpStatus, [contentType])
|
|
936
|
+
<a id="getserializationfunction"></a>
|
|
816
937
|
|
|
817
|
-
|
|
818
|
-
the
|
|
819
|
-
|
|
938
|
+
By calling this function using a provided `schema` or `httpStatus`,
|
|
939
|
+
and the optional `contentType`, it will return a `serialization` function
|
|
940
|
+
that can be used to serialize diverse inputs. It returns `undefined` if no
|
|
941
|
+
serialization function was found using either of the provided inputs.
|
|
942
|
+
|
|
943
|
+
This heavily depends of the `schema#responses` attached to the route, or
|
|
944
|
+
the serialization functions compiled by using `compileSerializationSchema`.
|
|
820
945
|
|
|
821
946
|
```js
|
|
822
|
-
const
|
|
823
|
-
|
|
947
|
+
const serialize = reply
|
|
948
|
+
.getSerializationFunction({
|
|
949
|
+
type: 'object',
|
|
950
|
+
properties: {
|
|
951
|
+
foo: {
|
|
952
|
+
type: 'string'
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
})
|
|
956
|
+
serialize({ foo: 'bar' }) // '{"foo":"bar"}'
|
|
824
957
|
|
|
825
|
-
|
|
826
|
-
const stream = fs.createReadStream('some-file')
|
|
827
|
-
reply.header('Content-Type', 'application/octet-stream')
|
|
828
|
-
reply.send(ReadableStream.from(stream))
|
|
829
|
-
})
|
|
830
|
-
```
|
|
958
|
+
// or
|
|
831
959
|
|
|
832
|
-
|
|
833
|
-
|
|
960
|
+
const serialize = reply
|
|
961
|
+
.getSerializationFunction(200)
|
|
962
|
+
serialize({ foo: 'bar' }) // '{"foo":"bar"}'
|
|
834
963
|
|
|
835
|
-
|
|
836
|
-
headers in one place. The payload provided inside `Response` is
|
|
837
|
-
considered to be pre-serialized, so they will be sent unmodified
|
|
838
|
-
without response validation.
|
|
964
|
+
// or
|
|
839
965
|
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
and may confuse when checking the `payload` in `onSend` hooks.
|
|
966
|
+
const serialize = reply
|
|
967
|
+
.getSerializationFunction(200, 'application/json')
|
|
968
|
+
serialize({ foo: 'bar' }) // '{"foo":"bar"}'
|
|
969
|
+
```
|
|
845
970
|
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
const { ReadableStream } = require('node:stream/web')
|
|
971
|
+
See [.compileSerializationSchema(schema, [httpStatus], [contentType])](#compileserializationschema)
|
|
972
|
+
for more information on how to compile serialization schemas.
|
|
849
973
|
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
const readableStream = ReadableStream.from(stream)
|
|
853
|
-
const response = new Response(readableStream, {
|
|
854
|
-
status: 200,
|
|
855
|
-
headers: { 'content-type': 'application/octet-stream' }
|
|
856
|
-
})
|
|
857
|
-
reply.send(response)
|
|
858
|
-
})
|
|
859
|
-
```
|
|
974
|
+
##### .compileSerializationSchema(schema, [httpStatus], [contentType])
|
|
975
|
+
<a id="compileserializationschema"></a>
|
|
860
976
|
|
|
977
|
+
This function will compile a serialization schema and
|
|
978
|
+
return a function that can be used to serialize data.
|
|
979
|
+
The function returned (a.k.a. _serialization function_) returned is compiled
|
|
980
|
+
by using the provided `SerializerCompiler`. Also this is cached by using
|
|
981
|
+
a `WeakMap` for reducing compilation calls.
|
|
861
982
|
|
|
862
|
-
|
|
863
|
-
|
|
983
|
+
The optional parameters `httpStatus` and `contentType`, if provided,
|
|
984
|
+
are forwarded directly to the `SerializerCompiler`, so it can be used
|
|
985
|
+
to compile the serialization function if a custom `SerializerCompiler` is used.
|
|
864
986
|
|
|
865
|
-
|
|
866
|
-
|
|
987
|
+
This heavily depends of the `schema#responses` attached to the route, or
|
|
988
|
+
the serialization functions compiled by using `compileSerializationSchema`.
|
|
867
989
|
|
|
868
990
|
```js
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
991
|
+
const serialize = reply
|
|
992
|
+
.compileSerializationSchema({
|
|
993
|
+
type: 'object',
|
|
994
|
+
properties: {
|
|
995
|
+
foo: {
|
|
996
|
+
type: 'string'
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
})
|
|
1000
|
+
serialize({ foo: 'bar' }) // '{"foo":"bar"}'
|
|
876
1001
|
|
|
877
|
-
|
|
878
|
-
be used to enhance the HTTP response.
|
|
1002
|
+
// or
|
|
879
1003
|
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
1004
|
+
const serialize = reply
|
|
1005
|
+
.compileSerializationSchema({
|
|
1006
|
+
type: 'object',
|
|
1007
|
+
properties: {
|
|
1008
|
+
foo: {
|
|
1009
|
+
type: 'string'
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
}, 200)
|
|
1013
|
+
serialize({ foo: 'bar' }) // '{"foo":"bar"}'
|
|
883
1014
|
|
|
884
|
-
|
|
885
|
-
[`http-errors`](https://www.npmjs.com/package/http-errors) module or
|
|
886
|
-
[`@fastify/sensible`](https://github.com/fastify/fastify-sensible) plugin to
|
|
887
|
-
generate errors:
|
|
1015
|
+
// or
|
|
888
1016
|
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
1017
|
+
const serialize = reply
|
|
1018
|
+
.compileSerializationSchema({
|
|
1019
|
+
'3xx': {
|
|
1020
|
+
content: {
|
|
1021
|
+
'application/json': {
|
|
1022
|
+
schema: {
|
|
1023
|
+
name: { type: 'string' },
|
|
1024
|
+
phone: { type: 'number' }
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
}, '3xx', 'application/json')
|
|
1030
|
+
serialize({ name: 'Jone', phone: 201090909090 }) // '{"name":"Jone", "phone":201090909090}'
|
|
893
1031
|
```
|
|
894
1032
|
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
1033
|
+
Note that you should be careful when using this function, as it will cache
|
|
1034
|
+
the compiled serialization functions based on the schema provided. If the
|
|
1035
|
+
schemas provided is mutated or changed, the serialization functions will not
|
|
1036
|
+
detect that the schema has been altered and for instance it will reuse the
|
|
1037
|
+
previously compiled serialization function based on the reference of the schema
|
|
1038
|
+
previously provided.
|
|
899
1039
|
|
|
900
|
-
|
|
901
|
-
|
|
1040
|
+
If there's a need to change the properties of a schema, always opt to create
|
|
1041
|
+
a totally new object, otherwise the implementation won't benefit from the cache
|
|
1042
|
+
mechanism.
|
|
902
1043
|
|
|
1044
|
+
:Using the following schema as example:
|
|
903
1045
|
```js
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
properties: {
|
|
910
|
-
statusCode: { type: 'number' },
|
|
911
|
-
code: { type: 'string' },
|
|
912
|
-
error: { type: 'string' },
|
|
913
|
-
message: { type: 'string' },
|
|
914
|
-
time: { type: 'string' }
|
|
915
|
-
}
|
|
916
|
-
}
|
|
1046
|
+
const schema1 = {
|
|
1047
|
+
type: 'object',
|
|
1048
|
+
properties: {
|
|
1049
|
+
foo: {
|
|
1050
|
+
type: 'string'
|
|
917
1051
|
}
|
|
918
1052
|
}
|
|
919
|
-
}
|
|
920
|
-
const error = new Error('This endpoint has not been implemented')
|
|
921
|
-
error.time = 'it will be implemented in two weeks'
|
|
922
|
-
reply.code(501).send(error)
|
|
923
|
-
})
|
|
1053
|
+
}
|
|
924
1054
|
```
|
|
925
1055
|
|
|
926
|
-
|
|
927
|
-
[`setErrorHandler`](./Server.md#seterrorhandler) API.
|
|
928
|
-
|
|
929
|
-
> ℹ️ Note:
|
|
930
|
-
> You are responsible for logging when customizing the error handler.
|
|
931
|
-
|
|
932
|
-
API:
|
|
933
|
-
|
|
1056
|
+
*Not*
|
|
934
1057
|
```js
|
|
935
|
-
|
|
936
|
-
request.log.warn(error)
|
|
937
|
-
const statusCode = error.statusCode >= 400 ? error.statusCode : 500
|
|
938
|
-
reply
|
|
939
|
-
.code(statusCode)
|
|
940
|
-
.type('text/plain')
|
|
941
|
-
.send(statusCode >= 500 ? 'Internal server error' : error.message)
|
|
942
|
-
})
|
|
943
|
-
```
|
|
944
|
-
|
|
945
|
-
Beware that calling `reply.send(error)` in your custom error handler will send
|
|
946
|
-
the error to the default error handler.
|
|
947
|
-
Check out the [Reply Lifecycle](./Lifecycle.md#reply-lifecycle)
|
|
948
|
-
for more information.
|
|
949
|
-
|
|
950
|
-
The not found errors generated by the router will use the
|
|
951
|
-
[`setNotFoundHandler`](./Server.md#setnotfoundhandler)
|
|
1058
|
+
const serialize = reply.compileSerializationSchema(schema1)
|
|
952
1059
|
|
|
953
|
-
|
|
1060
|
+
// Later on...
|
|
1061
|
+
schema1.properties.foo.type = 'integer'
|
|
1062
|
+
const newSerialize = reply.compileSerializationSchema(schema1)
|
|
954
1063
|
|
|
955
|
-
|
|
956
|
-
fastify.setNotFoundHandler(function (request, reply) {
|
|
957
|
-
reply
|
|
958
|
-
.code(404)
|
|
959
|
-
.type('text/plain')
|
|
960
|
-
.send('a custom not found')
|
|
961
|
-
})
|
|
1064
|
+
console.log(newSerialize === serialize) // true
|
|
962
1065
|
```
|
|
963
1066
|
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
The type of the sent payload (after serialization and going through any
|
|
968
|
-
[`onSend` hooks](./Hooks.md#onsend)) must be one of the following types,
|
|
969
|
-
otherwise, an error will be thrown:
|
|
970
|
-
|
|
971
|
-
- `string`
|
|
972
|
-
- `Buffer`
|
|
973
|
-
- `stream`
|
|
974
|
-
- `undefined`
|
|
975
|
-
- `null`
|
|
1067
|
+
*Instead*
|
|
1068
|
+
```js
|
|
1069
|
+
const serialize = reply.compileSerializationSchema(schema1)
|
|
976
1070
|
|
|
977
|
-
|
|
978
|
-
|
|
1071
|
+
// Later on...
|
|
1072
|
+
const newSchema = Object.assign({}, schema1)
|
|
1073
|
+
newSchema.properties.foo.type = 'integer'
|
|
979
1074
|
|
|
980
|
-
|
|
1075
|
+
const newSerialize = reply.compileSerializationSchema(newSchema)
|
|
981
1076
|
|
|
982
|
-
|
|
983
|
-
```
|
|
984
|
-
const { promisify } = require('node:util')
|
|
985
|
-
const delay = promisify(setTimeout)
|
|
1077
|
+
console.log(newSerialize === serialize) // false
|
|
1078
|
+
```
|
|
986
1079
|
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
})
|
|
1080
|
+
##### .serializeInput(data, [schema | httpStatus], [httpStatus], [contentType])
|
|
1081
|
+
<a id="serializeinput"></a>
|
|
990
1082
|
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
return { hello: 'world' }
|
|
994
|
-
})
|
|
995
|
-
```
|
|
1083
|
+
This function will serialize the input data based on the provided schema
|
|
1084
|
+
or HTTP status code. If both are provided the `httpStatus` will take precedence.
|
|
996
1085
|
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
`status`) and `message` properties to modify the reply.
|
|
1086
|
+
If there is not a serialization function for a given `schema` a new serialization
|
|
1087
|
+
function will be compiled, forwarding the `httpStatus` and `contentType` if provided.
|
|
1000
1088
|
|
|
1001
1089
|
```js
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
// will return to the client the same json
|
|
1012
|
-
})
|
|
1013
|
-
```
|
|
1090
|
+
reply
|
|
1091
|
+
.serializeInput({ foo: 'bar'}, {
|
|
1092
|
+
type: 'object',
|
|
1093
|
+
properties: {
|
|
1094
|
+
foo: {
|
|
1095
|
+
type: 'string'
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
}) // '{"foo":"bar"}'
|
|
1014
1099
|
|
|
1015
|
-
|
|
1016
|
-
[Routes#async-await](./Routes.md#async-await).
|
|
1100
|
+
// or
|
|
1017
1101
|
|
|
1018
|
-
|
|
1019
|
-
|
|
1102
|
+
reply
|
|
1103
|
+
.serializeInput({ foo: 'bar'}, {
|
|
1104
|
+
type: 'object',
|
|
1105
|
+
properties: {
|
|
1106
|
+
foo: {
|
|
1107
|
+
type: 'string'
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
}, 200) // '{"foo":"bar"}'
|
|
1020
1111
|
|
|
1021
|
-
|
|
1022
|
-
will wait until the reply is sent. The `await` syntax calls the `reply.then()`.
|
|
1112
|
+
// or
|
|
1023
1113
|
|
|
1024
|
-
|
|
1114
|
+
reply
|
|
1115
|
+
.serializeInput({ foo: 'bar'}, 200) // '{"foo":"bar"}'
|
|
1025
1116
|
|
|
1026
|
-
|
|
1027
|
-
- `rejected` will be called if the underlying stream had an error, e.g. the
|
|
1028
|
-
socket has been destroyed.
|
|
1117
|
+
// or
|
|
1029
1118
|
|
|
1030
|
-
|
|
1119
|
+
reply
|
|
1120
|
+
.serializeInput({ name: 'Jone', age: 18 }, '200', 'application/vnd.v1+json') // '{"name": "Jone", "age": 18}'
|
|
1121
|
+
```
|
|
1031
1122
|
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then
|
|
1035
|
-
for the signature
|
|
1123
|
+
See [.compileSerializationSchema(schema, [httpStatus], [contentType])](#compileserializationschema)
|
|
1124
|
+
for more information on how to compile serialization schemas.
|