1 | <h1 align="center">Fastify</h1>
|
2 |
|
3 | ## Decorators
|
4 |
|
5 | The decorators API allows customization of the core Fastify objects, such as
|
6 | the server instance itself and any request and reply objects used during the
|
7 | HTTP request lifecycle. The decorators API can be used to attach any type of
|
8 | property to the core objects, e.g. functions, plain objects, or native types.
|
9 |
|
10 | This API is a *synchronous* API. Attempting to define a decoration
|
11 | asynchronously could result in the Fastify instance booting prior to the
|
12 | decoration completing its initialization. To avoid this issue, and register an
|
13 | asynchronous decoration, the `register` API, in combination with
|
14 | `fastify-plugin`, must be used instead. To learn more, see the
|
15 | [Plugins](Plugins.md) documentation.
|
16 |
|
17 | Decorating core objects with this API allows the underlying JavaScript engine
|
18 | to optimize handling of the server, request, and reply objects. This is
|
19 | accomplished by defining the shape of all such object instances before they are
|
20 | instantiated and used. As an example, the following is not recommended because
|
21 | it will change the shape of objects during their lifecycle:
|
22 |
|
23 | ```js
|
24 | // Bad example! Continue reading.
|
25 |
|
26 | // Attach a user property to the incoming request before the request
|
27 | // handler is invoked.
|
28 | fastify.addHook('preHandler', function (req, reply, done) {
|
29 | req.user = 'Bob Dylan'
|
30 | done()
|
31 | })
|
32 |
|
33 | // Use the attached user property in the request handler.
|
34 | fastify.get('/', function (req, reply) {
|
35 | reply.send(`Hello, ${req.user}`)
|
36 | })
|
37 | ```
|
38 |
|
39 | Since the above example mutates the request object after it has already
|
40 | been instantiated, the JavaScript engine must deoptimize access to the request
|
41 | object. By using the decoration API this deoptimization is avoided:
|
42 |
|
43 | ```js
|
44 | // Decorate request with a 'user' property
|
45 | fastify.decorateRequest('user', '')
|
46 |
|
47 | // Update our property
|
48 | fastify.addHook('preHandler', (req, reply, done) => {
|
49 | req.user = 'Bob Dylan'
|
50 | done()
|
51 | })
|
52 | // And finally access it
|
53 | fastify.get('/', (req, reply) => {
|
54 | reply.send(`Hello, ${req.user}!`)
|
55 | })
|
56 | ```
|
57 |
|
58 | See
|
59 | [JavaScript engine fundamentals: Shapes and Inline Caches](https://web.archive.org/web/20200201163000/https://mathiasbynens.be/notes/shapes-ics)
|
60 | for more information on this topic.
|
61 |
|
62 | ### Usage
|
63 | <a name="usage"></a>
|
64 |
|
65 | #### `decorate(name, value, [dependencies])`
|
66 | <a name="decorate"></a>
|
67 |
|
68 | This method is used to customize the Fastify [server](Server.md) instance.
|
69 |
|
70 | For example, to attach a new method to the server instance:
|
71 |
|
72 | ```js
|
73 | fastify.decorate('utility', function () {
|
74 | // Something very useful
|
75 | })
|
76 | ```
|
77 |
|
78 | As mentioned above, non-function values can be attached:
|
79 |
|
80 | ```js
|
81 | fastify.decorate('conf', {
|
82 | db: 'some.db',
|
83 | port: 3000
|
84 | })
|
85 | ```
|
86 |
|
87 | To access decorated properties, simply use the name provided to the
|
88 | decoration API:
|
89 |
|
90 | ```js
|
91 | fastify.utility()
|
92 |
|
93 | console.log(fastify.conf.db)
|
94 | ```
|
95 |
|
96 | The `dependencies` parameter is an optional list of decorators that the
|
97 | decorator being defined relies upon. This list is simply a list of string names
|
98 | of other decorators. In the following example, the "utility" decorator depends
|
99 | upon "greet" and "log" decorators:
|
100 |
|
101 | ```js
|
102 | fastify.decorate('utility', fn, ['greet', 'log'])
|
103 | ```
|
104 |
|
105 | If a dependency is not satisfied, the `decorate` method will throw an exception.
|
106 | The dependency check is peformed before the server instance is booted. Thus,
|
107 | it cannot occur during runtime.
|
108 |
|
109 | #### `decorateReply(name, value, [dependencies])`
|
110 | <a name="decorate-reply"></a>
|
111 |
|
112 | As the name suggests, this API is used to add new methods/properties to the core
|
113 | `Reply` object:
|
114 |
|
115 | ```js
|
116 | fastify.decorateReply('utility', function () {
|
117 | // Something very useful
|
118 | })
|
119 | ```
|
120 |
|
121 | Note: using an arrow function will break the binding of `this` to the Fastify
|
122 | `Reply` instance.
|
123 |
|
124 | See [`decorate`](#decorate) for information about the `dependencies` parameter.
|
125 |
|
126 | #### `decorateRequest(name, value, [dependencies])`
|
127 | <a name="decorate-request"></a>
|
128 |
|
129 | As above with [`decorateReply`](#decorate-reply), this API is used add new
|
130 | methods/properties to the core `Request` object:
|
131 |
|
132 | ```js
|
133 | fastify.decorateRequest('utility', function () {
|
134 | // something very useful
|
135 | })
|
136 | ```
|
137 |
|
138 | Note: using an arrow function will break the binding of `this` to the Fastify
|
139 | `Request` instance.
|
140 |
|
141 | See [`decorate`](#decorate) for information about the `dependencies` parameter.
|
142 |
|
143 | #### `hasDecorator(name)`
|
144 | <a name="has-decorator"></a>
|
145 |
|
146 | Used to check for the existence of a server instance decoration:
|
147 |
|
148 | ```js
|
149 | fastify.hasDecorator('utility')
|
150 | ```
|
151 |
|
152 | #### hasRequestDecorator
|
153 | <a name="has-request-decorator"></a>
|
154 |
|
155 | Used to check for the existence of a Request decoration:
|
156 |
|
157 | ```js
|
158 | fastify.hasRequestDecorator('utility')
|
159 | ```
|
160 |
|
161 | #### hasReplyDecorator
|
162 | <a name="has-reply-decorator"></a>
|
163 |
|
164 | Used to check for the existence of a Reply decoration:
|
165 |
|
166 | ```js
|
167 | fastify.hasReplyDecorator('utility')
|
168 | ```
|
169 |
|
170 | ### Decorators and Encapsulation
|
171 | <a name="decorators-encapsulation"></a>
|
172 |
|
173 | Defining a decorator (using `decorate`, `decorateRequest` or `decorateReply`)
|
174 | with the same name more than once in the same **encapsulated** context will
|
175 | throw an exception.
|
176 |
|
177 | As an example, the following will throw:
|
178 |
|
179 | ```js
|
180 | const server = require('fastify')()
|
181 |
|
182 | server.decorateReply('view', function (template, args) {
|
183 | // Amazing view rendering engine
|
184 | })
|
185 |
|
186 | server.get('/', (req, reply) => {
|
187 | reply.view('/index.html', { hello: 'world' })
|
188 | })
|
189 |
|
190 | // Somewhere else in our codebase, we define another
|
191 | // view decorator. This throws.
|
192 | server.decorateReply('view', function (template, args) {
|
193 | // Another rendering engine
|
194 | })
|
195 |
|
196 | server.listen(3000)
|
197 | ```
|
198 |
|
199 |
|
200 | But this will not:
|
201 |
|
202 | ```js
|
203 | const server = require('fastify')()
|
204 |
|
205 | server.decorateReply('view', function (template, args) {
|
206 | // Amazing view rendering engine.
|
207 | })
|
208 |
|
209 | server.register(async function (server, opts) {
|
210 | // We add a view decorator to the current encapsulated
|
211 | // plugin. This will not throw as outside of this encapsulated
|
212 | // plugin view is the old one, while inside it is the new one.
|
213 | server.decorateReply('view', function (template, args) {
|
214 | // Another rendering engine
|
215 | })
|
216 |
|
217 | server.get('/', (req, reply) => {
|
218 | reply.view('/index.page', { hello: 'world' })
|
219 | })
|
220 | }, { prefix: '/bar' })
|
221 |
|
222 | server.listen(3000)
|
223 | ```
|
224 |
|
225 | ### Getters and Setters
|
226 | <a name="getters-setters"></a>
|
227 |
|
228 | Decorators accept special "getter/setter" objects. These objects have functions
|
229 | named `getter` and `setter` (though, the `setter` function is optional). This
|
230 | allows defining properties via decorators. For example:
|
231 |
|
232 | ```js
|
233 | fastify.decorate('foo', {
|
234 | getter () {
|
235 | return 'a getter'
|
236 | }
|
237 | })
|
238 | ```
|
239 |
|
240 | Will define the `foo` property on the Fastify instance:
|
241 |
|
242 | ```js
|
243 | console.log(fastify.foo) // 'a getter'
|
244 | ```
|