Comparing version 4.1.0 to 4.2.0
@@ -51,3 +51,3 @@ <h1 align="center">Fastify</h1> | ||
1. the mechanism for authenticating with the provider | ||
[decorating](../Referece/Decorators.md) the `fastify` object with the | ||
[decorating](../Reference/Decorators.md) the `fastify` object with the | ||
authentication key (`magicKey` from here onwards) | ||
@@ -54,0 +54,0 @@ 1. the mechanism for denying requests that would, otherwise, fail |
@@ -135,5 +135,11 @@ <h1 align="center">Fastify</h1> | ||
close the server gracefully on `SIGINT` and `SIGTERM` signals. | ||
- [`@eropple/fastify-openapi3`](https://github.com/eropple/fastify-openapi3) Provides | ||
easy, developer-friendly OpenAPI 3.1 specs + doc explorer based on your routes. | ||
- [`@gquittet/graceful-server`](https://github.com/gquittet/graceful-server) | ||
Tiny (~5k), Fast, KISS, and dependency-free Node.JS library to make your | ||
Fastify API graceful. | ||
- [`@h4ad/serverless-adapter`](https://github.com/H4ad/serverless-adapter) | ||
Run REST APIs and other web applications using your existing Node.js | ||
application framework (Express, Koa, Hapi and Fastify), on top of AWS Lambda, | ||
Huawei and many other clouds. | ||
- [`@immobiliarelabs/fastify-metrics`](https://github.com/immobiliare/fastify-metrics) | ||
@@ -331,2 +337,4 @@ Minimalistic and opinionated plugin that collects usage/process metrics and | ||
Fastify plugin to parse request language. | ||
- [`fastify-lcache`](https://github.com/denbon05/fastify-lcache) | ||
Lightweight cache plugin | ||
- [`fastify-loader`](https://github.com/TheNoim/fastify-loader) Load routes from | ||
@@ -483,2 +491,4 @@ a directory and inject the Fastify instance in each file. | ||
Server-Sent Events using Async Iterators (supports newer versions of Fastify). | ||
- [`fastify-ssr-vite`](https://github.com/nineohnine/fastify-ssr-vite) A simple | ||
plugin for setting up server side rendering with vite. | ||
- [`fastify-stripe`](https://github.com/coopflow/fastify-stripe) Plugin to | ||
@@ -485,0 +495,0 @@ initialize and encapsulate [Stripe |
@@ -11,4 +11,36 @@ # V4 Migration Guide | ||
### Deprecation of `app.use()` | ||
### Error handling composition ([#3261](https://github.com/fastify/fastify/pull/3261)) | ||
When an error is thrown in a async error handler function, | ||
the upper-level error handler is executed if set. | ||
If there is not a upper-level error handler, the default will | ||
be executed as it was previously. | ||
``` | ||
import Fastify from 'fastify' | ||
const fastify = Fastify() | ||
fastify.register(async fastify => { | ||
fastify.setErrorHandler(async err => { | ||
console.log(err.message) // 'kaboom' | ||
throw new Error('caught') | ||
}) | ||
fastify.get('/encapsulated', async () => { | ||
throw new Error('kaboom') | ||
}) | ||
}) | ||
fastify.setErrorHandler(async err => { | ||
console.log(err.message) // 'caught' | ||
throw new Error('wrapped') | ||
}) | ||
const res = await fastify.inject('/encapsulated') | ||
console.log(res.json().message) // 'wrapped' | ||
``` | ||
### Deprecation of `app.use()` ([#3506](https://github.com/fastify/fastify/pull/3506)) | ||
Starting this version of Fastify, we have deprecated the use of `app.use()`. We | ||
@@ -74,1 +106,8 @@ have decided not to support the use of middlewares. Both | ||
``` | ||
### Add `reply.trailers` methods ([#3794](https://github.com/fastify/fastify/pull/3794)) | ||
Fastify now supports the [HTTP Trailer] response headers. | ||
[HTTP Trailer]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Trailer |
@@ -27,3 +27,3 @@ <h1 align="center">Serverless</h1> | ||
- [AWS Lambda](#aws-lambda) | ||
- [AWS](#aws) | ||
- [Google Cloud Functions](#google-cloud-functions) | ||
@@ -34,4 +34,16 @@ - [Google Cloud Run](#google-cloud-run) | ||
## AWS Lambda | ||
## AWS | ||
To integrate with AWS, you have two choices of library: | ||
- Using [@fastify/aws-lambda](https://github.com/fastify/aws-lambda-fastify) | ||
which only adds API Gateway support but has heavy optimizations for fastify. | ||
- Using [@h4ad/serverless-adapter](https://github.com/H4ad/serverless-adapter) | ||
which is a little slower as it creates an HTTP request for each AWS event but | ||
has support for more AWS services such as: AWS SQS, AWS SNS and others. | ||
So you can decide which option is best for you, but you can test both libraries. | ||
### Using @fastify/aws-lambda | ||
The sample provided allows you to easily build serverless web | ||
@@ -41,8 +53,4 @@ applications/services and RESTful APIs using Fastify on top of AWS Lambda and | ||
*Note: Using | ||
[@fastify/aws-lambda](https://github.com/fastify/aws-lambda-fastify) is just one | ||
possible way.* | ||
#### app.js | ||
### app.js | ||
```js | ||
@@ -77,3 +85,3 @@ const fastify = require('fastify'); | ||
### lambda.js | ||
#### lambda.js | ||
@@ -106,3 +114,3 @@ ```js | ||
### Example | ||
#### Example | ||
@@ -114,3 +122,2 @@ An example deployable with | ||
### Considerations | ||
@@ -123,2 +130,8 @@ | ||
#### Beyond API Gateway | ||
If you need to integrate with more AWS services, take a look at | ||
[@h4ad/serverless-adapter](https://viniciusl.com.br/serverless-adapter/docs/main/frameworks/fastify) | ||
on Fastify to find out how to integrate. | ||
## Google Cloud Functions | ||
@@ -125,0 +138,0 @@ |
@@ -19,3 +19,3 @@ <h1 align="center">Fastify</h1> | ||
Developers experienced with Fastify should consult the [reference | ||
documentation](./Reference/index.md) directly to find the topic they are seeking | ||
documentation](./Reference/Index.md) directly to find the topic they are seeking | ||
more information about. | ||
@@ -22,0 +22,0 @@ |
@@ -31,2 +31,3 @@ <h1 align="center">Fastify</h1> | ||
- [Route level hooks](#route-level-hooks) | ||
- [Using Hooks to Inject Custom Properties](#using-hooks-to-inject-custom-properties) | ||
- [Diagnostics Channel Hooks](#diagnostics-channel-hooks) | ||
@@ -653,2 +654,53 @@ | ||
## Using Hooks to Inject Custom Properties | ||
<a id="using-hooks-to-inject-custom-properties"></a> | ||
You can use a hook to inject custom properties into incoming requests. | ||
This is useful for reusing processed data from hooks in controllers. | ||
A very common use case is, for example, checking user authentication based | ||
on their token and then storing their recovered data into | ||
the [Request](./Request.md) instance. This way, your controllers can read it | ||
easily with `request.authenticatedUser` or whatever you want to call it. | ||
That's how it might look like: | ||
```js | ||
fastify.addHook('preParsing', async (request) => { | ||
request.authenticatedUser = { | ||
id: 42, | ||
name: 'Jane Doe', | ||
role: 'admin' | ||
} | ||
}) | ||
fastify.get('/me/is-admin', async function (req, reply) { | ||
return { isAdmin: req.authenticatedUser?.role === 'admin' || false } | ||
}) | ||
``` | ||
Note that `.authenticatedUser` could actually be any property name | ||
choosen by yourself. Using your own custom property prevents you | ||
from mutating existing properties, which | ||
would be a dangerous and destructive operation. So be careful and | ||
make sure your property is entirely new, also using this approach | ||
only for very specific and small cases like this example. | ||
Regarding TypeScript in this example, you'd need to update the | ||
`FastifyRequest` core interface to include your new property typing | ||
(for more about it, see [TypeScript](./TypeScript.md) page), like: | ||
```ts | ||
interface AuthenticatedUser { /* ... */ } | ||
declare module 'fastify' { | ||
export interface FastifyRequest { | ||
authenticatedUser?: AuthenticatedUser; | ||
} | ||
} | ||
``` | ||
Although this is a very pragmatic approach, if you're trying to do | ||
something more complex that changes these core objects, then | ||
consider creating a custom [Plugin](./Plugins.md) instead. | ||
## Diagnostics Channel Hooks | ||
@@ -655,0 +707,0 @@ |
@@ -16,3 +16,3 @@ <h1 align="center">Fastify</h1> | ||
You may have already seen in the [Getting | ||
Started]((../Guides/Getting-Started.md#your-first-plugin)) guide how easy it is | ||
Started](../Guides/Getting-Started.md#your-first-plugin) guide how easy it is | ||
to use this API: | ||
@@ -19,0 +19,0 @@ ``` |
@@ -202,5 +202,6 @@ <h1 align="center">Fastify</h1> | ||
A useful library for building types and a schema at once is | ||
[typebox](https://www.npmjs.com/package/@sinclair/typebox). With typebox you | ||
define your schema within your code and use them directly as types or schemas as | ||
you need them. | ||
[typebox](https://www.npmjs.com/package/@sinclair/typebox) along with | ||
[fastify-type-provider-typebox](https://github.com/fastify/fastify-type-provider-typebox). | ||
With typebox you define your schema within your code and use them | ||
directly as types or schemas as you need them. | ||
@@ -210,6 +211,6 @@ When you want to use it for validation of some payload in a fastify route you | ||
1. Install `typebox` in your project. | ||
1. Install `typebox` and `fastify-type-provider-typebox` in your project. | ||
```bash | ||
npm i @sinclair/typebox | ||
npm i @sinclair/typebox @fastify/type-provider-typebox | ||
``` | ||
@@ -223,7 +224,8 @@ | ||
const User = Type.Object({ | ||
export const User = Type.Object({ | ||
name: Type.String(), | ||
mail: Type.Optional(Type.String({ format: "email" })), | ||
}); | ||
type UserType = Static<typeof User>; | ||
mail: Type.Optional(Type.String({ format: 'email' })), | ||
}) | ||
export type UserType = Static<typeof User> | ||
``` | ||
@@ -234,6 +236,10 @@ | ||
```typescript | ||
const app = fastify(); | ||
import Fastify from 'fastify' | ||
import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox' | ||
// ... | ||
app.post<{ Body: UserType; Reply: UserType }>( | ||
"/", | ||
const fastify = Fastify().withTypeProvider<TypeBoxTypeProvider>() | ||
app.post<{ Body: UserType, Reply: UserType }>( | ||
'/', | ||
{ | ||
@@ -243,3 +249,3 @@ schema: { | ||
response: { | ||
200: User, | ||
200: User | ||
}, | ||
@@ -249,15 +255,22 @@ }, | ||
(request, reply) => { | ||
const { body: user } = request; | ||
/* user has type | ||
* const user: StaticProperties<{ | ||
* name: TString; | ||
* mail: TOptional<TString>; | ||
* }> | ||
*/ | ||
//... | ||
reply.status(200).send(user); | ||
// The `name` and `mail` types are automatically inferred | ||
const { name, mail } = request.body; | ||
reply.status(200).send({ name, mail }); | ||
} | ||
); | ||
) | ||
``` | ||
**Note** For Ajv version 7 and above is required to use the `ajvTypeBoxPlugin`: | ||
```typescript | ||
import Fastify from 'fastify' | ||
import { ajvTypeBoxPlugin, TypeBoxTypeProvider } from '@fastify/type-provider-typebox' | ||
const fastify = Fastify({ | ||
ajv: { | ||
plugins: [ajvTypeBoxPlugin] | ||
} | ||
}).withTypeProvider<TypeBoxTypeProvider>() | ||
``` | ||
#### Schemas in JSON Files | ||
@@ -1368,3 +1381,3 @@ | ||
[src](https://github.com/fastify/fastify/blob/main/types/error.d.ts#L17) | ||
[src](https://github.com/fastify/fastify/blob/main/fastify.d.ts#L179) | ||
@@ -1379,3 +1392,3 @@ FastifyError is a custom error object that includes status code and validation | ||
[src](https://github.com/fastify/fastify/blob/main/types/error.d.ts#L4) | ||
[src](https://github.com/fastify/fastify/blob/main/fastify.d.ts#L184) | ||
@@ -1382,0 +1395,0 @@ The route validation internally relies upon Ajv, which is a high-performance |
@@ -487,3 +487,14 @@ <h1 align="center">Fastify</h1> | ||
##### .statusCode property | ||
All validation errors will be added a `.statusCode` property set to `400`. This guarantees | ||
that the default error handler will set the status code of the response to `400`. | ||
```js | ||
fastify.setErrorHandler(function (error, request, reply) { | ||
request.log.error(error, `This error has status code ${error.statusCode}`) | ||
reply.status(error.statusCode).send(error) | ||
}) | ||
``` | ||
##### Validation messages with other validation libraries | ||
@@ -490,0 +501,0 @@ |
@@ -186,6 +186,6 @@ import * as http from 'http' | ||
keyword: string; | ||
dataPath: string; | ||
instancePath: string; | ||
schemaPath: string; | ||
params: Record<string, string | string[]>; | ||
message: string; | ||
message?: string; | ||
} | ||
@@ -192,0 +192,0 @@ |
'use strict' | ||
const VERSION = '4.1.0' | ||
const VERSION = '4.2.0' | ||
@@ -5,0 +5,0 @@ const Avvio = require('avvio') |
@@ -12,3 +12,4 @@ 'use strict' | ||
kLogLevel, | ||
kContentTypeParser | ||
kContentTypeParser, | ||
kRouteByFastify | ||
} = require('./symbols.js') | ||
@@ -29,3 +30,4 @@ | ||
schemaErrorFormatter, | ||
server | ||
server, | ||
isFastify | ||
}) { | ||
@@ -55,2 +57,3 @@ this.schema = schema | ||
this.schemaErrorFormatter = schemaErrorFormatter || server[kSchemaErrorFormatter] || defaultSchemaErrorFormatter | ||
this[kRouteByFastify] = isFastify | ||
@@ -57,0 +60,0 @@ this.server = server |
@@ -42,3 +42,3 @@ // This file is autogenerated by build/build-error-serializer.js, do not edit | ||
const integer = this.parseInteger(i) | ||
if (Number.isNaN(integer)) { | ||
if (Number.isNaN(integer) || !Number.isFinite(integer)) { | ||
throw new Error(`The value "${i}" cannot be converted to an integer.`) | ||
@@ -59,2 +59,4 @@ } else { | ||
throw new Error(`The value "${i}" cannot be converted to a number.`) | ||
} else if (!Number.isFinite(num)) { | ||
return null | ||
} else { | ||
@@ -77,40 +79,40 @@ return '' + num | ||
asDatetime (date, skipQuotes) { | ||
const quotes = skipQuotes === true ? '' : '"' | ||
asDatetime (date) { | ||
const quotes = '"' | ||
if (date instanceof Date) { | ||
return quotes + date.toISOString() + quotes | ||
} | ||
return this.asString(date, skipQuotes) | ||
return this.asString(date) | ||
} | ||
asDatetimeNullable (date, skipQuotes) { | ||
return date === null ? 'null' : this.asDatetime(date, skipQuotes) | ||
asDatetimeNullable (date) { | ||
return date === null ? 'null' : this.asDatetime(date) | ||
} | ||
asDate (date, skipQuotes) { | ||
const quotes = skipQuotes === true ? '' : '"' | ||
asDate (date) { | ||
const quotes = '"' | ||
if (date instanceof Date) { | ||
return quotes + new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toISOString().slice(0, 10) + quotes | ||
} | ||
return this.asString(date, skipQuotes) | ||
return this.asString(date) | ||
} | ||
asDateNullable (date, skipQuotes) { | ||
return date === null ? 'null' : this.asDate(date, skipQuotes) | ||
asDateNullable (date) { | ||
return date === null ? 'null' : this.asDate(date) | ||
} | ||
asTime (date, skipQuotes) { | ||
const quotes = skipQuotes === true ? '' : '"' | ||
asTime (date) { | ||
const quotes = '"' | ||
if (date instanceof Date) { | ||
return quotes + new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toISOString().slice(11, 19) + quotes | ||
} | ||
return this.asString(date, skipQuotes) | ||
return this.asString(date) | ||
} | ||
asTimeNullable (date, skipQuotes) { | ||
return date === null ? 'null' : this.asTime(date, skipQuotes) | ||
asTimeNullable (date) { | ||
return date === null ? 'null' : this.asTime(date) | ||
} | ||
asString (str, skipQuotes) { | ||
const quotes = skipQuotes === true ? '' : '"' | ||
asString (str) { | ||
const quotes = '"' | ||
if (str instanceof Date) { | ||
@@ -125,7 +127,2 @@ return quotes + str.toISOString() + quotes | ||
} | ||
// If we skipQuotes it means that we are using it as test | ||
// no need to test the string length for the render | ||
if (skipQuotes) { | ||
return str | ||
} | ||
@@ -192,3 +189,3 @@ if (str.length < 42) { | ||
function anonymous0 (input) { | ||
// main | ||
// # | ||
@@ -195,0 +192,0 @@ var obj = (input && typeof input.toJSON === 'function') |
@@ -93,3 +93,3 @@ 'use strict' | ||
if (reply.context.attachValidation === false) { | ||
reply.code(400).send(result) | ||
reply.send(result) | ||
return | ||
@@ -96,0 +96,0 @@ } |
@@ -11,3 +11,3 @@ 'use strict' | ||
const warning = require('./warnings') | ||
const { kRequestAcceptVersion } = require('./symbols') | ||
const { kRequestAcceptVersion, kRouteByFastify } = require('./symbols') | ||
@@ -117,3 +117,3 @@ const { | ||
// Convert shorthand to extended route declaration | ||
function prepareRoute ({ method, url, options, handler }) { | ||
function prepareRoute ({ method, url, options, handler, isFastify }) { | ||
if (typeof url !== 'string') { | ||
@@ -145,7 +145,7 @@ throw new FST_ERR_INVALID_URL(typeof url) | ||
return route.call(this, { options }) | ||
return route.call(this, { options, isFastify }) | ||
} | ||
// Route management | ||
function route ({ options }) { | ||
function route ({ options, isFastify }) { | ||
// Since we are mutating/assigning only top level props, it is fine to have a shallow copy using the spread operator | ||
@@ -182,13 +182,13 @@ const opts = { ...options } | ||
case 'slash': | ||
addNewRoute.call(this, { path }) | ||
addNewRoute.call(this, { path, isFastify }) | ||
break | ||
case 'no-slash': | ||
addNewRoute.call(this, { path: '' }) | ||
addNewRoute.call(this, { path: '', isFastify }) | ||
break | ||
case 'both': | ||
default: | ||
addNewRoute.call(this, { path: '' }) | ||
addNewRoute.call(this, { path: '', isFastify }) | ||
// If ignoreTrailingSlash is set to true we need to add only the '' route to prevent adding an incomplete one. | ||
if (ignoreTrailingSlash !== true && (ignoreDuplicateSlashes !== true || !prefix.endsWith('/'))) { | ||
addNewRoute.call(this, { path, prefixing: true }) | ||
addNewRoute.call(this, { path, prefixing: true, isFastify }) | ||
} | ||
@@ -198,5 +198,5 @@ } | ||
// Ensure that '/prefix/' + '/route' gets registered as '/prefix/route' | ||
addNewRoute.call(this, { path: path.slice(1) }) | ||
addNewRoute.call(this, { path: path.slice(1), isFastify }) | ||
} else { | ||
addNewRoute.call(this, { path }) | ||
addNewRoute.call(this, { path, isFastify }) | ||
} | ||
@@ -207,3 +207,3 @@ | ||
function addNewRoute ({ path, prefixing = false }) { | ||
function addNewRoute ({ path, prefixing = false, isFastify = false }) { | ||
const url = prefix + path | ||
@@ -250,3 +250,4 @@ | ||
replySerializer: this[kReplySerializerDefault], | ||
server: this | ||
server: this, | ||
isFastify | ||
}) | ||
@@ -259,9 +260,16 @@ | ||
const headRouteExists = opts.method === 'HEAD' && router.find(opts.method, opts.url, constraints) != null | ||
const headHandler = router.find('HEAD', opts.url, constraints) | ||
const hasHEADHandler = headHandler != null | ||
// Check if the current route is not for a sibling HEAD one | ||
if (!headRouteExists) { | ||
try { | ||
router.on(opts.method, opts.url, { constraints }, routeHandler, context) | ||
} catch (error) { | ||
// remove the head route created by fastify | ||
if (hasHEADHandler && !context[kRouteByFastify] && headHandler.store[kRouteByFastify]) { | ||
router.off(opts.method, opts.url, { constraints }) | ||
} | ||
try { | ||
router.on(opts.method, opts.url, { constraints }, routeHandler, context) | ||
} catch (error) { | ||
// any route insertion error created by fastify can be safely ignore | ||
// because it only duplicate route for head | ||
if (!context[kRouteByFastify]) { | ||
const isDuplicatedRoute = error.message.includes(`Method '${opts.method}' already declared for route '${opts.url}'`) | ||
@@ -331,15 +339,17 @@ if (isDuplicatedRoute) { | ||
const { exposeHeadRoute } = opts | ||
const hasRouteExposeHeadRouteFlag = exposeHeadRoute != null | ||
const shouldExposeHead = hasRouteExposeHeadRouteFlag ? exposeHeadRoute : globalExposeHeadRoutes | ||
done(notHandledErr) | ||
}) | ||
if (shouldExposeHead && options.method === 'GET' && !headRouteExists) { | ||
const onSendHandlers = parseHeadOnSendHandlers(opts.onSend) | ||
prepareRoute.call(this, { method: 'HEAD', url: path, options: { ...opts, onSend: onSendHandlers } }) | ||
} else if (headRouteExists && exposeHeadRoute) { | ||
warning.emit('FSTDEP007') | ||
} | ||
// register head route in sync | ||
// we must place it after the `this.after` | ||
const { exposeHeadRoute } = opts | ||
const hasRouteExposeHeadRouteFlag = exposeHeadRoute != null | ||
const shouldExposeHead = hasRouteExposeHeadRouteFlag ? exposeHeadRoute : globalExposeHeadRoutes | ||
done(notHandledErr) | ||
}) | ||
if (shouldExposeHead && options.method === 'GET' && !hasHEADHandler) { | ||
const onSendHandlers = parseHeadOnSendHandlers(opts.onSend) | ||
prepareRoute.call(this, { method: 'HEAD', url: path, options: { ...opts, onSend: onSendHandlers }, isFastify: true }) | ||
} else if (hasHEADHandler && exposeHeadRoute) { | ||
warning.emit('FSTDEP007') | ||
} | ||
} | ||
@@ -346,0 +356,0 @@ } |
@@ -50,5 +50,6 @@ 'use strict' | ||
kHasBeenDecorated: Symbol('fastify.hasBeenDecorated'), | ||
kKeepAliveConnections: Symbol('fastify.keepAliveConnections') | ||
kKeepAliveConnections: Symbol('fastify.keepAliveConnections'), | ||
kRouteByFastify: Symbol('fastify.routeByFastify') | ||
} | ||
module.exports = keys |
@@ -109,2 +109,3 @@ 'use strict' | ||
if (result instanceof Error) { | ||
result.statusCode = result.statusCode || 400 | ||
result.validationContext = result.validationContext || dataVar | ||
@@ -115,2 +116,3 @@ return result | ||
const error = schemaErrorFormatter(result, dataVar) | ||
error.statusCode = error.statusCode || 400 | ||
error.validation = result | ||
@@ -117,0 +119,0 @@ error.validationContext = dataVar |
{ | ||
"name": "fastify", | ||
"version": "4.1.0", | ||
"version": "4.2.0", | ||
"description": "Fast and low overhead web framework, for Node.js", | ||
@@ -149,3 +149,3 @@ "main": "fastify.js", | ||
"fast-json-body": "^1.1.0", | ||
"fast-json-stringify": "^4.2.0", | ||
"fast-json-stringify": "^5.0.0", | ||
"fastify-plugin": "^3.0.1", | ||
@@ -183,6 +183,6 @@ "fluent-json-schema": "^3.1.0", | ||
"@fastify/error": "^3.0.0", | ||
"@fastify/fast-json-stringify-compiler": "^3.0.1", | ||
"@fastify/fast-json-stringify-compiler": "^4.0.0", | ||
"abstract-logging": "^2.0.1", | ||
"avvio": "^8.1.3", | ||
"find-my-way": "^6.3.0", | ||
"find-my-way": "^7.0.0", | ||
"light-my-request": "^5.0.0", | ||
@@ -189,0 +189,0 @@ "pino": "^8.0.0", |
@@ -147,3 +147,3 @@ 'use strict' | ||
├── helicopter (GET, HEAD) | ||
└── hello (GET, PUT, HEAD) | ||
└── hello (GET, HEAD, PUT) | ||
` | ||
@@ -204,3 +204,3 @@ t.equal(typeof radixTree, 'string') | ||
│ • (errorHandler) "defaultErrorHandler()" | ||
└── hello (GET, PUT, HEAD) | ||
└── hello (GET, HEAD, PUT) | ||
• (onTimeout) ["onTimeout()"] | ||
@@ -215,3 +215,3 @@ • (onRequest) ["anonymous()"] | ||
│ • (onRequest) ["anonymous()"] | ||
└── hello (GET, PUT, HEAD) | ||
└── hello (GET, HEAD, PUT) | ||
• (onTimeout) ["onTimeout()"] | ||
@@ -218,0 +218,0 @@ • (onRequest) ["anonymous()"] |
@@ -327,3 +327,3 @@ 'use strict' | ||
t.ok(Array.isArray(err.validation)) | ||
reply.send('error') | ||
reply.code(400).send('error') | ||
}) | ||
@@ -330,0 +330,0 @@ |
@@ -209,3 +209,3 @@ 'use strict' | ||
t.equal(err.code, 'FST_ERR_SCH_SERIALIZATION_BUILD') | ||
t.match(err.message, /^Failed building the serialization schema for GET: \/:id, due to error Cannot read propert.*/) // error from fast-json-strinfigy | ||
t.match(err.message, /^Failed building the serialization schema for GET: \/:id, due to error Cannot find reference.*/) // error from fast-json-strinfigy | ||
}) | ||
@@ -830,3 +830,3 @@ }) | ||
t.equal(err.validationContext, 'body') | ||
reply.send() | ||
reply.code(400).send() | ||
}) | ||
@@ -833,0 +833,0 @@ fastify.post('/', { |
@@ -10,4 +10,6 @@ import fastify, { | ||
LightMyRequestCallback, | ||
InjectOptions, FastifyBaseLogger | ||
InjectOptions, FastifyBaseLogger, | ||
ValidationResult | ||
} from '../../fastify' | ||
import { ErrorObject as AjvErrorObject } from 'ajv' | ||
import * as http from 'http' | ||
@@ -212,1 +214,10 @@ import * as https from 'https' | ||
expectAssignable<FastifyPlugin>(() => {}) | ||
const ajvErrorObject: AjvErrorObject = { | ||
keyword: '', | ||
instancePath: '', | ||
schemaPath: '', | ||
params: {}, | ||
message: '' | ||
} | ||
expectAssignable<ValidationResult>(ajvErrorObject) |
@@ -52,3 +52,3 @@ import { expectType } from 'tsd' | ||
type CustomRequest = FastifyRequest<{ | ||
Body: RequestBody; | ||
Body: RequestBody | undefined; | ||
Querystring: RequestQuerystring; | ||
@@ -89,3 +89,3 @@ Params: RequestParams; | ||
const getHandlerWithCustomLogger: RouteHandlerMethod<RawServerDefault, RawRequestDefaultExpression, RawReplyDefaultExpression, RouteGenericInterface, ContextConfigDefault, FastifySchema, FastifyTypeProviderDefault, ResolveFastifyReplyReturnType<FastifyTypeProviderDefault, FastifySchema, RouteGenericInterface>, ResolveFastifyRequestType<FastifyTypeProviderDefault, FastifySchema, RouteGenericInterface>, CustomLoggerInterface> = function (request, _reply) { | ||
const getHandlerWithCustomLogger: RouteHandlerMethod<RawServerDefault, RawRequestDefaultExpression, RawReplyDefaultExpression, RouteGenericInterface, ContextConfigDefault, FastifySchema, FastifyTypeProviderDefault, ResolveFastifyRequestType<FastifyTypeProviderDefault, FastifySchema, RouteGenericInterface>, CustomLoggerInterface> = function (request, _reply) { | ||
expectType<CustomLoggerInterface>(request.log) | ||
@@ -109,7 +109,11 @@ } | ||
function putHandler (request: CustomRequest, reply: FastifyReply) { | ||
expectType<RequestBody>(request.body) | ||
expectType<RequestBody | undefined>(request.body) | ||
expectType<RequestParams>(request.params) | ||
expectType<RequestHeaders & RawRequestDefaultExpression['headers']>(request.headers) | ||
expectType<RequestQuerystring>(request.query) | ||
expectType<string>(request.body.content) | ||
if (typeof request.body === 'undefined') { | ||
expectType<undefined>(request.body) | ||
} else { | ||
expectType<string>(request.body.content) | ||
} | ||
expectType<string>(request.query.from) | ||
@@ -116,0 +120,0 @@ expectType<number>(request.params.id) |
@@ -301,3 +301,3 @@ import fastify, { | ||
}, | ||
async (_, res): Promise<RouteHandlerMethod<RawServerDefault, RawRequestDefaultExpression, RawReplyDefaultExpression, RouteGenericInterface, ContextConfigDefault, FastifySchema, TypeBoxProvider>> => { | ||
async (_, res) => { | ||
return false | ||
@@ -388,3 +388,3 @@ } | ||
}, | ||
async (_, res): Promise<RouteHandlerMethod<RawServerDefault, RawRequestDefaultExpression, RawReplyDefaultExpression, RouteGenericInterface, ContextConfigDefault, FastifySchema, TypeBoxProvider>> => { | ||
async (_, res) => { | ||
return false | ||
@@ -394,2 +394,11 @@ } | ||
// https://github.com/fastify/fastify/issues/4088 | ||
expectError(server.withTypeProvider<JsonSchemaToTsProvider>().get('/', { | ||
schema: { | ||
response: { type: 'string' } | ||
} as const | ||
}, (_, res) => { | ||
return { foo: 555 } | ||
})) | ||
// ------------------------------------------------------------------- | ||
@@ -396,0 +405,0 @@ // Reply Type Override |
@@ -100,2 +100,34 @@ 'use strict' | ||
test('validation error has 400 statusCode set', t => { | ||
t.plan(3) | ||
const fastify = Fastify() | ||
fastify.setErrorHandler((error, request, reply) => { | ||
const errorResponse = { | ||
message: error.message, | ||
statusCode: error.statusCode || 500 | ||
} | ||
reply.code(errorResponse.statusCode).send(errorResponse) | ||
}) | ||
fastify.post('/', { schema }, echoBody) | ||
fastify.inject({ | ||
method: 'POST', | ||
payload: { | ||
hello: 'michelangelo' | ||
}, | ||
url: '/' | ||
}, (err, res) => { | ||
t.error(err) | ||
t.same(res.json(), { | ||
statusCode: 400, | ||
message: "body must have required property 'name'" | ||
}) | ||
t.equal(res.statusCode, 400) | ||
}) | ||
}) | ||
test('error inside custom error handler should have validationContext', t => { | ||
@@ -102,0 +134,0 @@ t.plan(1) |
@@ -72,3 +72,2 @@ import { FastifyInstance } from './instance' | ||
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault, | ||
ReturnType = ResolveFastifyReplyReturnType<TypeProvider, SchemaCompiler, RouteGeneric>, | ||
RequestType extends FastifyRequestType = ResolveFastifyRequestType<TypeProvider, SchemaCompiler, RouteGeneric>, | ||
@@ -80,3 +79,4 @@ Logger extends FastifyLoggerInstance = FastifyLoggerInstance | ||
reply: FastifyReply<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider> | ||
) => ReturnType | ||
// This return type used to be a generic type argument. Due to TypeScript's inference of return types, this rendered returns unchecked. | ||
) => ResolveFastifyReplyReturnType<TypeProvider, SchemaCompiler, RouteGeneric> | ||
@@ -94,7 +94,6 @@ /** | ||
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault, | ||
ReturnType = ResolveFastifyReplyReturnType<TypeProvider, SchemaCompiler, RouteGeneric>, | ||
RequestType extends FastifyRequestType = ResolveFastifyRequestType<TypeProvider, SchemaCompiler, RouteGeneric>, | ||
Logger extends FastifyLoggerInstance = FastifyLoggerInstance | ||
> extends RouteShorthandOptions<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider, RequestType, Logger> { | ||
handler: RouteHandlerMethod<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider, ReturnType, RequestType, Logger>; | ||
handler: RouteHandlerMethod<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider, RequestType, Logger>; | ||
} | ||
@@ -111,14 +110,14 @@ | ||
> { | ||
<RouteGeneric extends RouteGenericInterface = RouteGenericInterface, ContextConfig = ContextConfigDefault, SchemaCompiler = FastifySchema, ReturnType = ResolveFastifyReplyReturnType<TypeProvider, SchemaCompiler, RouteGeneric>, RequestType extends FastifyRequestType = ResolveFastifyRequestType<TypeProvider, SchemaCompiler, RouteGeneric>, Logger extends FastifyLoggerInstance = FastifyLoggerInstance>( | ||
<RouteGeneric extends RouteGenericInterface = RouteGenericInterface, ContextConfig = ContextConfigDefault, SchemaCompiler = FastifySchema, RequestType extends FastifyRequestType = ResolveFastifyRequestType<TypeProvider, SchemaCompiler, RouteGeneric>, Logger extends FastifyLoggerInstance = FastifyLoggerInstance>( | ||
path: string, | ||
opts: RouteShorthandOptions<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider, RequestType, Logger>, | ||
handler: RouteHandlerMethod<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider, ReturnType, RequestType, Logger> | ||
handler: RouteHandlerMethod<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider, RequestType, Logger> | ||
): FastifyInstance<RawServer, RawRequest, RawReply, Logger, TypeProvider>; | ||
<RouteGeneric extends RouteGenericInterface = RouteGenericInterface, ContextConfig = ContextConfigDefault, SchemaCompiler = FastifySchema, ReturnType = ResolveFastifyReplyReturnType<TypeProvider, SchemaCompiler, RouteGeneric>, RequestType extends FastifyRequestType = ResolveFastifyRequestType<TypeProvider, SchemaCompiler, RouteGeneric>, Logger extends FastifyLoggerInstance = FastifyLoggerInstance>( | ||
<RouteGeneric extends RouteGenericInterface = RouteGenericInterface, ContextConfig = ContextConfigDefault, SchemaCompiler = FastifySchema, RequestType extends FastifyRequestType = ResolveFastifyRequestType<TypeProvider, SchemaCompiler, RouteGeneric>, Logger extends FastifyLoggerInstance = FastifyLoggerInstance>( | ||
path: string, | ||
handler: RouteHandlerMethod<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider, ReturnType, RequestType, Logger> | ||
handler: RouteHandlerMethod<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider, RequestType, Logger> | ||
): FastifyInstance<RawServer, RawRequest, RawReply, Logger, TypeProvider>; | ||
<RouteGeneric extends RouteGenericInterface = RouteGenericInterface, ContextConfig = ContextConfigDefault, SchemaCompiler = FastifySchema, ReturnType = ResolveFastifyReplyReturnType<TypeProvider, SchemaCompiler, RouteGeneric>, RequestType extends FastifyRequestType = ResolveFastifyRequestType<TypeProvider, SchemaCompiler, RouteGeneric>, Logger extends FastifyLoggerInstance = FastifyLoggerInstance>( | ||
<RouteGeneric extends RouteGenericInterface = RouteGenericInterface, ContextConfig = ContextConfigDefault, SchemaCompiler = FastifySchema, RequestType extends FastifyRequestType = ResolveFastifyRequestType<TypeProvider, SchemaCompiler, RouteGeneric>, Logger extends FastifyLoggerInstance = FastifyLoggerInstance>( | ||
path: string, | ||
opts: RouteShorthandOptionsWithHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider, ReturnType, RequestType, Logger> | ||
opts: RouteShorthandOptionsWithHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider, RequestType, Logger> | ||
): FastifyInstance<RawServer, RawRequest, RawReply, Logger, TypeProvider>; | ||
@@ -138,3 +137,2 @@ } | ||
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault, | ||
ReturnType = ResolveFastifyReplyReturnType<TypeProvider, SchemaCompiler, RouteGeneric>, | ||
RequestType extends FastifyRequestType = ResolveFastifyRequestType<TypeProvider, SchemaCompiler, RouteGeneric>, | ||
@@ -145,3 +143,3 @@ Logger extends FastifyLoggerInstance = FastifyLoggerInstance | ||
url: string; | ||
handler: RouteHandlerMethod<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider, ReturnType, RequestType, Logger>; | ||
handler: RouteHandlerMethod<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider, RequestType, Logger>; | ||
} | ||
@@ -148,0 +146,0 @@ |
@@ -24,13 +24,20 @@ | ||
// Used to map undefined SchemaCompiler properties to unknown | ||
type UndefinedToUnknown<T> = T extends undefined ? unknown : T | ||
// Without brackets, UndefinedToUnknown<undefined | null> => unknown | ||
type UndefinedToUnknown<T> = [T] extends [undefined] ? unknown : T | ||
// union-aware keyof operator | ||
// keyof ({ a: number} | { b: number}) => never | ||
// KeysOf<{a: number} | {b: number}> => "a" | "b" | ||
// this exists to allow users to override faulty type-provider logic. | ||
type KeysOf<T> = T extends any ? keyof T : never | ||
// Resolves Request types either from generic argument or Type Provider. | ||
type ResolveRequestParams<TypeProvider extends FastifyTypeProvider, SchemaCompiler extends FastifySchema, RouteGeneric extends RouteGenericInterface> = | ||
UndefinedToUnknown<keyof RouteGeneric['Params'] extends never ? CallTypeProvider<TypeProvider, SchemaCompiler['params']> : RouteGeneric['Params']> | ||
UndefinedToUnknown<KeysOf<RouteGeneric['Params']> extends never ? CallTypeProvider<TypeProvider, SchemaCompiler['params']> : RouteGeneric['Params']> | ||
type ResolveRequestQuerystring<TypeProvider extends FastifyTypeProvider, SchemaCompiler extends FastifySchema, RouteGeneric extends RouteGenericInterface> = | ||
UndefinedToUnknown<keyof RouteGeneric['Querystring'] extends never ? CallTypeProvider<TypeProvider, SchemaCompiler['querystring']> : RouteGeneric['Querystring']> | ||
UndefinedToUnknown<KeysOf<RouteGeneric['Querystring']> extends never ? CallTypeProvider<TypeProvider, SchemaCompiler['querystring']> : RouteGeneric['Querystring']> | ||
type ResolveRequestHeaders<TypeProvider extends FastifyTypeProvider, SchemaCompiler extends FastifySchema, RouteGeneric extends RouteGenericInterface> = | ||
UndefinedToUnknown<keyof RouteGeneric['Headers'] extends never ? CallTypeProvider<TypeProvider, SchemaCompiler['headers']> : RouteGeneric['Headers']> | ||
UndefinedToUnknown<KeysOf<RouteGeneric['Headers']> extends never ? CallTypeProvider<TypeProvider, SchemaCompiler['headers']> : RouteGeneric['Headers']> | ||
type ResolveRequestBody<TypeProvider extends FastifyTypeProvider, SchemaCompiler extends FastifySchema, RouteGeneric extends RouteGenericInterface> = | ||
UndefinedToUnknown<keyof RouteGeneric['Body'] extends never ? CallTypeProvider<TypeProvider, SchemaCompiler['body']> : RouteGeneric['Body']> | ||
UndefinedToUnknown<KeysOf<RouteGeneric['Body']> extends never ? CallTypeProvider<TypeProvider, SchemaCompiler['body']> : RouteGeneric['Body']> | ||
@@ -37,0 +44,0 @@ // The target request type. This type is inferenced on fastify 'requests' via generic argument assignment |
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1815307
256
43087
+ Added@fastify/fast-json-stringify-compiler@4.3.0(transitive)
+ Added@fastify/merge-json-schemas@0.1.1(transitive)
+ Addedajv-formats@3.0.1(transitive)
+ Addedfast-decode-uri-component@1.0.1(transitive)
+ Addedfast-json-stringify@5.16.1(transitive)
+ Addedfast-querystring@1.1.2(transitive)
+ Addedfind-my-way@7.7.0(transitive)
+ Addedjson-schema-ref-resolver@1.0.1(transitive)
- Removed@fastify/fast-json-stringify-compiler@3.0.1(transitive)
- Removeddeepmerge@4.3.1(transitive)
- Removedfast-json-stringify@4.2.0(transitive)
- Removedfind-my-way@6.4.0(transitive)
- Removedstring-similarity@4.0.4(transitive)
Updatedfind-my-way@^7.0.0