You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					248 lines
				
				7.6 KiB
			
		
		
			
		
	
	
					248 lines
				
				7.6 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								<h1 align="center">Fastify</h1>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## Plugins
							 | 
						||
| 
								 | 
							
								Fastify allows the user to extend its functionalities with plugins. A plugin can
							 | 
						||
| 
								 | 
							
								be a set of routes, a server [decorator](./Decorators.md), or whatever. The API
							 | 
						||
| 
								 | 
							
								that you will need to use one or more plugins, is `register`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								By default, `register` creates a *new scope*, this means that if you make some
							 | 
						||
| 
								 | 
							
								changes to the Fastify instance (via `decorate`), this change will not be
							 | 
						||
| 
								 | 
							
								reflected by the current context ancestors, but only to its descendants. This
							 | 
						||
| 
								 | 
							
								feature allows us to achieve plugin *encapsulation* and *inheritance*, in this
							 | 
						||
| 
								 | 
							
								way we create a *direct acyclic graph* (DAG) and we will not have issues caused
							 | 
						||
| 
								 | 
							
								by cross dependencies.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								You already see in the [getting started](../Guides/Getting-Started.md#your-first-plugin)
							 | 
						||
| 
								 | 
							
								section how using this API is pretty straightforward.
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								fastify.register(plugin, [options])
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								### Plugin Options
							 | 
						||
| 
								 | 
							
								<a id="plugin-options"></a>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								The optional `options` parameter for `fastify.register` supports a predefined
							 | 
						||
| 
								 | 
							
								set of options that Fastify itself will use, except when the plugin has been
							 | 
						||
| 
								 | 
							
								wrapped with [fastify-plugin](https://github.com/fastify/fastify-plugin). This
							 | 
						||
| 
								 | 
							
								options object will also be passed to the plugin upon invocation, regardless of
							 | 
						||
| 
								 | 
							
								whether or not the plugin has been wrapped. The currently supported list of
							 | 
						||
| 
								 | 
							
								Fastify specific options is:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								+ [`logLevel`](./Routes.md#custom-log-level)
							 | 
						||
| 
								 | 
							
								+ [`logSerializers`](./Routes.md#custom-log-serializer)
							 | 
						||
| 
								 | 
							
								+ [`prefix`](#route-prefixing-option)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								**Note: Those options will be ignored when used with fastify-plugin**
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								It is possible that Fastify will directly support other options in the future.
							 | 
						||
| 
								 | 
							
								Thus, to avoid collisions, a plugin should consider namespacing its options. For
							 | 
						||
| 
								 | 
							
								example, a plugin `foo` might be registered like so:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								fastify.register(require('fastify-foo'), {
							 | 
						||
| 
								 | 
							
								  prefix: '/foo',
							 | 
						||
| 
								 | 
							
								  foo: {
							 | 
						||
| 
								 | 
							
								    fooOption1: 'value',
							 | 
						||
| 
								 | 
							
								    fooOption2: 'value'
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								If collisions are not a concern, the plugin may simply accept the options object
							 | 
						||
| 
								 | 
							
								as-is:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								fastify.register(require('fastify-foo'), {
							 | 
						||
| 
								 | 
							
								  prefix: '/foo',
							 | 
						||
| 
								 | 
							
								  fooOption1: 'value',
							 | 
						||
| 
								 | 
							
								  fooOption2: 'value'
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								The `options` parameter can also be a `Function` that will be evaluated at the
							 | 
						||
| 
								 | 
							
								time the plugin is registered while giving access to the Fastify instance via
							 | 
						||
| 
								 | 
							
								the first positional argument:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								const fp = require('fastify-plugin')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								fastify.register(fp((fastify, opts, done) => {
							 | 
						||
| 
								 | 
							
								  fastify.decorate('foo_bar', { hello: 'world' })
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  done()
							 | 
						||
| 
								 | 
							
								}))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// The opts argument of fastify-foo will be { hello: 'world' }
							 | 
						||
| 
								 | 
							
								fastify.register(require('fastify-foo'), parent => parent.foo_bar)
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								The Fastify instance passed on to the function is the latest state of the
							 | 
						||
| 
								 | 
							
								**external Fastify instance** the plugin was declared on, allowing access to
							 | 
						||
| 
								 | 
							
								variables injected via [`decorate`](./Decorators.md) by preceding plugins
							 | 
						||
| 
								 | 
							
								according to the **order of registration**. This is useful in case a plugin
							 | 
						||
| 
								 | 
							
								depends on changes made to the Fastify instance by a preceding plugin i.e.
							 | 
						||
| 
								 | 
							
								utilizing an existing database connection to wrap around it.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Keep in mind that the Fastify instance passed on to the function is the same as
							 | 
						||
| 
								 | 
							
								the one that will be passed into the plugin, a copy of the external Fastify
							 | 
						||
| 
								 | 
							
								instance rather than a reference. Any usage of the instance will behave the same
							 | 
						||
| 
								 | 
							
								as it would if called within the plugins function i.e. if `decorate` is called,
							 | 
						||
| 
								 | 
							
								the decorated variables will be available within the plugins function unless it
							 | 
						||
| 
								 | 
							
								was wrapped with [`fastify-plugin`](https://github.com/fastify/fastify-plugin).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#### Route Prefixing option
							 | 
						||
| 
								 | 
							
								<a id="route-prefixing-option"></a>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								If you pass an option with the key `prefix` with a `string` value, Fastify will
							 | 
						||
| 
								 | 
							
								use it to prefix all the routes inside the register, for more info check
							 | 
						||
| 
								 | 
							
								[here](./Routes.md#route-prefixing).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Be aware that if you use
							 | 
						||
| 
								 | 
							
								[`fastify-plugin`](https://github.com/fastify/fastify-plugin) this option will
							 | 
						||
| 
								 | 
							
								not work.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#### Error handling
							 | 
						||
| 
								 | 
							
								<a id="error-handling"></a>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								The error handling is done by
							 | 
						||
| 
								 | 
							
								[avvio](https://github.com/mcollina/avvio#error-handling).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								As a general rule, it is highly recommended that you handle your errors in the
							 | 
						||
| 
								 | 
							
								next `after` or `ready` block, otherwise you will get them inside the `listen`
							 | 
						||
| 
								 | 
							
								callback.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								fastify.register(require('my-plugin'))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// `after` will be executed once
							 | 
						||
| 
								 | 
							
								// the previous declared `register` has finished
							 | 
						||
| 
								 | 
							
								fastify.after(err => console.log(err))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// `ready` will be executed once all the registers declared
							 | 
						||
| 
								 | 
							
								// have finished their execution
							 | 
						||
| 
								 | 
							
								fastify.ready(err => console.log(err))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// `listen` is a special ready,
							 | 
						||
| 
								 | 
							
								// so it behaves in the same way
							 | 
						||
| 
								 | 
							
								fastify.listen(3000, (err, address) => {
							 | 
						||
| 
								 | 
							
								  if (err) console.log(err)
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								### async/await
							 | 
						||
| 
								 | 
							
								<a id="async-await"></a>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								*async/await* is supported by `after`, `ready` and `listen`, as well as
							 | 
						||
| 
								 | 
							
								`fastify` being a [Thenable](https://promisesaplus.com/).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								await fastify.register(require('my-plugin'))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								await fastify.after()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								await fastify.ready()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								await fastify.listen(3000)
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#### ESM support
							 | 
						||
| 
								 | 
							
								<a id="esm-support"></a>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								ESM is supported as well from [Node.js
							 | 
						||
| 
								 | 
							
								`v13.3.0`](https://nodejs.org/api/esm.html) and above!
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								// main.mjs
							 | 
						||
| 
								 | 
							
								import Fastify from 'fastify'
							 | 
						||
| 
								 | 
							
								const fastify = Fastify()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								fastify.register(import('./plugin.mjs'))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								fastify.listen(3000, console.log)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// plugin.mjs
							 | 
						||
| 
								 | 
							
								async function plugin (fastify, opts) {
							 | 
						||
| 
								 | 
							
								  fastify.get('/', async (req, reply) => {
							 | 
						||
| 
								 | 
							
								    return { hello: 'world' }
							 | 
						||
| 
								 | 
							
								  })
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export default plugin
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								### Create a plugin
							 | 
						||
| 
								 | 
							
								<a id="create-plugin"></a>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Creating a plugin is very easy, you just need to create a function that takes
							 | 
						||
| 
								 | 
							
								three parameters, the `fastify` instance, an `options` object, and the `done`
							 | 
						||
| 
								 | 
							
								callback.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Example:
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								module.exports = function (fastify, opts, done) {
							 | 
						||
| 
								 | 
							
								  fastify.decorate('utility', function () {})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  fastify.get('/', handler)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  done()
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								You can also use `register` inside another `register`:
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								module.exports = function (fastify, opts, done) {
							 | 
						||
| 
								 | 
							
								  fastify.decorate('utility', function () {})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  fastify.get('/', handler)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  fastify.register(require('./other-plugin'))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  done()
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								Sometimes, you will need to know when the server is about to close, for example,
							 | 
						||
| 
								 | 
							
								because you must close a connection to a database. To know when this is going to
							 | 
						||
| 
								 | 
							
								happen, you can use the [`'onClose'`](./Hooks.md#on-close) hook.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Do not forget that `register` will always create a new Fastify scope, if you do
							 | 
						||
| 
								 | 
							
								not need that, read the following section.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								### Handle the scope
							 | 
						||
| 
								 | 
							
								<a id="handle-scope"></a>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								If you are using `register` only for extending the functionality of the server
							 | 
						||
| 
								 | 
							
								with  [`decorate`](./Decorators.md), it is your responsibility to tell Fastify
							 | 
						||
| 
								 | 
							
								not to create a new scope. Otherwise, your changes will not be accessible by the
							 | 
						||
| 
								 | 
							
								user in the upper scope.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								You have two ways to tell Fastify to avoid the creation of a new context:
							 | 
						||
| 
								 | 
							
								- Use the [`fastify-plugin`](https://github.com/fastify/fastify-plugin) module
							 | 
						||
| 
								 | 
							
								- Use the `'skip-override'` hidden property
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								We recommend using the `fastify-plugin` module, because it solves this problem
							 | 
						||
| 
								 | 
							
								for you, and you can pass a version range of Fastify as a parameter that your
							 | 
						||
| 
								 | 
							
								plugin will support.
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								const fp = require('fastify-plugin')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								module.exports = fp(function (fastify, opts, done) {
							 | 
						||
| 
								 | 
							
								  fastify.decorate('utility', function () {})
							 | 
						||
| 
								 | 
							
								  done()
							 | 
						||
| 
								 | 
							
								}, '0.x')
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								Check the [`fastify-plugin`](https://github.com/fastify/fastify-plugin)
							 | 
						||
| 
								 | 
							
								documentation to learn more about how to use this module.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								If you do not use the `fastify-plugin` module, you can use the `'skip-override'`
							 | 
						||
| 
								 | 
							
								hidden property, but we do not recommend it. If in the future the Fastify API
							 | 
						||
| 
								 | 
							
								changes it will be your responsibility to update the module, while if you use
							 | 
						||
| 
								 | 
							
								`fastify-plugin`, you can be sure about backward compatibility.
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								function yourPlugin (fastify, opts, done) {
							 | 
						||
| 
								 | 
							
								  fastify.decorate('utility', function () {})
							 | 
						||
| 
								 | 
							
								  done()
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								yourPlugin[Symbol.for('skip-override')] = true
							 | 
						||
| 
								 | 
							
								module.exports = yourPlugin
							 | 
						||
| 
								 | 
							
								```
							 |