Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ node('linux && git') {
}
stage('download updates') {
sh './update-readmes.sh'
sh './update-v4-readmes.sh'
sh './update-community-readmes.sh'
}
stage('check updates') {
Expand All @@ -25,6 +26,7 @@ node('linux && git') {
// existing files will have to be done by a human for now.
sh 'git add pages/en/lb2/readmes'
sh 'git add pages/en/lb3/readmes'
sh 'git add pages/en/lb4/readmes'
sh 'git add pages/en/community/readmes'
withEnv(gitEnv) {
sh 'git commit -m "Update READMEs from other repos"'
Expand Down
4 changes: 4 additions & 0 deletions _data/sidebars/lb4_sidebar.yml
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@ children:
url: Creating-components.html
output: 'web, pdf'

- title: 'Creating Decorators'
url: Creating-decorators.html
output: 'web, pdf'

- title: 'Testing your extension'
url: Testing-your-extension.html
output: 'web, pdf'
Expand Down
17 changes: 10 additions & 7 deletions pages/en/lb4/Context.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,14 +177,17 @@ up. For example, let's take the previous example and make it available on the
`GET /greet` route using decorators provided by
[`@loopback/rest`](https://github.com/strongloop/loopback-next/blob/master/packages/rest):

```js
```ts
class HelloController {
@get('/greet') // tell LoopBack you want this controller method
// to be available at the GET /greet route
@param.query.string('name') // tell LoopBack you want to accept
// the name parameter as a string from
// the query string
greet(name) {
// tell LoopBack you want this controller method
// to be available at the GET /greet route
@get('/greet')
greet(
// tell LoopBack you want to accept
// the name parameter as a string from
// the query string
@param.query.string('name')
name: string) {
return `Hello ${name}`;
}
}
Expand Down
11 changes: 11 additions & 0 deletions pages/en/lb4/Creating-decorators.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
lang: en
title: 'Creating decorators'
keywords: LoopBack 4.0, LoopBack 4
layout: readme
source: metadata
tags:
sidebar: lb4_sidebar
permalink: /doc/en/lb4/Creating-decorators.html
summary: A tutorial to use `@loopback/metadata` module to create new decorators
---
57 changes: 57 additions & 0 deletions pages/en/lb4/Decorators.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,63 @@ class WidgetController {
}
```

A few variants of `@inject` are provided to declare special forms of dependencies:

- `@inject.getter`: inject a getter function that returns a promise of the bound value of the key

Syntax: `@inject.getter(bindingKey: string)`.

```ts
class HelloController {
constructor(
@inject.getter('authentication.currentUser')
private userGetter: Getter<UserProfile>) {}

async greet() {
const user = await this.userGetter();
return `Hello, ${user.name}`;
}
}
```

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

Syntax: `@inject.setter(bindingKey: string)`.

```ts
class HelloController {
constructor(
@inject.setter('greeting')
private greetingSetter: Setter<string>) {}

greet() {
greetingSetter('my-greeting-message');
}
}
```

- `@inject.tag`: inject an array of values by a pattern or regexp to match bindng tags

Syntax: `@inject.tag(tag: string | RegExp)`.

```ts
class Store {
constructor(@inject.tag('store:location') public locations: string[]) {}
}

ctx.bind('store').toClass(Store);
ctx
.bind('store.locations.sf')
.to('San Francisco')
.tag('store:location');
ctx
.bind('store.locations.sj')
.to('San Jose')
.tag('store:location');
const store: Store = ctx.getSync('store');
// `store.locations` is now `['San Francisco', 'San Jose']`
```

For more information, see the [Dependency Injection](Dependency-Injection.htm) section under [LoopBack Core Concepts](Concepts.htm)

## Authentication Decorator
Expand Down
43 changes: 41 additions & 2 deletions pages/en/lb4/Dependency-Injection.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Dependency Injection makes the code easier to extend and customize, because the

## Configuring what to inject

Now that we wrote a class that gets the dependencies injected, you are probably wondering where are these values going to be injected from and how to configure what should be injected. This part is typically handled by an IoC Container, where IoC means [Inversion of Control](https://en.wikipedia.org/wiki/Inversion_of_control).
Now that we write a class that gets the dependencies injected, you are probably wondering where are these values going to be injected from and how to configure what should be injected. This part is typically handled by an IoC Container, where IoC means [Inversion of Control](https://en.wikipedia.org/wiki/Inversion_of_control).

In LoopBack, we use [Context](Context.html) to keep track of all injectable dependencies.

Expand Down Expand Up @@ -86,10 +86,11 @@ const authenticate = await app.get('authentication.provider');
You can learn more about Providers in [Creating Components](Creating-components.html).
## Flavors of Dependency Injection

LoopBack supports two kinds of dependency injection:
LoopBack supports three kinds of dependency injection:

1. constructor injection: the dependencies are provided as arguments of the class constructor.
2. property injection: the dependencies are stored in instance properties after the class was constructed.
3. method injection: the dependencies are provided as arguments of a method invocation. Please note that constructor injection is a special form of method injection to instantiate a class by calling its constructor.

### Constructor injection

Expand Down Expand Up @@ -126,6 +127,44 @@ class InfoController {
}
```

### Method injection

Method injection allows injection of dependencies at method invocation level. The parameters are decorated
with `@inject` or other variants to declare dependencies as method arguments.

```ts
class InfoController {

greet(@inject('authentication.currentUser') user: UserProfile) {
return `Hello, ${userProfile.name}`;
}
}
```

## Circular dependencies

LoopBack can detect circular dependencies and report the path which leads to the problem.
For example,

```ts
const context = new Context();
interface XInterface {}
interface YInterface {}

class XClass implements XInterface {
@inject('y') public y: YInterface;
}

class YClass implements YInterface {
@inject('x') public x: XInterface;
}

context.bind('x').toClass(XClass);
context.bind('y').toClass(YClass);
// An error will be thrown below - Circular dependency detected on path 'x --> y --> x'
const x: XInterface = context.getSync('x');
```

## Additional resources

- [Dependency Injection](https://en.wikipedia.org/wiki/Dependency_injection) on Wikipedia
Expand Down
Loading