UNPKG

8.11 kBMarkdownView Raw
1<h1 align="center">Fastify</h1>
2
3## Plugins
4Fastify allows the user to extend its functionalities with plugins.
5A plugin can be a set of routes, a server [decorator](https://github.com/fastify/fastify/blob/master/docs/Decorators.md) or whatever. The API that you will need to use one or more plugins, is `register`.<br>
6
7By default, `register` creates a *new scope*, this means that if you do some changes to the Fastify instance (via `decorate`), this change will not be reflected to the current context ancestors, but only to its sons. 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.
8
9You already see in the [getting started](https://github.com/fastify/fastify/blob/master/docs/Getting-Started.md#register) section how using this API is pretty straightforward.
10```
11fastify.register(plugin, [options])
12```
13
14<a name="plugin-options"></a>
15### Plugin Options
16The 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:
17
18+ [`logLevel`](https://github.com/fastify/fastify/blob/master/docs/Routes.md#custom-log-level)
19+ [`logSerializers`](https://github.com/fastify/fastify/blob/master/docs/Routes.md#custom-log-serializer)
20+ [`prefix`](https://github.com/fastify/fastify/blob/master/docs/Plugins.md#route-prefixing-options)
21
22**Note: Those options will be ignored when used with fastify-plugin**
23
24It 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:
25
26```js
27fastify.register(require('fastify-foo'), {
28 prefix: '/foo',
29 foo: {
30 fooOption1: 'value',
31 fooOption2: 'value'
32 }
33})
34```
35
36If collisions are not a concern, the plugin may simply accept the options object as-is:
37
38```js
39fastify.register(require('fastify-foo'), {
40 prefix: '/foo',
41 fooOption1: 'value',
42 fooOption2: 'value'
43})
44```
45
46The `options` parameter can also be a `Function` which will be evaluated at the time the plugin is registered while giving access to the fastify instance via the first positional argument:
47
48```js
49const fp = require('fastify-plugin')
50
51fastify.register(fp((fastify, opts, done) => {
52 fastify.decorate('foo_bar', { hello: 'world' })
53
54 done()
55}))
56
57// The opts argument of fastify-foo will be { hello: 'world' }
58fastify.register(require('fastify-foo'), parent => parent.foo_bar)
59```
60
61The 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`](https://github.com/fastify/fastify/blob/master/docs/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 f.e. utilizing an existing database connection to wrap around it.
62
63Keep in mind that the fastify instance passed on to the function is the same as the one that will be passed in to 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 plugin's function i.e. if `decorate` is called, the decorated variables will be available within the plugin's function unless it was wrapped with [`fastify-plugin`](https://github.com/fastify/fastify-plugin).
64
65<a name="route-prefixing-option"></a>
66#### Route Prefixing option
67If 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](https://github.com/fastify/fastify/blob/master/docs/Routes.md#route-prefixing).<br>
68Be aware that if you use [`fastify-plugin`](https://github.com/fastify/fastify-plugin) this option won't work.
69
70<a name="error-handling"></a>
71#### Error handling
72The error handling is done by [avvio](https://github.com/mcollina/avvio#error-handling).<br>
73As 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.
74
75```js
76fastify.register(require('my-plugin'))
77
78// `after` will be executed once
79// the previous declared `register` has finished
80fastify.after(err => console.log(err))
81
82// `ready` will be executed once all the registers declared
83// have finished their execution
84fastify.ready(err => console.log(err))
85
86// `listen` is a special ready,
87// so it behaves in the same way
88fastify.listen(3000, (err, address) => {
89 if (err) console.log(err)
90})
91```
92
93*async-await* is supported only by `ready` and `listen`.
94```js
95fastify.register(require('my-plugin'))
96
97await fastify.ready()
98
99await fastify.listen(3000)
100```
101
102<a name="esm-support"></a>
103#### ESM support
104
105ESM is supported as well from [Node.js `v13.3.0`](https://nodejs.org/api/esm.html) and above!
106
107```js
108// main.mjs
109import Fastify from 'fastify'
110const fastify = Fastify()
111
112fastify.register(import('./plugin.mjs'))
113
114fastify.listen(3000, console.log)
115
116
117// plugin.mjs
118async function plugin (fastify, opts) {
119 fastify.get('/', async (req, reply) => {
120 return { hello: 'world' }
121 })
122}
123
124export default plugin
125```
126
127<a name="create-plugin"></a>
128### Create a plugin
129Creating 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.<br>
130Example:
131```js
132module.exports = function (fastify, opts, done) {
133 fastify.decorate('utility', () => {})
134
135 fastify.get('/', handler)
136
137 done()
138}
139```
140You can also use `register` inside another `register`:
141```js
142module.exports = function (fastify, opts, done) {
143 fastify.decorate('utility', () => {})
144
145 fastify.get('/', handler)
146
147 fastify.register(require('./other-plugin'))
148
149 done()
150}
151```
152Sometimes, 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'`](https://github.com/fastify/fastify/blob/master/docs/Hooks.md#on-close) hook.
153
154Do not forget that `register` will always create a new Fastify scope, if you don't need that, read the following section.
155
156<a name="handle-scope"></a>
157### Handle the scope
158If you are using `register` only for extending the functionality of the server with [`decorate`](https://github.com/fastify/fastify/blob/master/docs/Decorators.md), it is your responsibility to tell Fastify to not create a new scope, otherwise your changes will not be accessible by the user in the upper scope.
159
160You have two ways to tell Fastify to avoid the creation of a new context:
161- Use the [`fastify-plugin`](https://github.com/fastify/fastify-plugin) module
162- Use the `'skip-override'` hidden property
163
164We recommend to 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.
165```js
166const fp = require('fastify-plugin')
167
168module.exports = fp(function (fastify, opts, done) {
169 fastify.decorate('utility', () => {})
170 done()
171}, '0.x')
172```
173Check the [`fastify-plugin`](https://github.com/fastify/fastify-plugin) documentation to know more about how use this module.
174
175If you don't 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 a your responsibility update the module, while if you use `fastify-plugin`, you can be sure about backwards compatibility.
176```js
177function yourPlugin (fastify, opts, done) {
178 fastify.decorate('utility', () => {})
179 done()
180}
181yourPlugin[Symbol.for('skip-override')] = true
182module.exports = yourPlugin
183```