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); + } +});