From b063904fdd1e1674f8d3aff15e59f1ef4bdc165d Mon Sep 17 00:00:00 2001 From: shimks Date: Thu, 15 Feb 2018 16:28:48 -0500 Subject: [PATCH 1/4] move RestServer config out of start --- pages/en/lb4/Application.md | 8 ++++++-- .../en/lb4/Defining-and-validating-the-API.md | 18 ++++++++---------- pages/en/lb4/Routes.md | 5 ++--- pages/en/lb4/Sequence.md | 8 +++----- pages/en/lb4/Server.md | 12 +++++++----- 5 files changed, 26 insertions(+), 25 deletions(-) diff --git a/pages/en/lb4/Application.md b/pages/en/lb4/Application.md index e7bea3197..b67a2de98 100644 --- a/pages/en/lb4/Application.md +++ b/pages/en/lb4/Application.md @@ -38,7 +38,12 @@ export class WidgetApplication extends Application { constructor() { // This is where you would pass configuration to the base constructor // (as well as handle your own!) - super(); + super({ + rest: { + port: 8080 + } + }); + const app = this; // For clarity. // You can bind to the Application-level context here. // app.bind('foo').to(bar); @@ -51,7 +56,6 @@ export class WidgetApplication extends Application { // This is where you would asynchronously retrieve servers, providers and // other components to configure them before launch. const server = await app.getServer(RestServer); - server.bind('rest.port').to(8080); server.api(WidgetApi); // The superclass start method will call start on all servers that are // bound to the application. diff --git a/pages/en/lb4/Defining-and-validating-the-API.md b/pages/en/lb4/Defining-and-validating-the-API.md index 0ed835e73..c00558567 100644 --- a/pages/en/lb4/Defining-and-validating-the-API.md +++ b/pages/en/lb4/Defining-and-validating-the-API.md @@ -289,7 +289,7 @@ _.merge(spec, CategoryAPI); export default spec; ``` -You can then bind the full spec to the application using `server.spec()`. This is done on the server level, because each server instance can expose a different (sub)set of API. +You can then bind the full spec to the application using `app.api()`. Normally, this is done on the server level because each server instance can expose a different (sub)set of API, but since `RestApplication` uses only one REST server, you can bind the spec at application level. You also need to associate the controllers implementing the spec with the app using `app.controller(GreetController)`. This is not done on the server level because a controller may be used with multiple server instances, and types! @@ -302,20 +302,18 @@ import { ProductController, DealController, CategoryController } from "./control export class YourMicroservice extends RestApplication { constructor() { - super(); + super({ + rest: { + port: 3001 + } + }); const app = this; app.controller(ProductController); app.controller(DealController); app.controller(CategoryController); - - } - async start() { - const server = await app.getServer(RestServer); - // inject your spec here! - server.api(spec); - server.bind("rest.port").to(3001); - await super.start(); + //inject your spec + app.api(spec); } // etc... } diff --git a/pages/en/lb4/Routes.md b/pages/en/lb4/Routes.md index 6d0e8d679..ab21444ed 100644 --- a/pages/en/lb4/Routes.md +++ b/pages/en/lb4/Routes.md @@ -74,7 +74,7 @@ server.api(spec); The example below defines a `Route` that will be matched for `GET /`. When the `Route` is matched, the `greet` Operation (above) will be called. It accepts an OpenAPI [OperationObject](https://github.com/OAI/OpenAPI-Specification/blob/0e51e2a1b2d668f434e44e5818a0cdad1be090b4/versions/2.0.md#operationObject) which is defined using `spec`. The route is then attached to a valid server context running underneath the -application. +application. ```ts import {RestApplication, RestServer, Route} from '@loopback/rest'; import {OperationObject} from '@loopback/openapi-spec'; @@ -96,9 +96,8 @@ function greet(name: string) { } (async function start() { - const server = await app.getServer(RestServer); const route = new Route('get', '/', spec, greet); - server.route(route); + app.route(route); // attaches route to RestServer await app.start(); })(); ``` diff --git a/pages/en/lb4/Sequence.md b/pages/en/lb4/Sequence.md index 92347320b..95a775c34 100644 --- a/pages/en/lb4/Sequence.md +++ b/pages/en/lb4/Sequence.md @@ -86,18 +86,16 @@ class MySequence extends DefaultSequence { } ``` -In order for LoopBack to use your custom sequence, you must register it on any -applicable `Server` instances before starting your `Application`: +In order for LoopBack to use your custom sequence, you must register it +before starting your `Application`: ```js import {RestApplication, RestServer} from '@loopback/rest'; const app = new RestApplication(); -// or (async function start() { - const server = await app.getServer(RestServer); - server.sequence(MySequence); + app.sequence(MySequence); await app.start(); })(); ``` diff --git a/pages/en/lb4/Server.md b/pages/en/lb4/Server.md index d0e4d2135..3f335a59a 100644 --- a/pages/en/lb4/Server.md +++ b/pages/en/lb4/Server.md @@ -23,16 +23,18 @@ import {RestApplication, RestServer} from '@loopback/rest'; export class HelloWorldApp extends RestApplication { constructor() { super(); + // give our RestServer instance a sequence handler function which + // returns the Hello World string for all requests + // with RestApplication, handler function can be registered + // at app level + app.handler((sequence, request, response) => { + sequence.send(response, 'Hello World!'); + }); } async start() { // get a singleton HTTP server instance const rest = await this.getServer(RestServer); - // give our RestServer instance a sequence handler function which - // returns the Hello World string for all requests - rest.handler((sequence, request, response) => { - sequence.send(response, 'Hello World!'); - }); // call start on application class, which in turn starts all registered // servers await super.start(); From af022ee80f4d0f0a73761c68d8dcc521e5a1f0a8 Mon Sep 17 00:00:00 2001 From: shimks Date: Fri, 16 Feb 2018 13:35:46 -0500 Subject: [PATCH 2/4] get rid of async start --- pages/en/lb4/Defining-and-validating-the-API.md | 12 ++++++++++-- pages/en/lb4/Routes.md | 17 +++++++---------- pages/en/lb4/Sequence.md | 6 ++---- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/pages/en/lb4/Defining-and-validating-the-API.md b/pages/en/lb4/Defining-and-validating-the-API.md index c00558567..65cb22be7 100644 --- a/pages/en/lb4/Defining-and-validating-the-API.md +++ b/pages/en/lb4/Defining-and-validating-the-API.md @@ -289,9 +289,17 @@ _.merge(spec, CategoryAPI); export default spec; ``` -You can then bind the full spec to the application using `app.api()`. Normally, this is done on the server level because each server instance can expose a different (sub)set of API, but since `RestApplication` uses only one REST server, you can bind the spec at application level. +You can then bind the full spec to the application using `app.api()`. +This works well for applications with a single REST server, because +there is only one API definition involved. -You also need to associate the controllers implementing the spec with the app using `app.controller(GreetController)`. This is not done on the server level because a controller may be used with multiple server instances, and types! +If you are building an application with multiple REST servers, +where each server provides a different API, then you need +to call `server.api()` instead. + +You also need to associate the controllers implementing the spec with the app +using `app.controller(GreetController)`. This is not done on the server level +because a controller may be used with multiple server instances, and types! ```ts // application.ts diff --git a/pages/en/lb4/Routes.md b/pages/en/lb4/Routes.md index ab21444ed..936b0292e 100644 --- a/pages/en/lb4/Routes.md +++ b/pages/en/lb4/Routes.md @@ -74,12 +74,11 @@ server.api(spec); The example below defines a `Route` that will be matched for `GET /`. When the `Route` is matched, the `greet` Operation (above) will be called. It accepts an OpenAPI [OperationObject](https://github.com/OAI/OpenAPI-Specification/blob/0e51e2a1b2d668f434e44e5818a0cdad1be090b4/versions/2.0.md#operationObject) which is defined using `spec`. The route is then attached to a valid server context running underneath the -application. +application. ```ts import {RestApplication, RestServer, Route} from '@loopback/rest'; import {OperationObject} from '@loopback/openapi-spec'; -const app = new RestApplication(); const spec: OperationObject = { parameters: [{name: 'name', in: 'query', type: 'string'}], responses: { @@ -95,11 +94,11 @@ function greet(name: string) { return `hello ${name}`; } -(async function start() { - const route = new Route('get', '/', spec, greet); - app.route(route); // attaches route to RestServer - await app.start(); -})(); +const app = new RestApplication(); +const route = new Route('get', '/', spec, greet); +app.route(route); // attaches route to RestServer + +app.start(); ``` ### Using Route decorators with controller methods @@ -139,9 +138,7 @@ const app = new RestApplication(); app.controller(GreetController); -(async function start() { - await app.start(); -})(); +app.start(); ``` ## Invoking operations using Routes diff --git a/pages/en/lb4/Sequence.md b/pages/en/lb4/Sequence.md index 95a775c34..14cab99f9 100644 --- a/pages/en/lb4/Sequence.md +++ b/pages/en/lb4/Sequence.md @@ -93,11 +93,9 @@ before starting your `Application`: import {RestApplication, RestServer} from '@loopback/rest'; const app = new RestApplication(); +app.sequence(MySequencce); -(async function start() { - app.sequence(MySequence); - await app.start(); -})(); +app.start(); ``` ## Advanced topics From d903c1b26965386f5aca8092206ca93b98eebb0b Mon Sep 17 00:00:00 2001 From: shimks Date: Wed, 28 Feb 2018 13:29:23 -0500 Subject: [PATCH 3/4] remove async start in Application.md --- pages/en/lb4/Application.md | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/pages/en/lb4/Application.md b/pages/en/lb4/Application.md index b67a2de98..2cdb46659 100644 --- a/pages/en/lb4/Application.md +++ b/pages/en/lb4/Application.md @@ -32,7 +32,6 @@ tasks as a part of your setup: import {Application} from '@loopback/core'; import {RestComponent, RestServer} from '@loopback/rest'; import {SamoflangeController, DoohickeyController} from './controllers'; -import {WidgetApi} from './apidef/'; export class WidgetApplication extends Application { constructor() { @@ -52,16 +51,6 @@ export class WidgetApplication extends Application { app.controller(DoohickeyController); } - async start() { - // This is where you would asynchronously retrieve servers, providers and - // other components to configure them before launch. - const server = await app.getServer(RestServer); - server.api(WidgetApi); - // The superclass start method will call start on all servers that are - // bound to the application. - return await super.start(); - } - async stop() { // This is where you would do whatever is necessary before stopping your // app (graceful closing of connections, flushing buffers, etc) From 33f00e374f814e6d4f9a784216757d3188cd2267 Mon Sep 17 00:00:00 2001 From: shimks Date: Fri, 2 Mar 2018 12:04:15 -0500 Subject: [PATCH 4/4] add RestApplication tip --- pages/en/lb4/Application.md | 9 +++++++++ pages/en/lb4/Server.md | 5 +++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/pages/en/lb4/Application.md b/pages/en/lb4/Application.md index 2cdb46659..539c3fe11 100644 --- a/pages/en/lb4/Application.md +++ b/pages/en/lb4/Application.md @@ -184,6 +184,15 @@ export class MyApplication extends RestApplication { ## Tips for application setup Here are some tips to help avoid common pitfalls and mistakes. +### Extend from `RestApplication` when using `RestServer` +If you want to use `RestServer` from our `@loopback/rest` package, we recommend you extend +`RestApplication` in your app instead of manually binding `RestServer` or +`RestComponent`. `RestApplication` already uses `RestComponent` and makes +useful functions in `RestServer` like `handler()` available at the app level. +This means you can call these `RestServer` functions to do all of your +server-level setups in the app constructor without having to explicitly retrieve +an instance of your server. + ### Use unique bindings Use binding names that are prefixed with a unique string that does not overlap with loopback's bindings. As an example, if your application is built for diff --git a/pages/en/lb4/Server.md b/pages/en/lb4/Server.md index 3f335a59a..35297a806 100644 --- a/pages/en/lb4/Server.md +++ b/pages/en/lb4/Server.md @@ -50,9 +50,10 @@ export class HelloWorldApp extends RestApplication { You can add server instances to your application via the `app.server()` method individually or as an array using `app.servers()` method. Using `app.server()` allows you to uniquely name your binding key for your specific server instance. The following example demonstrates how to use these functions: ```ts -import {RestApplication, RestServer} from '@loopback/rest'; +import {Application} from '@loopback/core'; +import {RestServer} from '@loopback/rest'; -export class HelloWorldApp extends RestApplication { +export class HelloWorldApp extends Application { constructor() { super(); // This server instance will be bound under "servers.fooServer".