Skip to content

Commit

Permalink
feat(context): add @inject.binding and improve @inject.setter
Browse files Browse the repository at this point in the history
1. The decorators now allow binding creation policy control
2. `@inject.binding` can be used to resolve/configure a binding
  • Loading branch information
raymondfeng committed Apr 12, 2019
1 parent 1ba70b7 commit a396274
Show file tree
Hide file tree
Showing 9 changed files with 549 additions and 50 deletions.
78 changes: 77 additions & 1 deletion docs/site/Decorators_inject.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,19 @@ class MyControllerWithGetter {

`@inject.setter` injects a setter function to set the bound value of the key.

Syntax: `@inject.setter(bindingKey: string)`.
Syntax: `@inject.setter(bindingKey: BindingAddress, {bindingCreation?: ...})`.

The `setter` function injected has the following signature:

```ts
export type Setter<T> = (value?: T) => void;
```

The binding resolution/creation is controlled by `bindingCreation` option. See
[@inject.binding](#injectbinding) for possible settings.

The following example shows the usage of `@inject.setter` and the injected
setter function.

```ts
export class HelloController {
Expand All @@ -143,6 +155,70 @@ export class HelloController {
}
```

Please note the setter function simply binds a `value` to the underlying binding
using `binding.to(value)`.

To set other types of value providers such as `toDynamicValue`or `toClass`, use
`@inject.binding` instead.

### @inject.binding

`@inject.binding` injects a binding for the given key. It can be used to bind
various types of value providers to the underlying binding or configure the
binding. This is an advanced form of `@inject.setter`, which only allows to set
a constant value (using `Binding.to(value)` behind the scene) to the underlying
binding.

Syntax: `@inject.binding(bindingKey: BindingAddress, {bindingCreation?: ...})`.

```ts
export class HelloController {
constructor(
@inject.binding('greeting') private greetingBinding: Binding<string>,
) {}

@get('/hello')
async greet() {
// Bind `greeting` to a factory function that reads default greeting
// from a file or database
this.greetingBinding.toDynamicValue(() => readDefaultGreeting());
return await this.greetingBinding.get<string>(this.greetingBinding.key);
}
}
```

The `@inject.binding` takes an optional `metadata` object which can contain
`bindingCreation` to control how underlying binding is resolved or created based
on the following values:

```ts
/**
* Policy to control if a binding should be created for the context
*/
export enum BindingCreationPolicy {
/**
* Always create a binding with the key for the context
*/
ALWAYS_CREATE = 'Always',
/**
* Never create a binding for the context. If the key is not bound in the
* context, throw an error.
*/
NEVER_CREATE = 'Never',
/**
* Create a binding if the key is not bound in the context. Otherwise, return
* the existing binding.
*/
CREATE_IF_NOT_BOUND = 'IfNotBound',
}
```

For example:

```ts
@inject.setter('binding-key', {bindingCreation: BindingCreationPolicy.NEVER_CREATES})
```

### @inject.tag

`@inject.tag` injects an array of values by a pattern or regexp to match binding
Expand Down
1 change: 1 addition & 0 deletions docs/site/Dependency-injection.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ There are a few special decorators from the `inject` namespace.

- [`@inject.getter`](Decorators_inject.md#@inject.getter)
- [`@inject.setter`](Decorators_inject.md#@inject.setter)
- [`@inject.binding`](Decorators_inject.md#@inject.binding)
- [`@inject.context`](Decorators_inject.md#@inject.context)
- [`@inject.tag`](Decorators_inject.md#@inject.tag)
- [`@inject.view`](Decorators_inject.md#@inject.view)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

import {expect} from '@loopback/testlab';
import {Context, instantiateClass} from '@loopback/context';
import {Request} from '@loopback/rest';
import {AuthenticateFn, UserProfile, AuthenticationBindings} from '../../..';
import {MockStrategy} from '../fixtures/mock-strategy';
import {expect} from '@loopback/testlab';
import {Strategy} from 'passport';
import {AuthenticateFn, AuthenticationBindings, UserProfile} from '../../..';
import {AuthenticateActionProvider} from '../../../providers';
import {MockStrategy} from '../fixtures/mock-strategy';

describe('AuthenticateActionProvider', () => {
describe('constructor()', () => {
Expand Down
Loading

0 comments on commit a396274

Please sign in to comment.