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.
		
		
		
		
		
			
		
			
				
					196 lines
				
				5.7 KiB
			
		
		
			
		
	
	
					196 lines
				
				5.7 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								<h1 align="center">Fastify</h1>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## Encapsulation
							 | 
						||
| 
								 | 
							
								<a id="encapsulation"></a>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								A fundamental feature of Fastify is the "encapsulation context." The
							 | 
						||
| 
								 | 
							
								encapsulation context governs which [decorators](./Decorators.md), registered
							 | 
						||
| 
								 | 
							
								[hooks](./Hooks.md), and [plugins](./Plugins.md) are available to
							 | 
						||
| 
								 | 
							
								[routes](./Routes.md). A visual representation of the encapsulation context
							 | 
						||
| 
								 | 
							
								is shown in the following figure:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								In the above figure, there are several entities:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								1. The _root context_
							 | 
						||
| 
								 | 
							
								2. Three _root plugins_
							 | 
						||
| 
								 | 
							
								3. Two _child contexts_ where each _child context_ has
							 | 
						||
| 
								 | 
							
								    * Two _child plugins_
							 | 
						||
| 
								 | 
							
								    * One _grandchild context_ where each _grandchild context_ has
							 | 
						||
| 
								 | 
							
								        - Three _child plugins_
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Every _child context_ and _grandchild context_ has access to the _root plugins_.
							 | 
						||
| 
								 | 
							
								Within each _child context_, the _grandchild contexts_ have access to the
							 | 
						||
| 
								 | 
							
								_child plugins_ registered within the containing _child context_, but the
							 | 
						||
| 
								 | 
							
								containing _child context_ **does not** have access to the _child plugins_
							 | 
						||
| 
								 | 
							
								registered within its _grandchild context_.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Given that everything in Fastify is a [plugin](./Plugins.md), except for the
							 | 
						||
| 
								 | 
							
								_root context_, every "context" and "plugin" in this example is a plugin
							 | 
						||
| 
								 | 
							
								that can consist of decorators, hooks, plugins, and routes. Thus, to put
							 | 
						||
| 
								 | 
							
								this example into concrete terms, consider a basic scenario of a REST API
							 | 
						||
| 
								 | 
							
								server that has three routes: the first route (`/one`) requires authentication,
							 | 
						||
| 
								 | 
							
								the second route (`/two`) does not, and the third route (`/three`) has
							 | 
						||
| 
								 | 
							
								access to the same context as the second route. Using
							 | 
						||
| 
								 | 
							
								[@fastify/bearer-auth][bearer] to provide the authentication, the code for this
							 | 
						||
