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