Skip to content

Commit

Permalink
Merge f995e94 into 70af13a
Browse files Browse the repository at this point in the history
  • Loading branch information
hacksparrow committed Dec 10, 2019
2 parents 70af13a + f995e94 commit 88a24ac
Show file tree
Hide file tree
Showing 16 changed files with 383 additions and 101 deletions.
23 changes: 18 additions & 5 deletions docs/site/migration/express-middleware.md
Expand Up @@ -6,8 +6,21 @@ sidebar: lb4_sidebar
permalink: /doc/en/lb4/migration-express-middleware.html
---

{% include note.html content="
This is a placeholder page, the task of adding content is tracked by the
following GitHub issue:
[loopback-next#3947](https://github.com/strongloop/loopback-next/issues/3947)
" %}
Migrating Express middleware from LoopBack 3 (LB3) application to LoopBack 4
(LB4) application requires the use of a base Express application that will mount
the LB4 application, which in turn mounts the LB3 application.

The base Express application presents the mounting point for the middleware that
will be shared by the LB3 and LB4 applications.

## Migrating LB3 Express middleware

[This tutorial](https://github.com/strongloop/loopback-next/tree/master/examples/lb3-application/README.md)
shows the Express middleware migration process in two steps:

1. Mounting LB3 application on LB4 application
2. Migrating Express middleware from LB3 application

To see an example of a LB3 application that has been mounted on a LB4
application and has its Express middleware migrated to a common location, see
[lb3-application](https://github.com/strongloop/loopback-next/tree/master/examples/lb3-application).
242 changes: 237 additions & 5 deletions examples/lb3-application/README.md
@@ -1,9 +1,11 @@
# @loopback/example-lb3-application

This example demonstrates how to mount your existing LoopBack 3 application in a
new LoopBack 4 project.
This example demonstrates how to mount your existing LoopBack 3 (LB3)
application on a new LoopBack 4 (LB4) project and how to move the middleware
from the LB3 application to a common location so that both the LB3 and LB4
applications can use them.

## Tutorial
## Mounting LB3 app on LB4 app

1. Create a new LoopBack 4 project using `lb4 app`.

Expand Down Expand Up @@ -91,8 +93,6 @@ new LoopBack 4 project.
this.component(Lb3AppBooterComponent);
```

## Try it out

Start the new LB4 application

```sh
Expand All @@ -103,6 +103,238 @@ Start the new LB4 application
Open the URL printed to console to view your front-end served from `public`
directory or go to `http://127.0.0.1:3000/explorer` to explore the REST API.

The LB3 application is now successfully mounted on a LB4 application, but we can
further optimize the setup so that only the bare neccessary artifacts from the
LoopBack 3 application remain. This includes moving almost all of the middleware
to a common location so that they are shared by both the LoopBack 3 and the
LoopBack 4 apps.

## Migrating Express middleware from LB3 app

1. Update config.json First off, edit the LB3 app's `config.json` file.

Remove these properties, they are not required anymore:

```json
"host": "0.0.0.0",
"port": 3000,
```

Change `restApiRoot` to `/` or any path where you would like the LB3 app to
be mounted; that's relative to the LB4 app's REST API path, which defaults to
`/api`.

And then add `"handleUnknownPaths": false` to the `rest` property, this will
prevent the LB3 REST api from sending a 404 response for requests it cannot
handle.

The `config.json` file should now look like this:

```json
{
"restApiRoot": "/",
"remoting": {
"context": false,
"rest": {
"handleErrors": false,
"handleUnknownPaths": false,
"normalizeHttpPath": false,
"xml": false
},
"json": {
"strict": false,
"limit": "100kb"
},
"urlencoded": {
"extended": true,
"limit": "100kb"
},
"cors": false
}
}
```

2. Configure the base Express app

We will be using a base Express app (`src/server.ts`) for mounting the LB4
app as described in
"[Creating an Express Application with LoopBack REST API](https://loopback.io/doc/en/lb4/express-with-lb4-rest-tutorial.html)"
guide.

Migrate the LB3 app's middleware from its `middleware.json` file to this
Express app, except the one from the `routes` phase (there is a
[pending task](https://github.com/strongloop/loopback-next/issues/4181) to
complete the support for this middleware).

Each root property in the `middleware.json` object represents a middleware
phase, extract the relevant middleware and load them in the Express app in
order.

An entry like `"compression": {}` translates to `compression()`, and
`loopback#favicon` translates to `loopback.favicon()` in TypeScript. For more
details about `middleware.json`, refer to
[its documentation](https://loopback.io/doc/en/lb3/middleware.json.html).

The `middleware.json` file should look like this now:

```js
{
"routes": {
"loopback#rest": {
"paths": [
"${restApiRoot}"
]
}
}
}
```

The middleware mounted in the Express app will be shared by both LB3 and LB4
apps.

Move any static files from the LB3 app to the `public` directory of the
Express app. Move any non-REST routes defined anywhere in the LB3 app to the
Express app.

This is what the `src/server.ts` file will look like:

```ts
import {ApplicationConfig} from '@loopback/core';
import * as express from 'express';
import {Request, Response} from 'express';
import * as http from 'http';
import pEvent from 'p-event';
import * as path from 'path';
// Replace CoffeeShopApplication with the name of your application
import {CoffeeShopApplication} from './application';

const loopback = require('loopback');
const compression = require('compression');
const cors = require('cors');
const helmet = require('helmet');

export class ExpressServer {
private app: express.Application;
public readonly lbApp: CoffeeShopApplication;
private server?: http.Server;

constructor(options: ApplicationConfig = {}) {
this.app = express();
this.lbApp = new CoffeeShopApplication(options);

// Middleware migrated from LoopBack 3
this.app.use(loopback.favicon());
this.app.use(compression());
this.app.use(cors());
this.app.use(helmet());

// Mount the LB4 REST API
this.app.use('/api', this.lbApp.requestHandler);

// Custom Express routes
this.app.get('/ping', function(_req: Request, res: Response) {
res.send('pong');
});

// Serve static files in the public folder
this.app.use(express.static(path.join(__dirname, '../public')));
}

public async boot() {
await this.lbApp.boot();
}

public async start() {
await this.lbApp.start();
const port = this.lbApp.restServer.config.port || 3000;
const host = this.lbApp.restServer.config.host || '127.0.0.1';
this.server = this.app.listen(port, host);
await pEvent(this.server, 'listening');
}

public async stop() {
if (!this.server) return;
await this.lbApp.stop();
this.server.close();
await pEvent(this.server, 'close');
this.server = undefined;
}
}
```

3. Update `src/index.ts`

The Express app will replace the `CoffeeShopApplication` as the entry point
for the program, modify the `src/index.ts` file accordingly.

```ts
import {ApplicationConfig} from '@loopback/core';
import {ExpressServer} from './server';

export {ExpressServer};

export async function main(options: ApplicationConfig = {}) {
const server = new ExpressServer(options);
await server.boot();
await server.start();
console.log(`Server is running at ${server.url}`);
}
```

4. Update `index.js`

Next, modify the `index.js` file in the root of the project to prevent the
LB4 app from listening, by adding `listenOnStart: false` in `config.rest`
object. The `config` object should now look like this:

```js
const config = {
rest: {
port: +process.env.PORT || 3000,
host: process.env.HOST || 'localhost',
openApiSpec: {
// useful when used with OpenAPI-to-GraphQL to locate your application
setServersFromRequest: true,
},
listenOnStart: false,
},
};
```

Then, in the `bootOptions` of the `CoffeeShopApplication` class, add the
`lb3app` to configure the path of the LB3 APIs.

```js
lb3app: {
mode: 'fullApp';
}
```

`this.bootOptions` should now look like this:

```ts
this.bootOptions = {
controllers: {
// Customize ControllerBooter Conventions here
dirs: ['controllers'],
extensions: ['.controller.js'],
nested: true,
},
lb3app: {
mode: 'fullApp',
},
};
```

Start the app:

```sh
$ npm start
```

Load [http://localhost:3000/](http://localhost:3000/) on your browser. This will
load the Express app, with mounted LB3 and LB4 applications.

### Need help?

Check out our [Gitter channel](https://gitter.im/strongloop/loopback) and ask
Expand Down
2 changes: 2 additions & 0 deletions examples/lb3-application/index.js
Expand Up @@ -17,6 +17,8 @@ if (require.main === module) {
// useful when used with OpenAPI-to-GraphQL to locate your application
setServersFromRequest: true,
},
// Use the LB4 application as a route. It should not be listening.
listenOnStart: false,
},
};
application.main(config).catch(err => {
Expand Down
8 changes: 0 additions & 8 deletions examples/lb3-application/lb3app/server/boot/routes.js

This file was deleted.

5 changes: 2 additions & 3 deletions examples/lb3-application/lb3app/server/config.json
@@ -1,11 +1,10 @@
{
"restApiRoot": "/api",
"host": "0.0.0.0",
"port": 3000,
"restApiRoot": "/",
"remoting": {
"context": false,
"rest": {
"handleErrors": false,
"handleUnknownPaths": false,
"normalizeHttpPath": false,
"xml": false
},
Expand Down
39 changes: 1 addition & 38 deletions examples/lb3-application/lb3app/server/middleware.json 100755 → 100644
@@ -1,46 +1,9 @@
{
"initial:before": {
"loopback#favicon": {}
},
"initial": {
"compression": {},
"cors": {
"params": {
"origin": true,
"credentials": true,
"maxAge": 86400
}
},
"helmet#xssFilter": {},
"helmet#frameguard": {
"params": [
"deny"
]
},
"helmet#hsts": {
"params": {
"maxAge": 0,
"includeSubDomains": true
}
},
"helmet#hidePoweredBy": {},
"helmet#ieNoOpen": {},
"helmet#noSniff": {},
"helmet#noCache": {
"enabled": false
}
},
"session": {},
"auth": {},
"parse": {},
"routes": {
"loopback#rest": {
"paths": [
"${restApiRoot}"
]
}
},
"files": {},
"final": {},
"final:after": {}
}
}
16 changes: 16 additions & 0 deletions examples/lb3-application/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 88a24ac

Please sign in to comment.