diff --git a/packages/docs/services/inversify-site/docs/api/container.mdx b/packages/docs/services/inversify-site/docs/api/container.mdx index e8500fe9..e88e7152 100644 --- a/packages/docs/services/inversify-site/docs/api/container.mdx +++ b/packages/docs/services/inversify-site/docs/api/container.mdx @@ -91,7 +91,7 @@ Creates a new Container containing the bindings ( cloned bindings ) of two or mo applyCustomMetadataReader(metadataReader: interfaces.MetadataReader): void; ``` -Sets a custom metadata reader. See [middleware](https://github.com/inversify/InversifyJS/blob/master/wiki/middleware.md). +Sets a custom metadata reader. See [middleware](/docs/fundamentals/lifecycle/middleware). ## applyMiddleware @@ -99,7 +99,7 @@ Sets a custom metadata reader. See [middleware](https://github.com/inversify/Inv applyMiddleware(...middleware: interfaces.Middleware[]): void; ``` -An advanced feature that can be used for cross cutting concerns. See [middleware](https://github.com/inversify/InversifyJS/blob/master/wiki/middleware.md). +An advanced feature that can be used for cross cutting concerns. See [middleware](/docs/fundamentals/lifecycle/middleware). ## bind @@ -115,7 +115,7 @@ Sets a new binding. createChild(containerOptions?: interfaces.ContainerOptions): Container; ``` -Create a [container hierarchy](https://github.com/inversify/InversifyJS/blob/master/wiki/hierarchical_di.md). Parent `ContainerOptions` are provided by default. +Create a [container hierarchy](/docs/fundamentals/di-hierarchy). Parent `ContainerOptions` are provided by default. ## get diff --git a/packages/docs/services/inversify-site/docs/fundamentals/inheritance.mdx b/packages/docs/services/inversify-site/docs/fundamentals/inheritance.mdx index a8c0ad3a..01fe4335 100644 --- a/packages/docs/services/inversify-site/docs/fundamentals/inheritance.mdx +++ b/packages/docs/services/inversify-site/docs/fundamentals/inheritance.mdx @@ -14,17 +14,17 @@ Inheritance can be accomplished as long as constructor parameters are properly d ```ts @injectable() class Warrior { - public rank: string; - constructor(rank: string) { // args count = 1 - this.rank = rank; - } + public rank: string; + constructor(rank: string) { // args count = 1 + this.rank = rank; + } } @injectable() class SamuraiMaster extends Warrior { - constructor() { // args count = 0 - super("master"); - } + constructor() { // args count = 0 + super("master"); + } } ``` @@ -33,3 +33,20 @@ When trying to get a `SamuraiMaster`, the container throws an Error alerting the ## Using @unmanaged decorator The [unmanaged](/docs/api/decorator#unmanaged) decorator is a good way to tell inversify a base type constructor param is should not be managed. This is often the case when dealing with inheritance hierarchies in which only leaf types are injected. + +```ts +@injectable() +class Warrior { + public rank: string; + constructor(@unmanaged() rank: string) { // args count = 0, unmanaged args are not included + this.rank = rank; + } +} + +@injectable() +class SamuraiMaster extends Warrior { + constructor() { // args count = 0 + super("master"); + } +} +``` diff --git a/packages/docs/services/inversify-site/docs/fundamentals/lifecycle/middleware.mdx b/packages/docs/services/inversify-site/docs/fundamentals/lifecycle/middleware.mdx new file mode 100644 index 00000000..8891a393 --- /dev/null +++ b/packages/docs/services/inversify-site/docs/fundamentals/lifecycle/middleware.mdx @@ -0,0 +1,157 @@ +--- +sidebar_position: 3 +title: Middleware +--- +# Middleware + +:::warning + +Middleware docs are included for historical reasons. They are likely to be remove in favor of more appropiate features. + +::: + +Middlewares can be added to a container in order to intercept service resolution requests: + +## Basic middleware + +```ts +import { interfaces, Container } from "inversify"; + +function logger(planAndResolve: interfaces.Next): interfaces.Next { + return (args: interfaces.NextArgs) => { + let start = new Date().getTime(); + let result = planAndResolve(args); + let end = new Date().getTime(); + console.log(`wooooo ${end - start}`); + return result; + }; +} + +let container = new Container(); +container.applyMiddleware(logger); +``` + +## Multiple middleware functions + +When multiple middleware functions are applied: + +```ts +container.applyMiddleware(middleware1, middleware2); +``` + +The middleware will be invoked from right to left. +This means that `middleware2` is invoked before `middleware1`. + +## Context interceptor + +In some cases you may want to intercept the resolution plan. + +The default `contextInterceptor` is passed to the middleware as an property of `args`. + +```ts +function middleware1(planAndResolve: interfaces.Next): interfaces.Next { + return (args: interfaces.NextArgs) => { + // args.nextContextInterceptor + // ... + }; +} +``` + +You can extend the default `contextInterceptor` using a function: + +```ts +function middleware1(planAndResolve: interfaces.Next): interfaces.Next { + return (args: interfaces.NextArgs) => { + let nextContextInterceptor = args.contextInterceptor; + args.contextInterceptor = (context: interfaces.Context) => { + console.log(context); + return nextContextInterceptor(context); + }; + return planAndResolve(args); + }; +} +``` + +## Custom metadata reader + +:::danger + +It is not recommended to create your own custom +metadata reader. We have included this feature to allow library / framework creators +to have a higher level of customization but the average user should not use a custom +metadata reader. In general, a custom metadata reader should only be used when +developing a framework in order to provide users with an annotation APIs +less explicit than the default annotation API. + +If you are developing a framework or library and you create a custom metadata reader, +Please remember to provide your framework with support for an alternative for all the +decorators in the default API: `@injectable`, `@inject`, `@multiInject`, `@tagged`, +`@named`, `@optional`, `@postConstruct`, `@preDestroy` `@targetName` & `@unmanaged`. + +::: + +Middleware allows you to intercept a plan and resolve it but you are not allowed to change the way the annotation phase behaves. + +There is a second extension point that allows you to decide what kind of annotation +system you would like to use. The default annotation system is powered by decorators and +reflect-metadata: + +```ts +@injectable() +class Ninja implements Ninja { + + private _katana: Katana; + private _shuriken: Shuriken; + + constructor( + @inject("Katana") katana: Katana, + @inject("Shuriken") shuriken: Shuriken + ) { + this._katana = katana; + this._shuriken = shuriken; + } + + public fight() { return this._katana.hit(); }; + public sneak() { return this._shuriken.throw(); }; + +} +``` + +You can use a custom metadata reader to implement a custom annotation system. + +For example, you could implement an annotation system based on static properties: + +```ts +class Ninja implements Ninja { + + public static constructorInjections = [ + "Katana", "Shuriken" + ]; + + private _katana: Katana; + private _shuriken: Shuriken; + + constructor( + katana: Katana, + shuriken: Shuriken + ) { + this._katana = katana; + this._shuriken = shuriken; + } + + public fight() { return this._katana.hit(); }; + public sneak() { return this._shuriken.throw(); }; + +} +``` + +A custom metadata reader must implement the `interfaces.MetadataReader` interface. + +A full example [can be found in our unit tests](https://github.com/inversify/InversifyJS/blob/master/test/features/metadata_reader.test.ts). + +Once you have a custom metadata reader you will be ready to apply it: + +```ts +let container = new Container(); +container.applyCustomMetadataReader(new StaticPropsMetadataReader()); +```