Awesome
@fastify/sensible
Defaults for Fastify that everyone can agree on™.<br> This plugin adds some useful utilities to your Fastify instance, see the API section to learn more.
Why are these APIs here and not included with Fastify?<br> Because Fastify aims to be as small and focused as possible, every utility that is not essential should be shipped as a standalone plugin.
Install
npm i @fastify/sensible
Compatibility
Plugin version | Fastify version |
---|---|
^6.x | ^5.x |
^5.x | ^4.x |
^4.x | ^3.x |
^2.x | ^2.x |
^1.x | ^1.x |
Please note that if a Fastify version is out of support, then so are the corresponding version(s) of this plugin in the table above. See Fastify's LTS policy for more details.
Usage
const fastify = require('fastify')()
fastify.register(require('@fastify/sensible'))
fastify.get('/', (req, reply) => {
reply.notFound()
})
fastify.get('/async', async (req, reply) => {
throw fastify.httpErrors.notFound()
})
fastify.get('/async-return', async (req, reply) => {
return reply.notFound()
})
fastify.listen({ port: 3000 })
Shared JSON Schema for HTTP errors
If you set the sharedSchemaId
option, a shared JSON Schema is added and can be used in your routes.
const fastify = require('fastify')()
fastify.register(require('@fastify/sensible'), {
sharedSchemaId: 'HttpError'
})
fastify.get('/async', {
schema: {
response: {
404: { $ref: 'HttpError' }
}
},
handler: async (req, reply) => {
return reply.notFound()
}
})
fastify.listen({ port: 3000 })
API
fastify.httpErrors
Object that exposes createError
and all of the 4xx
and 5xx
error constructors.
Use of 4xx
and 5xx
error constructors follows the same structure as new createError[code || name]([msg]))
in http-errors:
// the custom message is optional
const notFoundErr = fastify.httpErrors.notFound('custom message')
4xx
- <code>fastify.httpErrors.<b>badRequest()</b></code>
- <code>fastify.httpErrors.<b>unauthorized()</b></code>
- <code>fastify.httpErrors.<b>paymentRequired()</b></code>
- <code>fastify.httpErrors.<b>forbidden()</b></code>
- <code>fastify.httpErrors.<b>notFound()</b></code>
- <code>fastify.httpErrors.<b>methodNotAllowed()</b></code>
- <code>fastify.httpErrors.<b>notAcceptable()</b></code>
- <code>fastify.httpErrors.<b>proxyAuthenticationRequired()</b></code>
- <code>fastify.httpErrors.<b>requestTimeout()</b></code>
- <code>fastify.httpErrors.<b>conflict()</b></code>
- <code>fastify.httpErrors.<b>gone()</b></code>
- <code>fastify.httpErrors.<b>lengthRequired()</b></code>
- <code>fastify.httpErrors.<b>preconditionFailed()</b></code>
- <code>fastify.httpErrors.<b>payloadTooLarge()</b></code>
- <code>fastify.httpErrors.<b>uriTooLong()</b></code>
- <code>fastify.httpErrors.<b>unsupportedMediaType()</b></code>
- <code>fastify.httpErrors.<b>rangeNotSatisfiable()</b></code>
- <code>fastify.httpErrors.<b>expectationFailed()</b></code>
- <code>fastify.httpErrors.<b>imateapot()</b></code>
- <code>fastify.httpErrors.<b>misdirectedRequest()</b></code>
- <code>fastify.httpErrors.<b>unprocessableEntity()</b></code>
- <code>fastify.httpErrors.<b>locked()</b></code>
- <code>fastify.httpErrors.<b>failedDependency()</b></code>
- <code>fastify.httpErrors.<b>tooEarly()</b></code>
- <code>fastify.httpErrors.<b>upgradeRequired()</b></code>
- <code>fastify.httpErrors.<b>preconditionRequired()</b></code>
- <code>fastify.httpErrors.<b>tooManyRequests()</b></code>
- <code>fastify.httpErrors.<b>requestHeaderFieldsTooLarge()</b></code>
- <code>fastify.httpErrors.<b>unavailableForLegalReasons()</b></code>
5xx
- <code>fastify.httpErrors.<b>internalServerError()</b></code>
- <code>fastify.httpErrors.<b>notImplemented()</b></code>
- <code>fastify.httpErrors.<b>badGateway()</b></code>
- <code>fastify.httpErrors.<b>serviceUnavailable()</b></code>
- <code>fastify.httpErrors.<b>gatewayTimeout()</b></code>
- <code>fastify.httpErrors.<b>httpVersionNotSupported()</b></code>
- <code>fastify.httpErrors.<b>variantAlsoNegotiates()</b></code>
- <code>fastify.httpErrors.<b>insufficientStorage()</b></code>
- <code>fastify.httpErrors.<b>loopDetected()</b></code>
- <code>fastify.httpErrors.<b>bandwidthLimitExceeded()</b></code>
- <code>fastify.httpErrors.<b>notExtended()</b></code>
- <code>fastify.httpErrors.<b>networkAuthenticationRequired()</b></code>
createError
Use of createError
follows the same structure as createError([status], [message], [properties])
in http-errors:
const err = fastify.httpErrors.createError(404, 'This video does not exist!')
reply.[httpError]
The reply
interface is decorated with all of the functions declared above, using it is easy:
fastify.get('/', (req, reply) => {
reply.notFound()
})
reply.vary
The reply
interface is decorated with jshttp/vary
, the API is the same, but you do not need to pass the res object.
fastify.get('/', (req, reply) => {
reply.vary('Accept')
reply.send('ok')
})
reply.cacheControl
The reply
interface is decorated an helper to configure cache control response headers.
// configure a single type
fastify.get('/', (req, reply) => {
reply.cacheControl('public')
reply.send('ok')
})
// configure multiple types
fastify.get('/', (req, reply) => {
reply.cacheControl('public')
reply.cacheControl('immutable')
reply.send('ok')
})
// configure a type time
fastify.get('/', (req, reply) => {
reply.cacheControl('max-age', 42)
reply.send('ok')
})
// the time can be defined as string
fastify.get('/', (req, reply) => {
// all the formats of github.com/vercel/ms are supported
reply.cacheControl('max-age', '1d') // will set to 'max-age=86400'
reply.send('ok')
})
reply.preventCache
The reply
interface is decorated with a helper to set the cache control header to a no caching configuration.
fastify.get('/', (req, reply) => {
// will set cache-control to 'no-store, max-age=0, private'
// and for HTTP/1.0 compatibility
// will set pragma to 'no-cache' and expires to 0
reply.preventCache()
reply.send('ok')
})
reply.revalidate
The reply
interface is decorated with a helper to set the cache control header to a no caching configuration.
fastify.get('/', (req, reply) => {
reply.revalidate() // will set to 'max-age=0, must-revalidate'
reply.send('ok')
})
reply.staticCache
The reply
interface is decorated with a helper to set the cache control header to a public and immutable configuration.
fastify.get('/', (req, reply) => {
// the time can be defined as a string
reply.staticCache(42) // will set to 'public, max-age=42, immutable'
reply.send('ok')
})
reply.stale
The reply
interface is decorated with a helper to set the cache control header for stale content.
fastify.get('/', (req, reply) => {
// the time can be defined as a string
reply.stale('while-revalidate', 42)
reply.stale('if-error', 1)
reply.send('ok')
})
reply.maxAge
The reply
interface is decorated with a helper to set max age of the response. It can be used in conjunction with reply.stale
, see here.
fastify.get('/', (req, reply) => {
// the time can be defined as a string
reply.maxAge(86400)
reply.stale('while-revalidate', 42)
reply.send('ok')
})
request.forwarded
The request
interface is decorated with jshttp/forwarded
, the API is the same, but you do not need to pass the request object:
fastify.get('/', (req, reply) => {
reply.send(req.forwarded())
})
request.is
The request
interface is decorated with jshttp/type-is
, the API is the same, but you do not need to pass the request object:
fastify.get('/', (req, reply) => {
reply.send(req.is(['html', 'json']))
})
assert
Verify if a given condition is true, if not it throws the specified http error.<br> Useful if you work with async routes:
// the custom message is optional
fastify.assert(
req.headers.authorization, 400, 'Missing authorization header'
)
The assert
API also exposes the following methods:
- <code>fastify.assert.<b>ok()</b></code>
- <code>fastify.assert.<b>equal()</b></code>
- <code>fastify.assert.<b>notEqual()</b></code>
- <code>fastify.assert.<b>strictEqual()</b></code>
- <code>fastify.assert.<b>notStrictEqual()</b></code>
- <code>fastify.assert.<b>deepEqual()</b></code>
- <code>fastify.assert.<b>notDeepEqual()</b></code>
to
Async await wrapper for easy error handling without try-catch, inspired by await-to-js
:
const [err, user] = await fastify.to(
db.findOne({ user: 'tyrion' })
)
Contributing
Do you feel there is some utility that everyone can agree on which is not present?<br> Open an issue and let's discuss it! Even better a pull request!
Acknowledgements
The project name is inspired by vim-sensible
, an awesome package that if you use vim you should use too.
License
MIT Copyright © Tomas Della Vedova & Fastify collaborators