Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/fastify/fastify-sensible

Defaults for Fastify that everyone can agree on
https://github.com/fastify/fastify-sensible

defaults fastify fastify-plugin http utility

Last synced: about 2 months ago
JSON representation

Defaults for Fastify that everyone can agree on

Awesome Lists containing this project

README

        

# @fastify/sensible

![CI](https://github.com/fastify/fastify-sensible/workflows/CI/badge.svg)
[![NPM version](https://img.shields.io/npm/v/@fastify/sensible.svg?style=flat)](https://www.npmjs.com/package/@fastify/sensible)
[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](https://standardjs.com/)

Defaults for Fastify that everyone can agree on™.

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?

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 |
| -------------- |---------------- |
| `^5.0.0` | `^4.0.0` |
| `^4.0.0` | `^3.0.0` |
| `^2.0.0` | `^2.0.0` |
| `^1.0.0` | `^1.0.0` |

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](https://github.com/fastify/fastify/blob/main/docs/Reference/LTS.md) for more details.

## Usage
```js
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.
```js
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]))`](https://github.com/jshttp/http-errors#new-createerrorcode--namemsg) in [http-errors](https://github.com/jshttp/http-errors):

```js
// the custom message is optional
const notFoundErr = fastify.httpErrors.notFound('custom message')
```

`4xx`
- fastify.httpErrors.badRequest()
- fastify.httpErrors.unauthorized()
- fastify.httpErrors.paymentRequired()
- fastify.httpErrors.forbidden()
- fastify.httpErrors.notFound()
- fastify.httpErrors.methodNotAllowed()
- fastify.httpErrors.notAcceptable()
- fastify.httpErrors.proxyAuthenticationRequired()
- fastify.httpErrors.requestTimeout()
- fastify.httpErrors.conflict()
- fastify.httpErrors.gone()
- fastify.httpErrors.lengthRequired()
- fastify.httpErrors.preconditionFailed()
- fastify.httpErrors.payloadTooLarge()
- fastify.httpErrors.uriTooLong()
- fastify.httpErrors.unsupportedMediaType()
- fastify.httpErrors.rangeNotSatisfiable()
- fastify.httpErrors.expectationFailed()
- fastify.httpErrors.imateapot()
- fastify.httpErrors.misdirectedRequest()
- fastify.httpErrors.unprocessableEntity()
- fastify.httpErrors.locked()
- fastify.httpErrors.failedDependency()
- fastify.httpErrors.tooEarly()
- fastify.httpErrors.upgradeRequired()
- fastify.httpErrors.preconditionRequired()
- fastify.httpErrors.tooManyRequests()
- fastify.httpErrors.requestHeaderFieldsTooLarge()
- fastify.httpErrors.unavailableForLegalReasons()

`5xx`
- fastify.httpErrors.internalServerError()
- fastify.httpErrors.notImplemented()
- fastify.httpErrors.badGateway()
- fastify.httpErrors.serviceUnavailable()
- fastify.httpErrors.gatewayTimeout()
- fastify.httpErrors.httpVersionNotSupported()
- fastify.httpErrors.variantAlsoNegotiates()
- fastify.httpErrors.insufficientStorage()
- fastify.httpErrors.loopDetected()
- fastify.httpErrors.bandwidthLimitExceeded()
- fastify.httpErrors.notExtended()
- fastify.httpErrors.networkAuthenticationRequired()

`createError`

Use of `createError` follows the same structure as [`createError([status], [message], [properties])`](https://github.com/jshttp/http-errors#createerrorstatus-message-properties) in [http-errors](https://github.com/jshttp/http-errors):

```js
var 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:
```js
fastify.get('/', (req, reply) => {
reply.notFound()
})
```

#### `reply.vary`
The `reply` interface is decorated with [`jshttp/vary`](https://github.com/jshttp/vary), the API is the same, but you do not need to pass the res object.
```js
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.
```js
// 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.
```js
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.
```js
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.
```js
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](https://tools.ietf.org/html/rfc5861).
```js
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](https://web.dev/stale-while-revalidate/).
```js
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`](https://github.com/jshttp/forwarded), the API is the same, but you do not need to pass the request object:
```js
fastify.get('/', (req, reply) => {
reply.send(req.forwarded())
})
```

#### `request.is`
The `request` interface is decorated with [`jshttp/type-is`](https://github.com/jshttp/type-is), the API is the same, but you do not need to pass the request object:
```js
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.
Useful if you work with *async* routes:
```js
// the custom message is optional
fastify.assert(
req.headers.authorization, 400, 'Missing authorization header'
)
```
The `assert` API also exposes the following methods:
- fastify.assert.ok()
- fastify.assert.equal()
- fastify.assert.notEqual()
- fastify.assert.strictEqual()
- fastify.assert.notStrictEqual()
- fastify.assert.deepEqual()
- fastify.assert.notDeepEqual()

#### `to`
Async await wrapper for easy error handling without try-catch, inspired by [`await-to-js`](https://github.com/scopsy/await-to-js):

```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?

Open an issue and let's discuss it! Even better a pull request!

## Acknowledgements

The project name is inspired by [`vim-sensible`](https://github.com/tpope/vim-sensible), an awesome package that if you use vim you should use too.

## License

MIT
Copyright © Tomas Della Vedova & Fastify collaborators