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 |