strong-tie/inbound-calls
0
1<h1 align="center">Fastify</h1>2 3## Reply4- [Reply](#reply)5 - [Introduction](#introduction)6 - [.code(statusCode)](#codestatuscode)7 - [.elapsedTime](#elapsedtime)8 - [.statusCode](#statuscode)9 - [.server](#server)10 - [.header(key, value)](#headerkey-value)11 - [.headers(object)](#headersobject)12 - [.getHeader(key)](#getheaderkey)13 - [.getHeaders()](#getheaders)14 - [.removeHeader(key)](#removeheaderkey)15 - [.hasHeader(key)](#hasheaderkey)16 - [.writeEarlyHints(hints, callback)](#writeearlyhintshints-callback)17 - [.trailer(key, function)](#trailerkey-function)18 - [.hasTrailer(key)](#hastrailerkey)19 - [.removeTrailer(key)](#removetrailerkey)20 - [.redirect(dest, [code ,])](#redirectdest--code)21 - [.callNotFound()](#callnotfound)22 - [.type(contentType)](#typecontenttype)23 - [.getSerializationFunction(schema | httpStatus, [contentType])](#getserializationfunctionschema--httpstatus)24 - [.compileSerializationSchema(schema, [httpStatus], [contentType])](#compileserializationschemaschema-httpstatus)25 - [.serializeInput(data, [schema | httpStatus], [httpStatus], [contentType])](#serializeinputdata-schema--httpstatus-httpstatus)26 - [.serializer(func)](#serializerfunc)27 - [.raw](#raw)28 - [.sent](#sent)29 - [.hijack()](#hijack)30 - [.send(data)](#senddata)31 - [Objects](#objects)32 - [Strings](#strings)33 - [Streams](#streams)34 - [Buffers](#buffers)35 - [TypedArrays](#typedarrays)36 - [ReadableStream](#readablestream)37 - [Response](#response)38 - [Errors](#errors)39 - [Type of the final payload](#type-of-the-final-payload)40 - [Async-Await and Promises](#async-await-and-promises)41 - [.then(fulfilled, rejected)](#thenfulfilled-rejected)42 43### Introduction44<a id="introduction"></a>45 46The second parameter of the handler function is `Reply`. Reply is a core Fastify47object that exposes the following functions and properties:48 49- `.code(statusCode)` - Sets the status code.50- `.status(statusCode)` - An alias for `.code(statusCode)`.51- `.statusCode` - Read and set the HTTP status code.52- `.elapsedTime` - Returns the amount of time passed53since the request was received by Fastify.54- `.server` - A reference to the fastify instance object.55- `.header(name, value)` - Sets a response header.56- `.headers(object)` - Sets all the keys of the object as response headers.57- `.getHeader(name)` - Retrieve value of already set header.58- `.getHeaders()` - Gets a shallow copy of all current response headers.59- `.removeHeader(key)` - Remove the value of a previously set header.60- `.hasHeader(name)` - Determine if a header has been set.61- `.writeEarlyHints(hints, callback)` - Sends early hints to the user62 while the response is being prepared.63- `.trailer(key, function)` - Sets a response trailer.64- `.hasTrailer(key)` - Determine if a trailer has been set.65- `.removeTrailer(key)` - Remove the value of a previously set trailer.66- `.type(value)` - Sets the header `Content-Type`.67- `.redirect(dest, [code,])` - Redirect to the specified URL, the status code is68 optional (defaults to `302`).69- `.callNotFound()` - Invokes the custom not found handler.70- `.serialize(payload)` - Serializes the specified payload using the default71 JSON serializer or using the custom serializer (if one is set) and returns the72 serialized payload.73- `.getSerializationFunction(schema | httpStatus, [contentType])` - Returns the serialization74 function for the specified schema or http status, if any of either are set.75- `.compileSerializationSchema(schema, [httpStatus], [contentType])` - Compiles76 the specified schema and returns a serialization function using the default77 (or customized) `SerializerCompiler`. The optional `httpStatus` is forwarded78 to the `SerializerCompiler` if provided, default to `undefined`.79- `.serializeInput(data, schema, [,httpStatus], [contentType])` - Serializes80 the specified data using the specified schema and returns the serialized payload.81 If the optional `httpStatus`, and `contentType` are provided, the function82 will use the serializer function given for that specific content type and83 HTTP Status Code. Default to `undefined`.84- `.serializer(function)` - Sets a custom serializer for the payload.85- `.send(payload)` - Sends the payload to the user, could be a plain text, a86 buffer, JSON, stream, or an Error object.87- `.sent` - A boolean value that you can use if you need to know if `send` has88 already been called.89- `.hijack()` - interrupt the normal request lifecycle.90- `.raw` - The91 [`http.ServerResponse`](https://nodejs.org/dist/latest-v20.x/docs/api/http.html#http_class_http_serverresponse)92 from Node core.93- `.log` - The logger instance of the incoming request.94- `.request` - The incoming request.95 96```js97fastify.get('/', options, function (request, reply) {98 // Your code99 reply100 .code(200)101 .header('Content-Type', 'application/json; charset=utf-8')102 .send({ hello: 'world' })103})104```105 106### .code(statusCode)107<a id="code"></a>108 109If not set via `reply.code`, the resulting `statusCode` will be `200`.110 111### .elapsedTime112<a id="elapsedTime"></a>113 114Invokes the custom response time getter to calculate the amount of time passed115since the request was received by Fastify.116 117```js118const milliseconds = reply.elapsedTime119```120 121### .statusCode122<a id="statusCode"></a>123 124This property reads and sets the HTTP status code. It is an alias for125`reply.code()` when used as a setter.126```js127if (reply.statusCode >= 299) {128 reply.statusCode = 500129}130```131 132### .server133<a id="server"></a>134 135The Fastify server instance, scoped to the current [encapsulation136context](./Encapsulation.md).137 138```js139fastify.decorate('util', function util () {140 return 'foo'141})142 143fastify.get('/', async function (req, rep) {144 return rep.server.util() // foo145})146```147 148### .header(key, value)149<a id="header"></a>150 151Sets a response header. If the value is omitted or undefined, it is coerced to152`''`.153 154> Note: the header's value must be properly encoded using155> [`encodeURI`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI)156> or similar modules such as157> [`encodeurl`](https://www.npmjs.com/package/encodeurl). Invalid characters158> will result in a 500 `TypeError` response.159 160For more information, see161[`http.ServerResponse#setHeader`](https://nodejs.org/dist/latest-v20.x/docs/api/http.html#http_response_setheader_name_value).162 163- ### set-cookie164 <a id="set-cookie"></a>165 166 - When sending different values as a cookie with `set-cookie` as the key,167 every value will be sent as a cookie instead of replacing the previous168 value.169 170 ```js171 reply.header('set-cookie', 'foo');172 reply.header('set-cookie', 'bar');173 ```174 - The browser will only consider the latest reference of a key for the175 `set-cookie` header. This is done to avoid parsing the `set-cookie` header176 when added to a reply and speeds up the serialization of the reply.177 178 - To reset the `set-cookie` header, you need to make an explicit call to179 `reply.removeHeader('set-cookie')`, read more about `.removeHeader(key)`180 [here](#removeheaderkey).181 182 183 184### .headers(object)185<a id="headers"></a>186 187Sets all the keys of the object as response headers.188[`.header`](#headerkey-value) will be called under the hood.189```js190reply.headers({191 'x-foo': 'foo',192 'x-bar': 'bar'193})194```195 196### .getHeader(key)197<a id="getHeader"></a>198 199Retrieves the value of a previously set header.200```js201reply.header('x-foo', 'foo') // setHeader: key, value202reply.getHeader('x-foo') // 'foo'203```204 205### .getHeaders()206<a id="getHeaders"></a>207 208Gets a shallow copy of all current response headers, including those set via the209raw `http.ServerResponse`. Note that headers set via Fastify take precedence210over those set via `http.ServerResponse`.211 212```js213reply.header('x-foo', 'foo')214reply.header('x-bar', 'bar')215reply.raw.setHeader('x-foo', 'foo2')216reply.getHeaders() // { 'x-foo': 'foo', 'x-bar': 'bar' }217```218 219### .removeHeader(key)220<a id="getHeader"></a>221 222Remove the value of a previously set header.223```js224reply.header('x-foo', 'foo')225reply.removeHeader('x-foo')226reply.getHeader('x-foo') // undefined227```228 229### .hasHeader(key)230<a id="hasHeader"></a>231 232Returns a boolean indicating if the specified header has been set.233 234### .writeEarlyHints(hints, callback)235<a id="writeEarlyHints"></a>236 237Sends early hints to the client. Early hints allow the client to238start processing resources before the final response is sent.239This can improve performance by allowing the client to preload240or preconnect to resources while the server is still generating the response.241 242The hints parameter is an object containing the early hint key-value pairs.243 244Example:245 246```js247reply.writeEarlyHints({248 Link: '</styles.css>; rel=preload; as=style'249});250```251 252The optional callback parameter is a function that will be called253once the hint is sent or if an error occurs.254 255### .trailer(key, function)256<a id="trailer"></a>257 258Sets a response trailer. Trailer is usually used when you need a header that259requires heavy resources to be sent after the `data`, for example,260`Server-Timing` and `Etag`. It can ensure the client receives the response data261as soon as possible.262 263*Note: The header `Transfer-Encoding: chunked` will be added once you use the264trailer. It is a hard requirement for using trailer in Node.js.*265 266*Note: Any error passed to `done` callback will be ignored. If you interested267in the error, you can turn on `debug` level logging.*268 269```js270reply.trailer('server-timing', function() {271 return 'db;dur=53, app;dur=47.2'272})273 274const { createHash } = require('node:crypto')275// trailer function also receive two argument276// @param {object} reply fastify reply277// @param {string|Buffer|null} payload payload that already sent, note that it will be null when stream is sent278// @param {function} done callback to set trailer value279reply.trailer('content-md5', function(reply, payload, done) {280 const hash = createHash('md5')281 hash.update(payload)282 done(null, hash.disgest('hex'))283})284 285// when you prefer async-await286reply.trailer('content-md5', async function(reply, payload) {287 const hash = createHash('md5')288 hash.update(payload)289 return hash.disgest('hex')290})291```292 293### .hasTrailer(key)294<a id="hasTrailer"></a>295 296Returns a boolean indicating if the specified trailer has been set.297 298### .removeTrailer(key)299<a id="removeTrailer"></a>300 301Remove the value of a previously set trailer.302```js303reply.trailer('server-timing', function() {304 return 'db;dur=53, app;dur=47.2'305})306reply.removeTrailer('server-timing')307reply.getTrailer('server-timing') // undefined308```309 310 311### .redirect(dest, [code ,])312<a id="redirect"></a>313 314Redirects a request to the specified URL, the status code is optional, default315to `302` (if status code is not already set by calling `code`).316 317> Note: the input URL must be properly encoded using318> [`encodeURI`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI)319> or similar modules such as320> [`encodeurl`](https://www.npmjs.com/package/encodeurl). Invalid URLs will321> result in a 500 `TypeError` response.322 323Example (no `reply.code()` call) sets status code to `302` and redirects to324`/home`325```js326reply.redirect('/home')327```328 329Example (no `reply.code()` call) sets status code to `303` and redirects to330`/home`331```js332reply.redirect('/home', 303)333```334 335Example (`reply.code()` call) sets status code to `303` and redirects to `/home`336```js337reply.code(303).redirect('/home')338```339 340Example (`reply.code()` call) sets status code to `302` and redirects to `/home`341```js342reply.code(303).redirect('/home', 302)343```344 345### .callNotFound()346<a id="call-not-found"></a>347 348Invokes the custom not found handler. Note that it will only call `preHandler`349hook specified in [`setNotFoundHandler`](./Server.md#set-not-found-handler).350 351```js352reply.callNotFound()353```354 355### .type(contentType)356<a id="type"></a>357 358Sets the content type for the response. This is a shortcut for359`reply.header('Content-Type', 'the/type')`.360 361```js362reply.type('text/html')363```364If the `Content-Type` has a JSON subtype, and the charset parameter is not set,365`utf-8` will be used as the charset by default.366 367### .getSerializationFunction(schema | httpStatus, [contentType])368<a id="getserializationfunction"></a>369 370By calling this function using a provided `schema` or `httpStatus`,371and the optional `contentType`, it will return a `serialzation` function372that can be used to serialize diverse inputs. It returns `undefined` if no373serialization function was found using either of the provided inputs.374 375This heavily depends of the `schema#responses` attached to the route, or376the serialization functions compiled by using `compileSerializationSchema`.377 378```js379const serialize = reply380 .getSerializationFunction({381 type: 'object',382 properties: {383 foo: {384 type: 'string'385 }386 }387 })388serialize({ foo: 'bar' }) // '{"foo":"bar"}'389 390// or391 392const serialize = reply393 .getSerializationFunction(200)394serialize({ foo: 'bar' }) // '{"foo":"bar"}'395 396// or397 398const serialize = reply399 .getSerializationFunction(200, 'application/json')400serialize({ foo: 'bar' }) // '{"foo":"bar"}'401```402 403See [.compileSerializationSchema(schema, [httpStatus], [contentType])](#compileserializationschema)404for more information on how to compile serialization schemas.405 406### .compileSerializationSchema(schema, [httpStatus], [contentType])407<a id="compileserializationschema"></a>408 409This function will compile a serialization schema and410return a function that can be used to serialize data.411The function returned (a.k.a. _serialization function_) returned is compiled412by using the provided `SerializerCompiler`. Also this is cached by using413a `WeakMap` for reducing compilation calls.414 415The optional parameters `httpStatus` and `contentType`, if provided,416are forwarded directly to the `SerializerCompiler`, so it can be used417to compile the serialization function if a custom `SerializerCompiler` is used.418 419This heavily depends of the `schema#responses` attached to the route, or420the serialization functions compiled by using `compileSerializationSchema`.421 422```js423const serialize = reply424 .compileSerializationSchema({425 type: 'object',426 properties: {427 foo: {428 type: 'string'429 }430 }431 })432serialize({ foo: 'bar' }) // '{"foo":"bar"}'433 434// or435 436const serialize = reply437 .compileSerializationSchema({438 type: 'object',439 properties: {440 foo: {441 type: 'string'442 }443 }444 }, 200)445serialize({ foo: 'bar' }) // '{"foo":"bar"}'446 447// or448 449const serialize = reply450 .compileSerializationSchema({451 '3xx': {452 content: {453 'application/json': {454 schema: {455 name: { type: 'string' },456 phone: { type: 'number' }457 }458 }459 }460 }461 }, '3xx', 'application/json')462serialize({ name: 'Jone', phone: 201090909090 }) // '{"name":"Jone", "phone":201090909090}'463```464 465Note that you should be careful when using this function, as it will cache466the compiled serialization functions based on the schema provided. If the467schemas provided is mutated or changed, the serialization functions will not468detect that the schema has been altered and for instance it will reuse the469previously compiled serialization function based on the reference of the schema470previously provided.471 472If there's a need to change the properties of a schema, always opt to create473a totally new object, otherwise the implementation won't benefit from the cache474mechanism.475 476:Using the following schema as example:477```js478const schema1 = {479 type: 'object',480 properties: {481 foo: {482 type: 'string'483 }484 }485}486```487 488*Not*489```js490const serialize = reply.compileSerializationSchema(schema1)491 492// Later on...493schema1.properties.foo.type. = 'integer'494const newSerialize = reply.compileSerializationSchema(schema1)495 496console.log(newSerialize === serialize) // true497```498 499*Instead*500```js501const serialize = reply.compileSerializationSchema(schema1)502 503// Later on...504const newSchema = Object.assign({}, schema1)505newSchema.properties.foo.type = 'integer'506 507const newSerialize = reply.compileSerializationSchema(newSchema)508 509console.log(newSerialize === serialize) // false510```511 512### .serializeInput(data, [schema | httpStatus], [httpStatus], [contentType])513<a id="serializeinput"></a>514 515This function will serialize the input data based on the provided schema516or HTTP status code. If both are provided the `httpStatus` will take precedence.517 518If there is not a serialization function for a given `schema` a new serialization519function will be compiled, forwarding the `httpStatus` and `contentType` if provided.520 521```js522reply523 .serializeInput({ foo: 'bar'}, {524 type: 'object',525 properties: {526 foo: {527 type: 'string'528 }529 }530 }) // '{"foo":"bar"}'531 532// or533 534reply535 .serializeInput({ foo: 'bar'}, {536 type: 'object',537 properties: {538 foo: {539 type: 'string'540 }541 }542 }, 200) // '{"foo":"bar"}'543 544// or545 546reply547 .serializeInput({ foo: 'bar'}, 200) // '{"foo":"bar"}'548 549// or550 551reply552 .serializeInput({ name: 'Jone', age: 18 }, '200', 'application/vnd.v1+json') // '{"name": "Jone", "age": 18}'553```554 555See [.compileSerializationSchema(schema, [httpStatus], [contentType])](#compileserializationschema)556for more information on how to compile serialization schemas.557 558### .serializer(func)559<a id="serializer"></a>560 561By default, `.send()` will JSON-serialize any value that is not one of `Buffer`,562`stream`, `string`, `undefined`, or `Error`. If you need to replace the default563serializer with a custom serializer for a particular request, you can do so with564the `.serializer()` utility. Be aware that if you are using a custom serializer,565you must set a custom `'Content-Type'` header.566 567```js568reply569 .header('Content-Type', 'application/x-protobuf')570 .serializer(protoBuf.serialize)571```572 573Note that you don't need to use this utility inside a `handler` because Buffers,574streams, and strings (unless a serializer is set) are considered to already be575serialized.576 577```js578reply579 .header('Content-Type', 'application/x-protobuf')580 .send(protoBuf.serialize(data))581```582 583See [`.send()`](#send) for more information on sending different types of584values.585 586### .raw587<a id="raw"></a>588 589This is the590[`http.ServerResponse`](https://nodejs.org/dist/latest-v20.x/docs/api/http.html#http_class_http_serverresponse)591from Node core. Whilst you are using the Fastify `Reply` object, the use of592`Reply.raw` functions is at your own risk as you are skipping all the Fastify593logic of handling the HTTP response. e.g.:594 595```js596app.get('/cookie-2', (req, reply) => {597 reply.setCookie('session', 'value', { secure: false }) // this will not be used598 599 // in this case we are using only the nodejs http server response object600 reply.raw.writeHead(200, { 'Content-Type': 'text/plain' })601 reply.raw.write('ok')602 reply.raw.end()603})604```605Another example of the misuse of `Reply.raw` is explained in606[Reply](#getheaders).607 608### .sent609<a id="sent"></a>610 611As the name suggests, `.sent` is a property to indicate if a response has been612sent via `reply.send()`. It will also be `true` in case `reply.hijack()` was613used.614 615In case a route handler is defined as an async function or it returns a promise,616it is possible to call `reply.hijack()` to indicate that the automatic617invocation of `reply.send()` once the handler promise resolve should be skipped.618By calling `reply.hijack()`, an application claims full responsibility for the619low-level request and response. Moreover, hooks will not be invoked.620 621*Modifying the `.sent` property directly is deprecated. Please use the622aforementioned `.hijack()` method to achieve the same effect.*623 624### .hijack()625<a name="hijack"></a>626 627Sometimes you might need to halt the execution of the normal request lifecycle628and handle sending the response manually.629 630To achieve this, Fastify provides the `reply.hijack()` method that can be called631during the request lifecycle (At any point before `reply.send()` is called), and632allows you to prevent Fastify from sending the response, and from running the633remaining hooks (and user handler if the reply was hijacked before).634 635```js636app.get('/', (req, reply) => {637 reply.hijack()638 reply.raw.end('hello world')639 640 return Promise.resolve('this will be skipped')641})642```643 644If `reply.raw` is used to send a response back to the user, the `onResponse`645hooks will still be executed.646 647### .send(data)648<a id="send"></a>649 650As the name suggests, `.send()` is the function that sends the payload to the651end user.652 653#### Objects654<a id="send-object"></a>655 656As noted above, if you are sending JSON objects, `send` will serialize the657object with658[fast-json-stringify](https://www.npmjs.com/package/fast-json-stringify) if you659set an output schema, otherwise, `JSON.stringify()` will be used.660```js661fastify.get('/json', options, function (request, reply) {662 reply.send({ hello: 'world' })663})664```665 666#### Strings667<a id="send-string"></a>668 669If you pass a string to `send` without a `Content-Type`, it will be sent as670`text/plain; charset=utf-8`. If you set the `Content-Type` header and pass a671string to `send`, it will be serialized with the custom serializer if one is672set, otherwise, it will be sent unmodified (unless the `Content-Type` header is673set to `application/json; charset=utf-8`, in which case it will be674JSON-serialized like an object — see the section above).675```js676fastify.get('/json', options, function (request, reply) {677 reply.send('plain string')678})679```680 681#### Streams682<a id="send-streams"></a>683 684If you are sending a stream and you have not set a `'Content-Type'` header,685*send* will set it to `'application/octet-stream'`.686 687As noted above, streams are considered to be pre-serialized, so they will be688sent unmodified without response validation.689 690```js691const fs = require('node:fs')692 693fastify.get('/streams', function (request, reply) {694 const stream = fs.createReadStream('some-file', 'utf8')695 reply.header('Content-Type', 'application/octet-stream')696 reply.send(stream)697})698```699When using async-await you will need to return or await the reply object:700```js701const fs = require('node:fs')702 703fastify.get('/streams', async function (request, reply) {704 const stream = fs.createReadStream('some-file', 'utf8')705 reply.header('Content-Type', 'application/octet-stream')706 return reply.send(stream)707})708```709 710#### Buffers711<a id="send-buffers"></a>712 713If you are sending a buffer and you have not set a `'Content-Type'` header,714*send* will set it to `'application/octet-stream'`.715 716As noted above, Buffers are considered to be pre-serialized, so they will be717sent unmodified without response validation.718 719```js720const fs = require('node:fs')721 722fastify.get('/streams', function (request, reply) {723 fs.readFile('some-file', (err, fileBuffer) => {724 reply.send(err || fileBuffer)725 })726})727```728 729When using async-await you will need to return or await the reply object:730```js731const fs = require('node:fs')732 733fastify.get('/streams', async function (request, reply) {734 fs.readFile('some-file', (err, fileBuffer) => {735 reply.send(err || fileBuffer)736 })737 return reply738})739```740 741#### TypedArrays742<a id="send-typedarrays"></a>743 744`send` manages TypedArray like a Buffer, and sets the `'Content-Type'`745header to `'application/octet-stream'` if not already set.746 747As noted above, TypedArray/Buffers are considered to be pre-serialized, so they748will be sent unmodified without response validation.749 750```js751const fs = require('node:fs')752 753fastify.get('/streams', function (request, reply) {754 const typedArray = new Uint16Array(10)755 reply.send(typedArray)756})757```758 759#### ReadableStream760<a id="send-readablestream"></a>761 762`ReadableStream` will be treated as a node stream mentioned above,763the content is considered to be pre-serialized, so they will be764sent unmodified without response validation.765 766```js767const fs = require('node:fs')768const { ReadableStream } = require('node:stream/web')769 770fastify.get('/streams', function (request, reply) {771 const stream = fs.createReadStream('some-file')772 reply.header('Content-Type', 'application/octet-stream')773 reply.send(ReadableStream.from(stream))774})775```776 777#### Response778<a id="send-response"></a>779 780`Response` allows to manage the reply payload, status code and781headers in one place. The payload provided inside `Response` is782considered to be pre-serialized, so they will be sent unmodified783without response validation.784 785Please be aware when using `Response`, the status code and headers786will not directly reflect to `reply.statusCode` and `reply.getHeaders()`.787Such behavior is based on `Response` only allow `readonly` status788code and headers. The data is not allow to be bi-direction editing,789and may confuse when checking the `payload` in `onSend` hooks.790 791```js792const fs = require('node:fs')793const { ReadableStream } = require('node:stream/web')794 795fastify.get('/streams', function (request, reply) {796 const stream = fs.createReadStream('some-file')797 const readableStream = ReadableStream.from(stream)798 const response = new Response(readableStream, {799 status: 200,800 headers: { 'content-type': 'application/octet-stream' }801 })802 reply.send(response)803})804```805 806 807#### Errors808<a id="errors"></a>809 810If you pass to *send* an object that is an instance of *Error*, Fastify will811automatically create an error structured as the following:812 813```js814{815 error: String // the HTTP error message816 code: String // the Fastify error code817 message: String // the user error message818 statusCode: Number // the HTTP status code819}820```821 822You can add custom properties to the Error object, such as `headers`, that will823be used to enhance the HTTP response.824 825*Note: If you are passing an error to `send` and the statusCode is less than826400, Fastify will automatically set it at 500.*827 828Tip: you can simplify errors by using the829[`http-errors`](https://npm.im/http-errors) module or830[`@fastify/sensible`](https://github.com/fastify/fastify-sensible) plugin to831generate errors:832 833```js834fastify.get('/', function (request, reply) {835 reply.send(httpErrors.Gone())836})837```838 839To customize the JSON error output you can do it by:840 841- setting a response JSON schema for the status code you need842- add the additional properties to the `Error` instance843 844Notice that if the returned status code is not in the response schema list, the845default behavior will be applied.846 847```js848fastify.get('/', {849 schema: {850 response: {851 501: {852 type: 'object',853 properties: {854 statusCode: { type: 'number' },855 code: { type: 'string' },856 error: { type: 'string' },857 message: { type: 'string' },858 time: { type: 'string' }859 }860 }861 }862 }863}, function (request, reply) {864 const error = new Error('This endpoint has not been implemented')865 error.time = 'it will be implemented in two weeks'866 reply.code(501).send(error)867})868```869 870If you want to customize error handling, check out871[`setErrorHandler`](./Server.md#seterrorhandler) API.872 873*Note: you are responsible for logging when customizing the error handler*874 875API:876 877```js878fastify.setErrorHandler(function (error, request, reply) {879 request.log.warn(error)880 const statusCode = error.statusCode >= 400 ? error.statusCode : 500881 reply882 .code(statusCode)883 .type('text/plain')884 .send(statusCode >= 500 ? 'Internal server error' : error.message)885})886```887 888Beware that calling `reply.send(error)` in your custom error handler will send889the error to the default error handler.890Check out the [Reply Lifecycle](./Lifecycle.md#reply-lifecycle)891for more information.892 893The not found errors generated by the router will use the894[`setNotFoundHandler`](./Server.md#setnotfoundhandler)895 896API:897 898```js899fastify.setNotFoundHandler(function (request, reply) {900 reply901 .code(404)902 .type('text/plain')903 .send('a custom not found')904})905```906 907#### Type of the final payload908<a id="payload-type"></a>909 910The type of the sent payload (after serialization and going through any911[`onSend` hooks](./Hooks.md#onsend)) must be one of the following types,912otherwise, an error will be thrown:913 914- `string`915- `Buffer`916- `stream`917- `undefined`918- `null`919 920#### Async-Await and Promises921<a id="async-await-promise"></a>922 923Fastify natively handles promises and supports async-await.924 925*Note that in the following examples we are not using reply.send.*926```js927const { promisify } = require('node:util')928const delay = promisify(setTimeout)929 930fastify.get('/promises', options, function (request, reply) {931 return delay(200).then(() => { return { hello: 'world' }})932})933 934fastify.get('/async-await', options, async function (request, reply) {935 await delay(200)936 return { hello: 'world' }937})938```939 940Rejected promises default to a `500` HTTP status code. Reject the promise, or941`throw` in an `async function`, with an object that has `statusCode` (or942`status`) and `message` properties to modify the reply.943 944```js945fastify.get('/teapot', async function (request, reply) {946 const err = new Error()947 err.statusCode = 418948 err.message = 'short and stout'949 throw err950})951 952fastify.get('/botnet', async function (request, reply) {953 throw { statusCode: 418, message: 'short and stout' }954 // will return to the client the same json955})956```957 958If you want to know more please review959[Routes#async-await](./Routes.md#async-await).960 961### .then(fulfilled, rejected)962<a id="then"></a>963 964As the name suggests, a `Reply` object can be awaited upon, i.e. `await reply`965will wait until the reply is sent. The `await` syntax calls the `reply.then()`.966 967`reply.then(fulfilled, rejected)` accepts two parameters:968 969- `fulfilled` will be called when a response has been fully sent,970- `rejected` will be called if the underlying stream had an error, e.g. the971 socket has been destroyed.972 973For more details, see:974 975- https://github.com/fastify/fastify/issues/1864 for the discussion about this976 feature977- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then978 for the signature979 