| 
								 | 
							
								example is as follows:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								'use strict'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const fastify = require('fastify')()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								fastify.decorateRequest('answer', 42)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								fastify.register(async function authenticatedContext (childServer) {
							 | 
						||
| 
								 | 
							
								  childServer.register(require('@fastify/bearer-auth'), { keys: ['abc123'] })
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  childServer.route({
							 | 
						||
| 
								 | 
							
								    path: '/one',
							 | 
						||
| 
								 | 
							
								    method: 'GET',
							 | 
						||
| 
								 | 
							
								    handler (request, response) {
							 | 
						||
| 
								 | 
							
								      response.send({
							 | 
						||
| 
								 | 
							
								        answer: request.answer,
							 | 
						||
| 
								 | 
							
								        // request.foo will be undefined as it's only defined in publicContext
							 | 
						||
| 
								 | 
							
								        foo: request.foo,
							 | 
						||
| 
								 | 
							
								        // request.bar will be undefined as it's only defined in grandchildContext
							 | 
						||
| 
								 | 
							
								        bar: request.bar
							 | 
						||
| 
								 | 
							
								      })
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  })
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								fastify.register(async function publicContext (childServer) {
							 | 
						||
| 
								 | 
							
								  childServer.decorateRequest('foo', 'foo')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  childServer.route({
							 | 
						||
| 
								 | 
							
								    path: '/two',
							 | 
						||
| 
								 | 
							
								    method: 'GET',
							 | 
						||
| 
								 | 
							
								    handler (request, response) {
							 | 
						||
| 
								 | 
							
								      response.send({
							 | 
						||
| 
								 | 
							
								        answer: request.answer,
							 | 
						||
| 
								 | 
							
								        foo: request.foo,
							 | 
						||
| 
								 | 
							
								        // request.bar will be undefined as it's only defined in grandchildContext
							 | 
						||
| 
								 | 
							
								        bar: request.bar
							 | 
						||
| 
								 | 
							
								      })
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  })
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  childServer.register(async function grandchildContext (grandchildServer) {
							 | 
						||
| 
								 | 
							
								    grandchildServer.decorateRequest('bar', 'bar')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    grandchildServer.route({
							 | 
						||
| 
								 | 
							
								      path: '/three',
							 | 
						||
| 
								 | 
							
								      method: 'GET',
							 | 
						||
| 
								 | 
							
								      handler (request, response) {
							 | 
						||
| 
								 | 
							
								        response.send({
							 | 
						||
| 
								 | 
							
								          answer: request.answer,
							 | 
						||
| 
								 | 
							
								          foo: request.foo,
							 | 
						||
| 
								 | 
							
								          bar: request.bar
							 | 
						||
| 
								 | 
							
								        })
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								  })
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								fastify.listen(8000)
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								The above server example shows all of the encapsulation concepts outlined in the
							 | 
						||
| 
								 | 
							
								original diagram:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								1. Each _child context_ (`authenticatedContext`, `publicContext`, and
							 | 
						||
| 
								 | 
							
								`grandchildContext`) has access to the `answer` request decorator defined in
							 | 
						||
| 
								 | 
							
								the _root context_.
							 | 
						||
| 
								 | 
							
								2. Only the `authenticatedContext` has access to the `@fastify/bearer-auth`
							 | 
						||
| 
								 | 
							
								plugin.
							 | 
						||
| 
								 | 
							
								3. Both the `publicContext` and `grandchildContext` have access to the `foo`
							 | 
						||
| 
								 | 
							
								request decorator.
							 | 
						||
| 
								 | 
							
								4. Only the `grandchildContext` has access to the `bar` request decorator.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								To see this, start the server and issue requests:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```sh
							 | 
						||
| 
								 | 
							
								# curl -H 'authorization: Bearer abc123' http://127.0.0.1:8000/one
							 | 
						||
| 
								 | 
							
								{"answer":42}
							 | 
						||
| 
								 | 
							
								# curl http://127.0.0.1:8000/two
							 | 
						||
| 
								 | 
							
								{"answer":42,"foo":"foo"}
							 | 
						||
| 
								 | 
							
								# curl http://127.0.0.1:8000/three
							 | 
						||
| 
								 | 
							
								{"answer":42,"foo":"foo","bar":"bar"}
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[bearer]: https://github.com/fastify/fastify-bearer-auth
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								## Sharing Between Contexts
							 | 
						||
| 
								 | 
							
								<a id="shared-context"></a>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Notice that each context in the prior example inherits _only_ from the parent
							 | 
						||
| 
								 | 
							
								contexts. Parent contexts cannot access any entities within their descendent
							 | 
						||
| 
								 | 
							
								contexts. This default is occasionally not desired. In such cases, the
							 | 
						||
| 
								 | 
							
								encapsulation context can be broken through the usage of
							 | 
						||
| 
								 | 
							
								[fastify-plugin][fastify-plugin] such that anything registered in a descendent
							 | 
						||
| 
								 | 
							
								context is available to the containing parent context.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Assuming the `publicContext` needs access to the `bar` decorator defined
							 | 
						||
| 
								 | 
							
								within the `grandchildContext` in the previous example, the code can be
							 | 
						||
| 
								 | 
							
								rewritten to:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```js
							 | 
						||
| 
								 | 
							
								'use strict'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const fastify = require('fastify')()
							 | 
						||
| 
								 | 
							
								const fastifyPlugin = require('fastify-plugin')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								fastify.decorateRequest('answer', 42)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// `authenticatedContext` omitted for clarity
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								fastify.register(async function publicContext (childServer) {
							 | 
						||
| 
								 | 
							
								  childServer.decorateRequest('foo', 'foo')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  childServer.route({
							 | 
						||
| 
								 | 
							
								    path: '/two',
							 | 
						||
| 
								 | 
							
								    method: 'GET',
							 | 
						||
| 
								 | 
							
								    handler (request, response) {
							 | 
						||
| 
								 | 
							
								      response.send({
							 | 
						||
| 
								 | 
							
								        answer: request.answer,
							 | 
						||
| 
								 | 
							
								        foo: request.foo,
							 | 
						||
| 
								 | 
							
								        bar: request.bar
							 | 
						||
| 
								 | 
							
								      })
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  })
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  childServer.register(fastifyPlugin(grandchildContext))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  async function grandchildContext (grandchildServer) {
							 | 
						||
| 
								 | 
							
								    grandchildServer.decorateRequest('bar', 'bar')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    grandchildServer.route({
							 | 
						||
| 
								 | 
							
								      path: '/three',
							 | 
						||
| 
								 | 
							
								      method: 'GET',
							 | 
						||
| 
								 | 
							
								      handler (request, response) {
							 | 
						||
| 
								 | 
							
								        response.send({
							 | 
						||
| 
								 | 
							
								          answer: request.answer,
							 | 
						||
| 
								 | 
							
								          foo: request.foo,
							 | 
						||
| 
								 | 
							
								          bar: request.bar
							 | 
						||
| 
								 | 
							
								        })
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								fastify.listen(8000)
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Restarting the server and re-issuing the requests for `/two` and `/three`:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								```sh
							 | 
						||
| 
								 | 
							
								# curl http://127.0.0.1:8000/two
							 | 
						||
| 
								 | 
							
								{"answer":42,"foo":"foo","bar":"bar"}
							 | 
						||
| 
								 | 
							
								# curl http://127.0.0.1:8000/three
							 | 
						||
| 
								 | 
							
								{"answer":42,"foo":"foo","bar":"bar"}
							 | 
						||
| 
								 | 
							
								```
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[fastify-plugin]: https://github.com/fastify/fastify-plugin
							 |