File size: 17,079 Bytes
23ac194
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
<h1 align="center">Fastify</h1>

# The hitchhiker's guide to plugins
First of all, `DON'T PANIC`!

Fastify was built from the beginning to be an extremely modular system. We built
a powerful API that allows you to add methods and utilities to Fastify by
creating a namespace. We built a system that creates an encapsulation model,
which allows you to split your application into multiple microservices at any
moment, without the need to refactor the entire application.

**Table of contents**
- [The hitchhiker's guide to plugins](#the-hitchhikers-guide-to-plugins)
  - [Register](#register)
  - [Decorators](#decorators)
  - [Hooks](#hooks)
  - [How to handle encapsulation and
    distribution](#how-to-handle-encapsulation-and-distribution)
  - [ESM support](#esm-support)
  - [Handle errors](#handle-errors)
  - [Custom errors](#custom-errors)
  - [Emit Warnings](#emit-warnings)
  - [Let's start!](#lets-start)

## Register
<a id="register"></a>

As with JavaScript, where everything is an object, in Fastify everything is a
plugin.

Your routes, your utilities, and so on are all plugins. To add a new plugin,
whatever its functionality may be, in Fastify you have a nice and unique API:
[`register`](../Reference/Plugins.md).
```js
fastify.register(
  require('./my-plugin'),
  { options }
)
```
`register` creates a new Fastify context, which means that if you perform any
changes on the Fastify instance, those changes will not be reflected in the
context's ancestors. In other words, encapsulation!

*Why is encapsulation important?*

Well, let's say you are creating a new disruptive startup, what do you do? You
create an API server with all your stuff, everything in the same place, a
monolith!

Ok, you are growing very fast and you want to change your architecture and try
microservices. Usually, this implies a huge amount of work, because of cross
dependencies and a lack of separation of concerns in the codebase.

Fastify helps you in that regard. Thanks to the encapsulation model, it will
completely avoid cross dependencies and will help you structure your code into
cohesive blocks.

*Let's return to how to correctly use `register`.*

As you probably know, the required plugins must expose a single function with
the following signature
```js
module.exports = function (fastify, options, done) {}
```
Where `fastify` is the encapsulated Fastify instance, `options` is the options
object, and `done` is the function you **must** call when your plugin is ready.

Fastify's plugin model is fully reentrant and graph-based, it handles
asynchronous code without any problems and it enforces both the load and close
order of plugins. *How?* Glad you asked, check out
[`avvio`](https://github.com/mcollina/avvio)! Fastify starts loading the plugin
__after__ `.listen()`, `.inject()` or `.ready()` are called.

Inside a plugin you can do whatever you want, register routes, utilities (we
will see this in a moment) and do nested registers, just remember to call `done`
when everything is set up!
```js
module.exports = function (fastify, options, done) {
  fastify.get('/plugin', (request, reply) => {
    reply.send({ hello: 'world' })
  })

  done()
}
```

Well, now you know how to use the `register` API and how it works, but how do we
add new functionality to Fastify and even better, share them with other
developers?

## Decorators
<a id="decorators"></a>

Okay, let's say that you wrote a utility that is so good that you decided to
make it available along with all your code. How would you do it? Probably
something like the following:
```js
// your-awesome-utility.js
module.exports = function (a, b) {
  return a + b
}
```
```js
const util = require('./your-awesome-utility')
console.log(util('that is ', 'awesome'))
```
Now you will import your utility in every file you need it in. (And do not
forget that you will probably also need it in your tests).

Fastify offers you a more elegant and comfortable way to do this, *decorators*.
Creating a decorator is extremely easy, just use the
[`decorate`](../Reference/Decorators.md) API:
```js
fastify.decorate('util', (a, b) => a + b)
```
Now you can access your utility just by calling `fastify.util` whenever you need
it - even inside your test.

And here starts the magic; do you remember how just now we were talking about
encapsulation? Well, using `register` and `decorate` in conjunction enable
exactly that, let me show you an example to clarify this:
```js
fastify.register((instance, opts, done) => {
  instance.decorate('util', (a, b) => a + b)
  console.log(instance.util('that is ', 'awesome'))

  done()
})

fastify.register((instance, opts, done) => {
  console.log(instance.util('that is ', 'awesome')) // This will throw an error

  done()
})
```
Inside the second register call `instance.util` will throw an error because
`util` exists only inside the first register context.

Let's step back for a moment and dig deeper into this: every time you use the
`register` API, a new context is created which avoids the negative situations
mentioned above.

Do note that encapsulation applies to the ancestors and siblings, but not the
children.
```js
fastify.register((instance, opts, done) => {
  instance.decorate('util', (a, b) => a + b)
  console.log(instance.util('that is ', 'awesome'))

  fastify.register((instance, opts, done) => {
    console.log(instance.util('that is ', 'awesome')) // This will not throw an error
    done()
  })

  done()
})

fastify.register((instance, opts, done) => {
  console.log(instance.util('that is ', 'awesome')) // This will throw an error

  done()
})
```
*Take home message: if you need a utility that is available in every part of
your application, take care that it is declared in the root scope of your
application. If that is not an option,  you can use the `fastify-plugin` utility
as described [here](#distribution).*

`decorate` is not the only API that you can use to extend the server
functionality, you can also use `decorateRequest` and `decorateReply`.

*`decorateRequest` and `decorateReply`? Why do we need them if we already have
`decorate`?*

Good question, we added them to make Fastify more developer-friendly. Let's see
an example:
```js
fastify.decorate('html', payload => {
  return generateHtml(payload)
})

fastify.get('/html', (request, reply) => {
  reply
    .type('text/html')
    .send(fastify.html({ hello: 'world' }))
})
```
It works, but it could be much better!
```js
fastify.decorateReply('html', function (payload) {
  this.type('text/html') // This is the 'Reply' object
  this.send(generateHtml(payload))
})

fastify.get('/html', (request, reply) => {
  reply.html({ hello: 'world' })
})
```
Reminder that the `this` keyword is not available on *arrow functions*,
so when passing functions in *`decorateReply`* and *`decorateRequest`* as
a utility that also needs access to the `request` and `reply` instance,
a function that is defined using the `function` keyword is needed instead
of an *arrow function expression*.

In the same way you can do this for the `request` object:
```js
fastify.decorate('getHeader', (req, header) => {
  return req.headers[header]
})

fastify.addHook('preHandler', (request, reply, done) => {
  request.isHappy = fastify.getHeader(request.raw, 'happy')
  done()
})

fastify.get('/happiness', (request, reply) => {
  reply.send({ happy: request.isHappy })
})
```
Again, it works, but it can be much better!
```js
fastify.decorateRequest('setHeader', function (header) {
  this.isHappy = this.headers[header]
})

fastify.decorateRequest('isHappy', false) // This will be added to the Request object prototype, yay speed!

fastify.addHook('preHandler', (request, reply, done) => {
  request.setHeader('happy')
  done()
})

fastify.get('/happiness', (request, reply) => {
  reply.send({ happy: request.isHappy })
})
```

We have seen how to extend server functionality and how to handle the
encapsulation system, but what if you need to add a function that must be
executed whenever the server "[emits](../Reference/Lifecycle.md)" an
event?

## Hooks
<a id="hooks"></a>

You just built an amazing utility, but now you need to execute that for every
request, this is what you will likely do:
```js
fastify.decorate('util', (request, key, value) => { request[key] = value })

fastify.get('/plugin1', (request, reply) => {
  fastify.util(request, 'timestamp', new Date())
  reply.send(request)
})

fastify.get('/plugin2', (request, reply) => {
  fastify.util(request, 'timestamp', new Date())
  reply.send(request)
})
```
I think we all agree that this is terrible. Repeated code, awful readability and
it cannot scale.

So what can you do to avoid this annoying issue? Yes, you are right, use a
[hook](../Reference/Hooks.md)!

```js
fastify.decorate('util', (request, key, value) => { request[key] = value })

fastify.addHook('preHandler', (request, reply, done) => {
  fastify.util(request, 'timestamp', new Date())
  done()
})

fastify.get('/plugin1', (request, reply) => {
  reply.send(request)
})

fastify.get('/plugin2', (request, reply) => {
  reply.send(request)
})
```
Now for every request, you will run your utility. You can register as many hooks
as you need.

Sometimes you want a hook that should be executed for just a subset of routes,
how can you do that? Yep, encapsulation!

```js
fastify.register((instance, opts, done) => {
  instance.decorate('util', (request, key, value) => { request[key] = value })

  instance.addHook('preHandler', (request, reply, done) => {
    instance.util(request, 'timestamp', new Date())
    done()
  })

  instance.get('/plugin1', (request, reply) => {
    reply.send(request)
  })

  done()
})

fastify.get('/plugin2', (request, reply) => {
  reply.send(request)
})
```
Now your hook will run just for the first route!

An alternative approach is to make use of the [onRoute hook](../Reference/Hooks.md#onroute)
to customize application routes dynamically from inside the plugin. Every time
a new route is registered, you can read and modify the route options. For example,
based on a [route config option](../Reference/Routes.md#routes-options):

```js
fastify.register((instance, opts, done) => {
  instance.decorate('util', (request, key, value) => { request[key] = value })

  function handler(request, reply, done) {
    instance.util(request, 'timestamp', new Date())
    done()
  }

  instance.addHook('onRoute', (routeOptions) => {
    if (routeOptions.config && routeOptions.config.useUtil === true) {
      // set or add our handler to the route preHandler hook
      if (!routeOptions.preHandler) {
        routeOptions.preHandler = [handler]
        return
      }
      if (Array.isArray(routeOptions.preHandler)) {
        routeOptions.preHandler.push(handler)
        return
      }
      routeOptions.preHandler = [routeOptions.preHandler, handler]
    }
  })

  fastify.get('/plugin1', {config: {useUtil: true}}, (request, reply) => {
    reply.send(request)
  })

  fastify.get('/plugin2', (request, reply) => {
    reply.send(request)
  })

  done()
})
```

This variant becomes extremely useful if you plan to distribute your plugin, as
described in the next section.

As you probably noticed by now, `request` and `reply` are not the standard
Node.js *request* and *response* objects, but Fastify's objects.


## How to handle encapsulation and distribution
<a id="distribution"></a>

Perfect, now you know (almost) all of the tools that you can use to extend
Fastify. Nevertheless, chances are that you came across one big issue: how is
distribution handled?

The preferred way to distribute a utility is to wrap all your code inside a
`register`. Using this, your plugin can support asynchronous bootstrapping
*(since `decorate` is a synchronous API)*, in the case of a database connection
for example.

*Wait, what? Didn't you tell me that `register` creates an encapsulation and
that the stuff I create inside will not be available outside?*

Yes, I said that. However, what I didn't tell you is that you can tell Fastify
to avoid this behavior with the
[`fastify-plugin`](https://github.com/fastify/fastify-plugin) module.
```js
const fp = require('fastify-plugin')
const dbClient = require('db-client')

function dbPlugin (fastify, opts, done) {
  dbClient.connect(opts.url, (err, conn) => {
    fastify.decorate('db', conn)
    done()
  })
}

module.exports = fp(dbPlugin)
```
You can also tell `fastify-plugin` to check the installed version of Fastify, in
case you need a specific API.

As we mentioned earlier, Fastify starts loading its plugins __after__
`.listen()`, `.inject()` or `.ready()` are called and as such, __after__ they
have been declared. This means that, even though the plugin may inject variables
to the external Fastify instance via [`decorate`](../Reference/Decorators.md),
the decorated variables will not be accessible before calling `.listen()`,
`.inject()` or `.ready()`.

In case you rely on a variable injected by a preceding plugin and want to pass
that in the `options` argument of `register`, you can do so by using a function
instead of an object:
```js
const fastify = require('fastify')()
const fp = require('fastify-plugin')
const dbClient = require('db-client')

function dbPlugin (fastify, opts, done) {
  dbClient.connect(opts.url, (err, conn) => {
    fastify.decorate('db', conn)
    done()
  })
}

fastify.register(fp(dbPlugin), { url: 'https://example.com' })
fastify.register(require('your-plugin'), parent => {
  return { connection: parent.db, otherOption: 'foo-bar' }
})
```
In the above example, the `parent` variable of the function passed in as the
second argument of `register` is a copy of the **external Fastify instance**
that the plugin was registered at. This means that we can access any
variables that were injected by preceding plugins in the order of declaration.

## 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! Just export your plugin
as an ESM module and you are good to go!

```js
// plugin.mjs
async function plugin (fastify, opts) {
  fastify.get('/', async (req, reply) => {
    return { hello: 'world' }
  })
}

export default plugin
```

## Handle errors
<a id="handle-errors"></a>

One of your plugins may fail during startup. Maybe you expect it
and you have a custom logic that will be triggered in that case. How can you
implement this? The `after` API is what you need. `after` simply registers a
callback that will be executed just after a register, and it can take up to
three parameters.

The callback changes based on the parameters you are giving:

1. If no parameter is given to the callback and there is an error, that error
   will be passed to the next error handler.
1. If one parameter is given to the callback, that parameter will be the error
   object.
1. If two parameters are given to the callback, the first will be the error
   object; the second will be the done callback.
1. If three parameters are given to the callback, the first will be the error
   object, the second will be the top-level context unless you have specified
   both server and override, in that case, the context will be what the override
   returns, and the third the done callback.

Let's see how to use it:
```js
fastify
  .register(require('./database-connector'))
  .after(err => {
    if (err) throw err
  })
```

## Custom errors
<a id="custom-errors"></a>

If your plugin needs to expose custom errors, you can easily generate consistent
error objects across your codebase and plugins with the
[`@fastify/error`](https://github.com/fastify/fastify-error) module.

```js
const createError = require('@fastify/error')
const CustomError = createError('ERROR_CODE', 'message')
console.log(new CustomError())
```

## Emit Warnings
<a id="emit-warnings"></a>

If you want to deprecate an API, or you want to warn the user about a specific
use case, you can use the
[`process-warning`](https://github.com/fastify/process-warning) module.

```js
const warning = require('process-warning')()
warning.create('MyPluginWarning', 'MP_ERROR_CODE', 'message')
warning.emit('MP_ERROR_CODE')
```

## Let's start!
<a id="start"></a>

Awesome, now you know everything you need to know about Fastify and its plugin
system to start building your first plugin, and please if you do, tell us! We
will add it to the [*ecosystem*](https://github.com/fastify/fastify#ecosystem)
section of our documentation!

If you want to see some real-world examples, check out:
- [`@fastify/view`](https://github.com/fastify/point-of-view) Templates
  rendering (*ejs, pug, handlebars, marko*) plugin support for Fastify.
- [`@fastify/mongodb`](https://github.com/fastify/fastify-mongodb) Fastify
  MongoDB connection plugin, with this you can share the same MongoDB connection
  pool in every part of your server.
- [`@fastify/multipart`](https://github.com/fastify/fastify-multipart) Multipart
  support for Fastify
- [`@fastify/helmet`](https://github.com/fastify/fastify-helmet) Important
  security headers for Fastify


*Do you feel like something is missing here? Let us know! :)*