diff --git a/public/index.html.template b/public/index.html.template
index e0d8e5587..9f9d762b0 100644
--- a/public/index.html.template
+++ b/public/index.html.template
@@ -36,7 +36,9 @@
- ${name}@${version}
+ ${name}
+ Version ${version}
+
OpenAPI spec: /openapi.json
API Explorer: /explorer
diff --git a/src/application.ts b/src/application.ts
index 2fa986c35..33e78aa80 100644
--- a/src/application.ts
+++ b/src/application.ts
@@ -3,7 +3,7 @@
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
-import {ApplicationConfig} from '@loopback/core';
+import {ApplicationConfig, BindingKey} from '@loopback/core';
import {RestApplication} from '@loopback/rest';
import {MySequence} from './sequence';
@@ -20,12 +20,27 @@ import {
} from '@loopback/repository';
/* tslint:enable:no-unused-variable */
+/**
+ * Information from package.json
+ */
+export interface PackageInfo {
+ name: string;
+ version: string;
+ description: string;
+}
+export const PackageKey = BindingKey.create('application.package');
+
+const pkg: PackageInfo = require('../../package.json');
+
export class ShoppingApplication extends BootMixin(
RepositoryMixin(RestApplication),
) {
constructor(options?: ApplicationConfig) {
super(options);
+ // Bind package.json to the application context
+ this.bind(PackageKey).to(pkg);
+
// Set up the custom sequence
this.sequence(MySequence);
diff --git a/src/controllers/home-page.controller.ts b/src/controllers/home-page.controller.ts
index 513f65b1b..4cea203e2 100644
--- a/src/controllers/home-page.controller.ts
+++ b/src/controllers/home-page.controller.ts
@@ -9,19 +9,15 @@ import * as path from 'path';
import {template, TemplateExecutor} from 'lodash';
import {inject} from '@loopback/context';
import {RestBindings, Response} from '@loopback/rest';
-
-const pkg = require('../../../package.json');
+import {PackageInfo, PackageKey} from '../application';
export class HomePageController {
- name: string;
- version: string;
- description: string;
render: TemplateExecutor;
- constructor(@inject(RestBindings.Http.RESPONSE) private res: Response) {
- this.name = pkg.name;
- this.version = pkg.version;
- this.description = pkg.description || pkg.name;
+ constructor(
+ @inject(PackageKey) private pkg: PackageInfo,
+ @inject(RestBindings.Http.RESPONSE) private response: Response,
+ ) {
const html = fs.readFileSync(
path.join(__dirname, '../../../public/index.html.template'),
'utf-8',
@@ -38,8 +34,8 @@ export class HomePageController {
},
})
homePage() {
- const homePage = this.render(this);
- this.res
+ const homePage = this.render(this.pkg);
+ this.response
.status(200)
.contentType('html')
.send(homePage);
diff --git a/src/index.ts b/src/index.ts
index d1d55be58..ae72790c1 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -6,7 +6,7 @@
import {ShoppingApplication} from './application';
import {ApplicationConfig} from '@loopback/core';
-export {ShoppingApplication};
+export {ShoppingApplication, PackageInfo, PackageKey} from './application';
export async function main(options?: ApplicationConfig) {
const app = new ShoppingApplication(options);
diff --git a/test/acceptance/home-page.controller.acceptance.ts b/test/acceptance/home-page.controller.acceptance.ts
new file mode 100644
index 000000000..f30571e08
--- /dev/null
+++ b/test/acceptance/home-page.controller.acceptance.ts
@@ -0,0 +1,51 @@
+// Copyright IBM Corp. 2018. All Rights Reserved.
+// Node module: @loopback/example-shopping
+// This file is licensed under the MIT License.
+// License text available at https://opensource.org/licenses/MIT
+
+import {createClientForHandler, supertest, expect} from '@loopback/testlab';
+import {RestServer} from '@loopback/rest';
+import {ShoppingApplication} from '../..';
+
+describe('HomePageController', () => {
+ let app: ShoppingApplication;
+ let server: RestServer;
+ let client: supertest.SuperTest;
+
+ before(givenAnApplication);
+
+ before(givenARestServer);
+
+ before(async () => {
+ await app.boot();
+ await app.start();
+ });
+
+ before(() => {
+ client = createClientForHandler(server.requestHandler);
+ });
+
+ after(async () => {
+ await app.stop();
+ });
+
+ it('exposes a default home page', async () => {
+ const res = await client
+ .get('/')
+ .expect(200)
+ .expect('Content-Type', /text\/html/);
+ expect(res.body).to.match(/@loopback\/example\-shopping/);
+ });
+
+ function givenAnApplication() {
+ app = new ShoppingApplication({
+ rest: {
+ port: 0,
+ },
+ });
+ }
+
+ async function givenARestServer() {
+ server = await app.getServer(RestServer);
+ }
+});