Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: component migration - general aspects #5262

Merged
merged 1 commit into from
May 5, 2020
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
47 changes: 47 additions & 0 deletions docs/site/migration/components/current-context.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
lang: en
title: 'Migrating access to current context'
keywords: LoopBack 4, LoopBack 3, Migration, Extensions, Components
sidebar: lb4_sidebar
permalink: /doc/en/lb4/migration-extensions-current-context.html
---

{% include tip.html content="
Missing instructions for your LoopBack 3 use case? Please report a [Migration docs issue](https://github.com/strongloop/loopback-next/issues/new?labels=question,Migration,Docs&template=Migration_docs.md) on GitHub to let us know.
" %}

It's often desirable to share contextual data between different parts of an
application. For example, a REST connector calling a backend web service may
want to forward transaction (correlation) id provided in a HTTP header of the
incoming request, or perhaps an auditing component wants to access the
information about the user making the request to store it in the log.

LoopBack 3 offers three approaches:

1. The recommended solution is to explicitly pass any contextual information via
`options` argument. Most LoopBack APIs accept (and forward) this argument and
there are means how to initialize the `options` value based on the incoming
request.

2. Code working at REST layer can access and store contextual information on the
HTTP request object.

3. An experimental component
[`loopback-context`](https://github.com/strongloop/loopback-context) uses
continuation-local-storage to provide static per-request storage that can be
accessed from anywhere inside a LoopBack application (an Express middleware,
a model method, a connector, etc.).

In LoopBack 4, extensions should use `@inject` decorators to access contextual
information. For example:

- `@inject(key)` and `@inject.getter(key)` to receive values from the context
- `@inject.setter(key)` to obtain a setter function for writing values to the
context
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should mention that TRANSIENT scope should be used for such bindings in order to receive per-request contextual data.


To keep the contextual data per-request (as opposed to per-application), the
`TRANSIENT` binding scope should be used.

Components can keep using the old `options`-based approach where it makes more
sense than Dependency Injection, typically when working with existing
`options`-based code like Repository APIs.
48 changes: 48 additions & 0 deletions docs/site/migration/components/mixins.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
lang: en
title: 'Migrating components contributing Model mixins'
keywords: LoopBack 4, LoopBack 3, Migration, Extensions, Components, Mixins
sidebar: lb4_sidebar
permalink: /doc/en/lb4/migration-extensions-mixins.html
---

{% include tip.html content="
Missing instructions for your LoopBack 3 use case? Please report a [Migration docs issue](https://github.com/strongloop/loopback-next/issues/new?labels=question,Migration,Docs&template=Migration_docs.md) on GitHub to let us know.
" %}

In LoopBack 3, a component contributes mixins by providing files exporting mixin
functions, for example:

```js
// lib/my-mixin.js
module.exports = myMixin(Model, options) {
// modify the target model provided in `Model`
// apply configuration as specified in `options`
};
```

In LoopBack 4, models are architecturally decoupled into 3 entities (a model, a
repository and a controller), as further explained in
[Migrating models](../models/overview.md) and
[Migrating custom model methods](../models/methods.md). As a result, most
LoopBack 3 mixins become a set of multiple mixins in LoopBack 4.

To migrate a mixin from a LoopBack 3 component to a LoopBack 4 component:

1. Follow the steps described in
[Migrating model mixins ](https://loopback.io/doc/en/lb4/migration-models-mixins.html)
to convert your mixin implementation to LB4 style. We recommend to put the
new files to `src/mixins` directory in your LB4 component project.

2. Modify your LB4 component to export the mixins - add `export` statements to
components `src/index.ts` file. For example:

```ts
// src/index.ts
export * from './mixins/my-mixin';
```

3. Update your documentation to show how to apply the new mixins in LoopBack 4
applications, use the content provided in
[Migrating model mixins ](https://loopback.io/doc/en/lb4/migration-models-mixins.html)
for inspiration.
79 changes: 79 additions & 0 deletions docs/site/migration/components/overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
---
lang: en
title: 'Migrating components and extensions'
keywords: LoopBack 4, LoopBack 3, Migration, Extensions, Components
sidebar: lb4_sidebar
permalink: /doc/en/lb4/migration-extensions-overview.html
redirect_from: /doc/en/lb4/migration-extensions.html
---

{% include tip.html content="
Missing instructions for your LoopBack 3 use case? Please report a [Migration docs issue](https://github.com/strongloop/loopback-next/issues/new?labels=question,Migration,Docs&template=Migration_docs.md) on GitHub to let us know.
" %}

{% include note.html content="
This is a placeholder page, the task of adding content is tracked by the
following GitHub issue:
[loopback-next#3955](https://github.com/strongloop/loopback-next/issues/3955)
" %}

In LoopBack 3, a component is essentially a function that extends and/or patches
the target application.

LoopBack 3 components can contribute:

- additional models
- new REST API endpoints (Express routes)
- mixin to be used by application models

They can also modify application's models to

- register new
[Operation Hooks](https://loopback.io/doc/en/lb3/Operation-hooks.html)
- register new [Remote Hooks](https://loopback.io/doc/en/lb3/Remote-hooks.html)
- define new relations

In LoopBack 4, a component is typically a class providing artifacts it wants to
contribute to the application. It is responsibility of the target application to
import those artifacts.

LoopBack 4 components can contribute:

- [Model and Entity classes](../../Model.md)
- [Mixins](../../Mixin.md)
- [Decorators](../../Creating-decorators.md)
- [Sequence Actions](../../Sequence.md#actions)
- [Controllers](../../Controllers.md)
- [Life cycle observers](../../Extension-life-cycle.md)
- [Repositories](../../Repositories.md)
- [Service proxies](../../Calling-other-APIs-and-Web-Services.md)
- [Servers](../../Creating-servers.md)
- [HTTP request parsers](../../Extending-request-body-parsing.md)
- Extensions for [Extension Points](../../Extension-point-and-extensions.md)
- [Booters](../../Booting-an-Application.md#custom-booters)
- [Model API builders](../../Extending-Model-API-builder.md)
- Extensions for Extension Points defined by 3rd-party component
- Any other values to be bound in `Application`'s context:
- [Classes](../../Binding.md#a-class)
- [Providers](../../Binding.md#a-provider)
- [Arbitrary bindings](../../Binding.md) (instances of `Binding` class)

As the last resort, LoopBack 4 components can also modify the target application
directly by calling `Application` APIs (this is similar to LoopBack 3 approach).

To make the migration guide easier to navigate, we split component-related
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should mention #5304 and give an example to show how to use an application as a component to allow boot artifacts from a sub-application.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am afraid I don't see how the booter for loading artifacts from a sub-application is related to migrating LB3 extensions to LB4? Can you @raymondfeng please open a follow-up issue to describe in more detail what are you looking for?

instructions into several sub-sections.

1. [Migrating component project layout](./project-layout.md) describes how to
migrate your LoopBack 3 extension project infrastructure to LoopBack 4 style
and how to update the instructions for using your component.

1. [Migrating access to current context](./current-context.md) describes how to
migrate code accessing contextual information shared by different parts of a
LoopBack application.

1. [Migrating components contributing Model mixins](./mixins) explains how to
migrate a component that's contributing Model mixins.

1. _More sections will be created as part of
[loopback-next#3955](https://github.com/strongloop/loopback-next/issues/3955)._
116 changes: 116 additions & 0 deletions docs/site/migration/components/project-layout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
---
lang: en
title: 'Migrating component project layout'
keywords: LoopBack 4, LoopBack 3, Migration, Extensions, Components
sidebar: lb4_sidebar
permalink: /doc/en/lb4/migration-extensions-project-layout.html
---

{% include tip.html content="
Missing instructions for your LoopBack 3 use case? Please report a [Migration docs issue](https://github.com/strongloop/loopback-next/issues/new?labels=question,Migration,Docs&template=Migration_docs.md) on GitHub to let us know.
" %}

The first step on the component migration journey is to reorganize the project
files, change component's entry point and documentation for adding the component
to the target application.

## LoopBack 3 component layout & mounting

A LB3 component is implemented as a function accepting the target app object and
the configuration options.

A minimal component consists of a single `index.js` file with the following
content:

```ts
module.exports = function initializeComponent(loopbackApplication, options) {
// implementation
};
```

A component is typically added to a LB3 application by creating a new entry in
`server/component-config.json`, see
[LoopBack components](https://loopback.io/doc/en/lb3/LoopBack-components.html).

For example:

```json
{
"loopback-explorer": {
"mountPath": "/explorer"
}
}
```

This allows the component to receive configuration. App developers can provide
environment-specific configuration by using `component-config.{env}.json` files.

## LoopBack 4 layout

As explained in [Creating components](../../Creating-Components.md) and
[Using components](../../Using-components.md), a typical LoopBack 4 component is
an npm package exporting a Component class.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should recommend lb4 extension command to scaffold a package to expose components.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The component class is usually implemented inside
`src/{component-name}.component.ts` file, for example
[src/metrics.component.ts](https://github.com/strongloop/loopback-next/blob/38f10b240551227d2d030c2fe8ee206880c9e029/extensions/metrics/src/metrics.component.ts):

```ts
import {Application, Component, CoreBindings} from '@loopback/core';
import {bind, config, ContextTags, inject} from '@loopback/context';
import {MetricsBindings} from './keys';
import {DEFAULT_METRICS_OPTIONS, MetricsOptions} from './types';

@bind({tags: {[ContextTags.KEY]: MetricsBindings.COMPONENT}})
export class MetricsComponent implements Component {
constructor(
@inject(CoreBindings.APPLICATION_INSTANCE)
private application: Application,
@config()
options: MetricsOptions = DEFAULT_METRICS_OPTIONS,
) {
// ...
}
// ...
}
```

The code snippet above also shows how a LoopBack 4 component can receive
configuration and the target application object.

## Usage instructions

LoopBack 4 components are added to applications inside application constructor.

First, the application file needs to import the component class:

```ts
import {MetricsComponent} from '@loopback/extension-metrics';
```

Then in the constructor, add the component to your application:

```ts
this.component(MetricsComponent);
```

Finally, the application can configure the component by adding the following
code to its constructor:

```ts
this.configure(MetricsBindings.COMPONENT).to({
// the configuration
});
```

## Migration steps

It is not feasible to migrate a LoopBack 3 component project to a LoopBack 4
component project in a series of incremental changes done within the same
repository. We recommend to create a new project using
[`lb4 extension`](../../Extension-generator.md) CLI command and then
incrementally migrate artifacts from the original LoopBack 3 component to the
new project.

{% include note.html content="The extension project template used by `lb4 extension` is a bit outdated now, please refer to [loopback-next#5336](https://github.com/strongloop/loopback-next/issues/5336) for more details.
" %}
17 changes: 0 additions & 17 deletions docs/site/migration/extensions.md

This file was deleted.

17 changes: 15 additions & 2 deletions docs/site/sidebars/lb4_sidebar.yml
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ children:
url: Access-databases.html
output: 'web, pdf'
children:

- title: 'Working with data'
url: Working-with-data.html
output: 'web, pdf'
Expand Down Expand Up @@ -864,8 +864,21 @@ children:
output: 'web, pdf'

- title: 'Components and extensions'
url: migration-extensions.html
url: migration-extensions-overview.html
output: 'web, pdf'
children:

- title: 'Project layout'
url: migration-extensions-project-layout.html
output: 'web, pdf'

- title: 'Current context'
url: migration-extensions-current-context.html
output: 'web, pdf'

- title: 'Mixins'
url: migration-extensions-mixins.html
output: 'web, pdf'

- title: 'Clients (API consumers)'
url: migration-clients.html
Expand Down
Loading