fastify 6.0.0-alpha.4 → 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/SECURITY.md +6 -0
- package/build/build-validation.js +2 -0
- package/docs/Guides/Ecosystem.md +12 -53
- package/docs/Guides/Migration-Guide-V5.md +2 -2
- package/docs/Guides/Serverless.md +33 -10
- package/docs/Reference/Errors.md +13 -2
- package/docs/Reference/Hooks.md +13 -0
- package/docs/Reference/Reply.md +787 -681
- package/docs/Reference/Request.md +308 -104
- package/docs/Reference/Routes.md +6 -2
- package/docs/Reference/Server.md +41 -4
- package/docs/Reference/Validation-and-Serialization.md +48 -1
- package/docs/Reference/Warnings.md +2 -0
- package/fastify.d.ts +1 -0
- package/fastify.js +35 -1
- package/lib/config-validator.js +102 -73
- package/lib/content-type-parser.js +35 -14
- package/lib/content-type.js +4 -4
- 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 -14
- package/lib/handle-request.js +7 -20
- package/lib/reply.js +18 -13
- package/lib/request.js +12 -7
- package/lib/route.js +40 -7
- package/lib/schemas.js +44 -32
- package/lib/validation.js +67 -10
- package/lib/warnings.js +10 -1
- package/package.json +8 -3
- package/test/child-logger-factory.test.js +25 -0
- package/test/close-disposable.test.js +154 -0
- package/test/constrained-routes.test.js +4 -2
- package/test/content-parser.test.js +99 -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 +19 -20
- package/test/internals/initial-config.test.js +2 -0
- package/test/internals/reply-serialize.test.js +20 -0
- package/test/internals/reply.test.js +30 -1
- package/test/internals/request.test.js +50 -0
- package/test/internals/server.test.js +6 -4
- package/test/reply-error.test.js +82 -0
- package/test/reply-media-type.test.js +57 -0
- package/test/reply-trailers.test.js +159 -1
- package/test/rfc-10008.test.js +6 -9
- package/test/router-compile.test.js +241 -0
- package/test/schema-feature.test.js +1 -1
- package/test/schema-serialization.test.js +120 -7
- package/test/schema-validation.test.js +251 -1
- package/test/types/errors.tst.ts +0 -1
- package/test/types/fastify.tst.ts +9 -0
- package/test/types/instance.tst.ts +1 -1
- package/test/types/route.tst.ts +37 -0
- package/test/types/using.tst.ts +20 -0
- package/test/validation-error-handling.test.js +21 -1
- package/types/errors.d.ts +0 -1
- package/types/instance.d.ts +9 -5
- package/types/route.d.ts +4 -2
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,486 +208,548 @@ 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
|
-
```js
|
|
346
|
-
reply.redirect('/home')
|
|
347
|
-
```
|
|
358
|
+
See special note about error handling for streams in
|
|
359
|
+
[`setErrorHandler`](./Server.md#seterrorhandler).
|
|
348
360
|
|
|
349
|
-
Example (no `reply.code()` call) sets status code to `303` and redirects to
|
|
350
|
-
`/home`
|
|
351
361
|
```js
|
|
352
|
-
|
|
353
|
-
```
|
|
362
|
+
const fs = require('node:fs')
|
|
354
363
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
reply.
|
|
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
|
+
})
|
|
358
369
|
```
|
|
359
|
-
|
|
360
|
-
Example (`reply.code()` call) sets status code to `302` and redirects to `/home`
|
|
370
|
+
When using async-await you will need to return or await the reply object:
|
|
361
371
|
```js
|
|
362
|
-
|
|
363
|
-
```
|
|
364
|
-
|
|
365
|
-
### .callNotFound()
|
|
366
|
-
<a id="call-not-found"></a>
|
|
367
|
-
|
|
368
|
-
Invokes the custom not found handler. Note that it will only call `preHandler`
|
|
369
|
-
hook specified in [`setNotFoundHandler`](./Server.md#set-not-found-handler).
|
|
372
|
+
const fs = require('node:fs')
|
|
370
373
|
|
|
371
|
-
|
|
372
|
-
|
|
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
|
+
})
|
|
373
379
|
```
|
|
374
380
|
|
|
375
|
-
|
|
376
|
-
<a id="
|
|
381
|
+
###### ReadableStream
|
|
382
|
+
<a id="send-readablestream"></a>
|
|
377
383
|
|
|
378
|
-
|
|
379
|
-
|
|
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.
|
|
380
387
|
|
|
381
388
|
```js
|
|
382
|
-
|
|
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
|
+
})
|
|
383
397
|
```
|
|
384
|
-
If the `Content-Type` has a JSON subtype, and the charset parameter is not set,
|
|
385
|
-
`utf-8` will be used as the charset by default. For other content types, the
|
|
386
|
-
charset must be set explicitly.
|
|
387
398
|
|
|
388
|
-
|
|
389
|
-
<a id="
|
|
399
|
+
###### Response
|
|
400
|
+
<a id="send-response"></a>
|
|
390
401
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
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.
|
|
395
406
|
|
|
396
|
-
|
|
397
|
-
|
|
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.
|
|
398
412
|
|
|
399
413
|
```js
|
|
400
|
-
const
|
|
401
|
-
|
|
402
|
-
type: 'object',
|
|
403
|
-
properties: {
|
|
404
|
-
foo: {
|
|
405
|
-
type: 'string'
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
})
|
|
409
|
-
serialize({ foo: 'bar' }) // '{"foo":"bar"}'
|
|
410
|
-
|
|
411
|
-
// or
|
|
412
|
-
|
|
413
|
-
const serialize = reply
|
|
414
|
-
.getSerializationFunction(200)
|
|
415
|
-
serialize({ foo: 'bar' }) // '{"foo":"bar"}'
|
|
416
|
-
|
|
417
|
-
// or
|
|
414
|
+
const fs = require('node:fs')
|
|
415
|
+
const { ReadableStream } = require('node:stream/web')
|
|
418
416
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
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
|
+
})
|
|
422
426
|
```
|
|
423
427
|
|
|
424
|
-
See [.compileSerializationSchema(schema, [httpStatus], [contentType])](#compileserializationschema)
|
|
425
|
-
for more information on how to compile serialization schemas.
|
|
426
|
-
|
|
427
|
-
### .compileSerializationSchema(schema, [httpStatus], [contentType])
|
|
428
|
-
<a id="compileserializationschema"></a>
|
|
429
|
-
|
|
430
|
-
This function will compile a serialization schema and
|
|
431
|
-
return a function that can be used to serialize data.
|
|
432
|
-
The function returned (a.k.a. _serialization function_) returned is compiled
|
|
433
|
-
by using the provided `SerializerCompiler`. Also this is cached by using
|
|
434
|
-
a `WeakMap` for reducing compilation calls.
|
|
435
428
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
to compile the serialization function if a custom `SerializerCompiler` is used.
|
|
429
|
+
###### Errors
|
|
430
|
+
<a id="errors"></a>
|
|
439
431
|
|
|
440
|
-
|
|
441
|
-
|
|
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:
|
|
442
434
|
|
|
443
435
|
```js
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
}
|
|
452
|
-
})
|
|
453
|
-
serialize({ foo: 'bar' }) // '{"foo":"bar"}'
|
|
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
|
+
}
|
|
442
|
+
```
|
|
454
443
|
|
|
455
|
-
|
|
444
|
+
You can add custom properties to the Error object, such as `headers`, that will
|
|
445
|
+
be used to enhance the HTTP response.
|
|
456
446
|
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
properties: {
|
|
461
|
-
foo: {
|
|
462
|
-
type: 'string'
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
}, 200)
|
|
466
|
-
serialize({ foo: 'bar' }) // '{"foo":"bar"}'
|
|
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.
|
|
467
450
|
|
|
468
|
-
|
|
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:
|
|
469
455
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
'application/json': {
|
|
475
|
-
schema: {
|
|
476
|
-
name: { type: 'string' },
|
|
477
|
-
phone: { type: 'number' }
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
}, '3xx', 'application/json')
|
|
483
|
-
serialize({ name: 'Jone', phone: 201090909090 }) // '{"name":"Jone", "phone":201090909090}'
|
|
456
|
+
```js
|
|
457
|
+
fastify.get('/', function (request, reply) {
|
|
458
|
+
reply.send(httpErrors.Gone())
|
|
459
|
+
})
|
|
484
460
|
```
|
|
485
461
|
|
|
486
|
-
|
|
487
|
-
the compiled serialization functions based on the schema provided. If the
|
|
488
|
-
schemas provided is mutated or changed, the serialization functions will not
|
|
489
|
-
detect that the schema has been altered and for instance it will reuse the
|
|
490
|
-
previously compiled serialization function based on the reference of the schema
|
|
491
|
-
previously provided.
|
|
462
|
+
To customize the JSON error output you can do it by:
|
|
492
463
|
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
464
|
+
- setting a response JSON schema for the status code you need
|
|
465
|
+
- add the additional properties to the `Error` instance
|
|
466
|
+
|
|
467
|
+
Notice that if the returned status code is not in the response schema list, the
|
|
468
|
+
default behavior will be applied.
|
|
496
469
|
|
|
497
|
-
:Using the following schema as example:
|
|
498
470
|
```js
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
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
|
+
}
|
|
504
484
|
}
|
|
505
485
|
}
|
|
506
|
-
}
|
|
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
|
+
})
|
|
507
491
|
```
|
|
508
492
|
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
const serialize = reply.compileSerializationSchema(schema1)
|
|
493
|
+
If you want to customize error handling, check out
|
|
494
|
+
[`setErrorHandler`](./Server.md#seterrorhandler) API.
|
|
512
495
|
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
const newSerialize = reply.compileSerializationSchema(schema1)
|
|
496
|
+
> ℹ️ Note:
|
|
497
|
+
> You are responsible for logging when customizing the error handler.
|
|
516
498
|
|
|
517
|
-
|
|
518
|
-
```
|
|
499
|
+
API:
|
|
519
500
|
|
|
520
|
-
*Instead*
|
|
521
501
|
```js
|
|
522
|
-
|
|
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
|
+
})
|
|
510
|
+
```
|
|
523
511
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
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.
|
|
527
516
|
|
|
528
|
-
|
|
517
|
+
The not found errors generated by the router will use the
|
|
518
|
+
[`setNotFoundHandler`](./Server.md#setnotfoundhandler)
|
|
529
519
|
|
|
530
|
-
|
|
520
|
+
API:
|
|
521
|
+
|
|
522
|
+
```js
|
|
523
|
+
fastify.setNotFoundHandler(function (request, reply) {
|
|
524
|
+
reply
|
|
525
|
+
.code(404)
|
|
526
|
+
.type('text/plain')
|
|
527
|
+
.send('a custom not found')
|
|
528
|
+
})
|
|
531
529
|
```
|
|
532
530
|
|
|
533
|
-
|
|
534
|
-
<a id="
|
|
531
|
+
###### Async-Await and Promises
|
|
532
|
+
<a id="async-await-promise"></a>
|
|
535
533
|
|
|
536
|
-
|
|
537
|
-
or HTTP status code. If both are provided the `httpStatus` will take precedence.
|
|
534
|
+
Fastify natively handles promises and supports async-await.
|
|
538
535
|
|
|
539
|
-
|
|
540
|
-
|
|
536
|
+
*Note that in the following examples we are not using reply.send.*
|
|
537
|
+
```js
|
|
538
|
+
const { promisify } = require('node:util')
|
|
539
|
+
const delay = promisify(setTimeout)
|
|
540
|
+
|
|
541
|
+
fastify.get('/promises', options, function (request, reply) {
|
|
542
|
+
return delay(200).then(() => { return { hello: 'world' }})
|
|
543
|
+
})
|
|
544
|
+
|
|
545
|
+
fastify.get('/async-await', options, async function (request, reply) {
|
|
546
|
+
await delay(200)
|
|
547
|
+
return { hello: 'world' }
|
|
548
|
+
})
|
|
549
|
+
```
|
|
550
|
+
|
|
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.
|
|
541
554
|
|
|
542
555
|
```js
|
|
543
|
-
reply
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
}) // '{"foo":"bar"}'
|
|
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
|
+
})
|
|
552
562
|
|
|
553
|
-
|
|
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
|
+
})
|
|
567
|
+
```
|
|
554
568
|
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
type: 'object',
|
|
558
|
-
properties: {
|
|
559
|
-
foo: {
|
|
560
|
-
type: 'string'
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
}, 200) // '{"foo":"bar"}'
|
|
569
|
+
If you want to know more please review
|
|
570
|
+
[Routes#async-await](./Routes.md#async-await).
|
|
564
571
|
|
|
565
|
-
|
|
572
|
+
###### Type of the final payload
|
|
573
|
+
<a id="payload-type"></a>
|
|
566
574
|
|
|
567
|
-
|
|
568
|
-
|
|
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:
|
|
569
578
|
|
|
570
|
-
|
|
579
|
+
- `string`
|
|
580
|
+
- `Buffer`
|
|
581
|
+
- `stream`
|
|
582
|
+
- `undefined`
|
|
583
|
+
- `null`
|
|
571
584
|
|
|
572
|
-
|
|
573
|
-
|
|
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.
|
|
632
|
+
```js
|
|
633
|
+
reply.headers({
|
|
634
|
+
'x-foo': 'foo',
|
|
635
|
+
'x-bar': 'bar'
|
|
636
|
+
})
|
|
574
637
|
```
|
|
575
638
|
|
|
576
|
-
|
|
577
|
-
|
|
639
|
+
##### .type(contentType)
|
|
640
|
+
<a id="type"></a>
|
|
578
641
|
|
|
579
|
-
|
|
580
|
-
|
|
642
|
+
Sets the content type for the response. This is a shortcut for
|
|
643
|
+
`reply.header('Content-Type', 'the/type')`.
|
|
581
644
|
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
the
|
|
586
|
-
|
|
645
|
+
```js
|
|
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.
|
|
651
|
+
|
|
652
|
+
##### .redirect(dest, [code])
|
|
653
|
+
<a id="redirect"></a>
|
|
654
|
+
|
|
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.
|
|
587
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`
|
|
588
684
|
```js
|
|
589
|
-
reply
|
|
590
|
-
.header('Content-Type', 'application/x-protobuf')
|
|
591
|
-
.serializer(protoBuf.serialize)
|
|
685
|
+
reply.redirect('/home')
|
|
592
686
|
```
|
|
593
687
|
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
688
|
+
Example (no `reply.code()` call) sets status code to `303` and redirects to
|
|
689
|
+
`/home`
|
|
690
|
+
```js
|
|
691
|
+
reply.redirect('/home', 303)
|
|
692
|
+
```
|
|
597
693
|
|
|
694
|
+
Example (`reply.code()` call) sets status code to `303` and redirects to `/home`
|
|
598
695
|
```js
|
|
599
|
-
reply
|
|
600
|
-
.header('Content-Type', 'application/x-protobuf')
|
|
601
|
-
.send(protoBuf.serialize(data))
|
|
696
|
+
reply.code(303).redirect('/home')
|
|
602
697
|
```
|
|
603
698
|
|
|
604
|
-
|
|
605
|
-
|
|
699
|
+
Example (`reply.code()` call) sets status code to `302` and redirects to `/home`
|
|
700
|
+
```js
|
|
701
|
+
reply.code(303).redirect('/home', 302)
|
|
702
|
+
```
|
|
606
703
|
|
|
607
|
-
|
|
608
|
-
<a id="
|
|
704
|
+
##### .getHeader(key)
|
|
705
|
+
<a id="getHeader"></a>
|
|
609
706
|
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
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'
|
|
711
|
+
```
|
|
712
|
+
|
|
713
|
+
##### .getHeaders()
|
|
714
|
+
<a id="getHeaders"></a>
|
|
715
|
+
|
|
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`.
|
|
615
719
|
|
|
616
720
|
```js
|
|
617
|
-
|
|
618
|
-
|
|
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
|
+
```
|
|
619
726
|
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
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>
|
|
734
|
+
|
|
735
|
+
Remove the value of a previously set header.
|
|
736
|
+
```js
|
|
737
|
+
reply.header('x-foo', 'foo')
|
|
738
|
+
reply.removeHeader('x-foo')
|
|
739
|
+
reply.getHeader('x-foo') // undefined
|
|
625
740
|
```
|
|
626
|
-
Another example of the misuse of `Reply.raw` is explained in
|
|
627
|
-
[Reply](#getheaders).
|
|
628
741
|
|
|
629
|
-
|
|
630
|
-
<a id="
|
|
742
|
+
##### .callNotFound()
|
|
743
|
+
<a id="call-not-found"></a>
|
|
631
744
|
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
used.
|
|
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).
|
|
635
747
|
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
By calling `reply.hijack()`, an application claims full responsibility for the
|
|
640
|
-
low-level request and response. Moreover, hooks will not be invoked.
|
|
748
|
+
```js
|
|
749
|
+
reply.callNotFound()
|
|
750
|
+
```
|
|
641
751
|
|
|
642
|
-
|
|
752
|
+
##### .hijack()
|
|
643
753
|
<a name="hijack"></a>
|
|
644
754
|
|
|
645
755
|
Sometimes you might need to halt the execution of the normal request lifecycle
|
|
@@ -662,357 +772,353 @@ app.get('/', (req, reply) => {
|
|
|
662
772
|
If `reply.raw` is used to send a response back to the user, the `onResponse`
|
|
663
773
|
hooks will still be executed.
|
|
664
774
|
|
|
665
|
-
|
|
666
|
-
<a id="
|
|
667
|
-
|
|
668
|
-
As the name suggests, `.send()` is the function that sends the payload to the
|
|
669
|
-
end user.
|
|
775
|
+
##### .serializer(func)
|
|
776
|
+
<a id="serializer"></a>
|
|
670
777
|
|
|
671
|
-
|
|
672
|
-
|
|
778
|
+
By default, `.send()` will JSON-serialize any value that is not one of `Buffer`,
|
|
779
|
+
`stream`, `string`, `undefined`, or `Error`. If you need to replace the default
|
|
780
|
+
serializer with a custom serializer for a particular request, you can do so with
|
|
781
|
+
the `.serializer()` utility. Be aware that if you are using a custom serializer,
|
|
782
|
+
you must set a custom `'Content-Type'` header.
|
|
673
783
|
|
|
674
|
-
As noted above, if you are sending JSON objects, `send` will serialize the
|
|
675
|
-
object with
|
|
676
|
-
[fast-json-stringify](https://www.npmjs.com/package/fast-json-stringify) if you
|
|
677
|
-
set an output schema, otherwise, `JSON.stringify()` will be used.
|
|
678
784
|
```js
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
785
|
+
reply
|
|
786
|
+
.header('Content-Type', 'application/x-protobuf')
|
|
787
|
+
.serializer(protoBuf.serialize)
|
|
682
788
|
```
|
|
683
789
|
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
If you pass a string to `send` without a `Content-Type`, it will be sent as
|
|
688
|
-
`text/plain; charset=utf-8`. If you set the `Content-Type` header and pass a
|
|
689
|
-
string to `send`, it will be serialized with the custom serializer if one is
|
|
690
|
-
set, otherwise, it will be sent unmodified.
|
|
691
|
-
|
|
692
|
-
> ℹ️ Note:
|
|
693
|
-
> Even when the `Content-Type` header is set to `application/json`,
|
|
694
|
-
> strings are sent unmodified by default. To serialize a string as JSON, you
|
|
695
|
-
> must set a custom serializer:
|
|
790
|
+
Note that you don't need to use this utility inside a `handler` because Buffers,
|
|
791
|
+
streams, and strings (unless a serializer is set) are considered to already be
|
|
792
|
+
serialized.
|
|
696
793
|
|
|
697
794
|
```js
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
.serializer(JSON.stringify)
|
|
702
|
-
.send('Hello') // Returns "Hello" (JSON-encoded string)
|
|
703
|
-
})
|
|
795
|
+
reply
|
|
796
|
+
.header('Content-Type', 'application/x-protobuf')
|
|
797
|
+
.send(protoBuf.serialize(data))
|
|
704
798
|
```
|
|
799
|
+
|
|
800
|
+
See [`.send()`](#send) for more information on sending different types of
|
|
801
|
+
values.
|
|
802
|
+
|
|
803
|
+
##### .serialize(payload)
|
|
804
|
+
<a id="serialize"></a>
|
|
805
|
+
|
|
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.
|
|
810
|
+
|
|
705
811
|
```js
|
|
706
|
-
fastify.get('/
|
|
707
|
-
reply.
|
|
812
|
+
fastify.get('/', function (request, reply) {
|
|
813
|
+
const payload = reply.serialize({ hello: 'world' })
|
|
814
|
+
reply.type('application/json').send(payload)
|
|
708
815
|
})
|
|
709
816
|
```
|
|
710
817
|
|
|
711
|
-
|
|
712
|
-
<a id="
|
|
713
|
-
|
|
714
|
-
If you are sending a stream and you have not set a `'Content-Type'` header,
|
|
715
|
-
*send* will set it to `'application/octet-stream'`.
|
|
818
|
+
##### .trailer(key, function)
|
|
819
|
+
<a id="trailer"></a>
|
|
716
820
|
|
|
717
|
-
|
|
718
|
-
sent
|
|
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.
|
|
719
825
|
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
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.
|
|
724
830
|
|
|
725
|
-
|
|
726
|
-
|
|
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.
|
|
727
834
|
|
|
728
835
|
```js
|
|
729
|
-
|
|
836
|
+
reply.trailer('server-timing', async function () {
|
|
837
|
+
return 'db;dur=53, app;dur=47.2'
|
|
838
|
+
})
|
|
730
839
|
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
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'))
|
|
735
849
|
})
|
|
736
|
-
```
|
|
737
|
-
When using async-await you will need to return or await the reply object:
|
|
738
|
-
```js
|
|
739
|
-
const fs = require('node:fs')
|
|
740
850
|
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
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')
|
|
745
856
|
})
|
|
746
857
|
```
|
|
747
858
|
|
|
748
|
-
|
|
749
|
-
<a id="
|
|
859
|
+
##### .hasTrailer(key)
|
|
860
|
+
<a id="hasTrailer"></a>
|
|
750
861
|
|
|
751
|
-
|
|
752
|
-
*send* will set it to `'application/octet-stream'`.
|
|
862
|
+
Returns a boolean indicating if the specified trailer has been set.
|
|
753
863
|
|
|
754
|
-
|
|
755
|
-
|
|
864
|
+
##### .removeTrailer(key)
|
|
865
|
+
<a id="removeTrailer"></a>
|
|
756
866
|
|
|
867
|
+
Remove the value of a previously set trailer.
|
|
757
868
|
```js
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
fastify.get('/streams', function (request, reply) {
|
|
761
|
-
fs.readFile('some-file', (err, fileBuffer) => {
|
|
762
|
-
reply.send(err || fileBuffer)
|
|
763
|
-
})
|
|
869
|
+
reply.trailer('server-timing', async function () {
|
|
870
|
+
return 'db;dur=53, app;dur=47.2'
|
|
764
871
|
})
|
|
872
|
+
reply.removeTrailer('server-timing')
|
|
873
|
+
reply.hasTrailer('server-timing') // false
|
|
765
874
|
```
|
|
766
875
|
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
const fs = require('node:fs')
|
|
770
|
-
|
|
771
|
-
fastify.get('/streams', async function (request, reply) {
|
|
772
|
-
fs.readFile('some-file', (err, fileBuffer) => {
|
|
773
|
-
reply.send(err || fileBuffer)
|
|
774
|
-
})
|
|
775
|
-
return reply
|
|
776
|
-
})
|
|
777
|
-
```
|
|
876
|
+
##### .writeEarlyHints(hints, callback)
|
|
877
|
+
<a id="writeEarlyHints"></a>
|
|
778
878
|
|
|
779
|
-
|
|
780
|
-
|
|
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.
|
|
781
883
|
|
|
782
|
-
|
|
783
|
-
header to `'application/octet-stream'` if not already set.
|
|
884
|
+
The hints parameter is an object containing the early hint key-value pairs.
|
|
784
885
|
|
|
785
|
-
|
|
786
|
-
will be sent unmodified without response validation.
|
|
886
|
+
Example:
|
|
787
887
|
|
|
788
888
|
```js
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
const typedArray = new Uint16Array(10)
|
|
793
|
-
reply.send(typedArray)
|
|
794
|
-
})
|
|
889
|
+
reply.writeEarlyHints({
|
|
890
|
+
Link: '</styles.css>; rel=preload; as=style'
|
|
891
|
+
});
|
|
795
892
|
```
|
|
796
893
|
|
|
797
|
-
|
|
798
|
-
|
|
894
|
+
The optional callback parameter is a function that will be called
|
|
895
|
+
once the hint is sent or if an error occurs.
|
|
799
896
|
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
sent unmodified without response validation.
|
|
897
|
+
##### .then(fulfilled, rejected)
|
|
898
|
+
<a id="then"></a>
|
|
803
899
|
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
const { ReadableStream } = require('node:stream/web')
|
|
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()`.
|
|
807
902
|
|
|
808
|
-
|
|
809
|
-
const stream = fs.createReadStream('some-file')
|
|
810
|
-
reply.header('Content-Type', 'application/octet-stream')
|
|
811
|
-
reply.send(ReadableStream.from(stream))
|
|
812
|
-
})
|
|
813
|
-
```
|
|
903
|
+
`reply.then(fulfilled, rejected)` accepts two parameters:
|
|
814
904
|
|
|
815
|
-
|
|
816
|
-
|
|
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.
|
|
817
908
|
|
|
818
|
-
|
|
819
|
-
headers in one place. The payload provided inside `Response` is
|
|
820
|
-
considered to be pre-serialized, so they will be sent unmodified
|
|
821
|
-
without response validation.
|
|
909
|
+
For more details, see:
|
|
822
910
|
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
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
|
|
915
|
+
|
|
916
|
+
##### .getDecorator(name)
|
|
917
|
+
|
|
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.
|
|
828
923
|
|
|
829
924
|
```js
|
|
830
|
-
|
|
831
|
-
|
|
925
|
+
fastify.decorateReply('helper', function () {
|
|
926
|
+
return this.statusCode
|
|
927
|
+
})
|
|
832
928
|
|
|
833
|
-
fastify.get('/
|
|
834
|
-
const
|
|
835
|
-
|
|
836
|
-
const response = new Response(readableStream, {
|
|
837
|
-
status: 200,
|
|
838
|
-
headers: { 'content-type': 'application/octet-stream' }
|
|
839
|
-
})
|
|
840
|
-
reply.send(response)
|
|
929
|
+
fastify.get('/', function (request, reply) {
|
|
930
|
+
const helper = reply.getDecorator('helper')
|
|
931
|
+
reply.code(201).send({ statusCode: helper() }) // { statusCode: 201 }
|
|
841
932
|
})
|
|
842
933
|
```
|
|
843
934
|
|
|
935
|
+
##### .getSerializationFunction(schema | httpStatus, [contentType])
|
|
936
|
+
<a id="getserializationfunction"></a>
|
|
844
937
|
|
|
845
|
-
|
|
846
|
-
|
|
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.
|
|
847
942
|
|
|
848
|
-
|
|
849
|
-
|
|
943
|
+
This heavily depends of the `schema#responses` attached to the route, or
|
|
944
|
+
the serialization functions compiled by using `compileSerializationSchema`.
|
|
850
945
|
|
|
851
946
|
```js
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
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"}'
|
|
859
957
|
|
|
860
|
-
|
|
861
|
-
be used to enhance the HTTP response.
|
|
958
|
+
// or
|
|
862
959
|
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
960
|
+
const serialize = reply
|
|
961
|
+
.getSerializationFunction(200)
|
|
962
|
+
serialize({ foo: 'bar' }) // '{"foo":"bar"}'
|
|
866
963
|
|
|
867
|
-
|
|
868
|
-
[`http-errors`](https://www.npmjs.com/package/http-errors) module or
|
|
869
|
-
[`@fastify/sensible`](https://github.com/fastify/fastify-sensible) plugin to
|
|
870
|
-
generate errors:
|
|
964
|
+
// or
|
|
871
965
|
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
})
|
|
966
|
+
const serialize = reply
|
|
967
|
+
.getSerializationFunction(200, 'application/json')
|
|
968
|
+
serialize({ foo: 'bar' }) // '{"foo":"bar"}'
|
|
876
969
|
```
|
|
877
970
|
|
|
878
|
-
|
|
971
|
+
See [.compileSerializationSchema(schema, [httpStatus], [contentType])](#compileserializationschema)
|
|
972
|
+
for more information on how to compile serialization schemas.
|
|
879
973
|
|
|
880
|
-
|
|
881
|
-
|
|
974
|
+
##### .compileSerializationSchema(schema, [httpStatus], [contentType])
|
|
975
|
+
<a id="compileserializationschema"></a>
|
|
882
976
|
|
|
883
|
-
|
|
884
|
-
|
|
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.
|
|
982
|
+
|
|
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.
|
|
986
|
+
|
|
987
|
+
This heavily depends of the `schema#responses` attached to the route, or
|
|
988
|
+
the serialization functions compiled by using `compileSerializationSchema`.
|
|
885
989
|
|
|
886
990
|
```js
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
time: { type: 'string' }
|
|
898
|
-
}
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
}
|
|
902
|
-
}, function (request, reply) {
|
|
903
|
-
const error = new Error('This endpoint has not been implemented')
|
|
904
|
-
error.time = 'it will be implemented in two weeks'
|
|
905
|
-
reply.code(501).send(error)
|
|
906
|
-
})
|
|
907
|
-
```
|
|
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"}'
|
|
908
1001
|
|
|
909
|
-
|
|
910
|
-
[`setErrorHandler`](./Server.md#seterrorhandler) API.
|
|
1002
|
+
// or
|
|
911
1003
|
|
|
912
|
-
|
|
913
|
-
|
|
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"}'
|
|
914
1014
|
|
|
915
|
-
|
|
1015
|
+
// or
|
|
916
1016
|
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
}
|
|
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}'
|
|
926
1031
|
```
|
|
927
1032
|
|
|
928
|
-
|
|
929
|
-
the
|
|
930
|
-
|
|
931
|
-
for
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
[`setNotFoundHandler`](./Server.md#setnotfoundhandler)
|
|
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.
|
|
935
1039
|
|
|
936
|
-
|
|
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.
|
|
937
1043
|
|
|
1044
|
+
:Using the following schema as example:
|
|
938
1045
|
```js
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
}
|
|
1046
|
+
const schema1 = {
|
|
1047
|
+
type: 'object',
|
|
1048
|
+
properties: {
|
|
1049
|
+
foo: {
|
|
1050
|
+
type: 'string'
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
945
1054
|
```
|
|
946
1055
|
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
The type of the sent payload (after serialization and going through any
|
|
951
|
-
[`onSend` hooks](./Hooks.md#onsend)) must be one of the following types,
|
|
952
|
-
otherwise, an error will be thrown:
|
|
953
|
-
|
|
954
|
-
- `string`
|
|
955
|
-
- `Buffer`
|
|
956
|
-
- `stream`
|
|
957
|
-
- `undefined`
|
|
958
|
-
- `null`
|
|
1056
|
+
*Not*
|
|
1057
|
+
```js
|
|
1058
|
+
const serialize = reply.compileSerializationSchema(schema1)
|
|
959
1059
|
|
|
960
|
-
|
|
961
|
-
|
|
1060
|
+
// Later on...
|
|
1061
|
+
schema1.properties.foo.type = 'integer'
|
|
1062
|
+
const newSerialize = reply.compileSerializationSchema(schema1)
|
|
962
1063
|
|
|
963
|
-
|
|
1064
|
+
console.log(newSerialize === serialize) // true
|
|
1065
|
+
```
|
|
964
1066
|
|
|
965
|
-
*
|
|
1067
|
+
*Instead*
|
|
966
1068
|
```js
|
|
967
|
-
const
|
|
968
|
-
const delay = promisify(setTimeout)
|
|
1069
|
+
const serialize = reply.compileSerializationSchema(schema1)
|
|
969
1070
|
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
1071
|
+
// Later on...
|
|
1072
|
+
const newSchema = Object.assign({}, schema1)
|
|
1073
|
+
newSchema.properties.foo.type = 'integer'
|
|
973
1074
|
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
})
|
|
1075
|
+
const newSerialize = reply.compileSerializationSchema(newSchema)
|
|
1076
|
+
|
|
1077
|
+
console.log(newSerialize === serialize) // false
|
|
978
1078
|
```
|
|
979
1079
|
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
`status`) and `message` properties to modify the reply.
|
|
1080
|
+
##### .serializeInput(data, [schema | httpStatus], [httpStatus], [contentType])
|
|
1081
|
+
<a id="serializeinput"></a>
|
|
983
1082
|
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
const err = new Error()
|
|
987
|
-
err.statusCode = 418
|
|
988
|
-
err.message = 'short and stout'
|
|
989
|
-
throw err
|
|
990
|
-
})
|
|
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.
|
|
991
1085
|
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
// will return to the client the same json
|
|
995
|
-
})
|
|
996
|
-
```
|
|
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.
|
|
997
1088
|
|
|
998
|
-
|
|
999
|
-
|
|
1089
|
+
```js
|
|
1090
|
+
reply
|
|
1091
|
+
.serializeInput({ foo: 'bar'}, {
|
|
1092
|
+
type: 'object',
|
|
1093
|
+
properties: {
|
|
1094
|
+
foo: {
|
|
1095
|
+
type: 'string'
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
}) // '{"foo":"bar"}'
|
|
1000
1099
|
|
|
1001
|
-
|
|
1002
|
-
<a id="then"></a>
|
|
1100
|
+
// or
|
|
1003
1101
|
|
|
1004
|
-
|
|
1005
|
-
|
|
1102
|
+
reply
|
|
1103
|
+
.serializeInput({ foo: 'bar'}, {
|
|
1104
|
+
type: 'object',
|
|
1105
|
+
properties: {
|
|
1106
|
+
foo: {
|
|
1107
|
+
type: 'string'
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
}, 200) // '{"foo":"bar"}'
|
|
1006
1111
|
|
|
1007
|
-
|
|
1112
|
+
// or
|
|
1008
1113
|
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
socket has been destroyed.
|
|
1114
|
+
reply
|
|
1115
|
+
.serializeInput({ foo: 'bar'}, 200) // '{"foo":"bar"}'
|
|
1012
1116
|
|
|
1013
|
-
|
|
1117
|
+
// or
|
|
1014
1118
|
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1119
|
+
reply
|
|
1120
|
+
.serializeInput({ name: 'Jone', age: 18 }, '200', 'application/vnd.v1+json') // '{"name": "Jone", "age": 18}'
|
|
1121
|
+
```
|
|
1122
|
+
|
|
1123
|
+
See [.compileSerializationSchema(schema, [httpStatus], [contentType])](#compileserializationschema)
|
|
1124
|
+
for more information on how to compile serialization schemas.
|