├── examples
├── lb3-express
│ ├── .eslintignore
│ ├── lib
│ │ ├── .eslintrc
│ │ ├── .yo-rc.json
│ │ ├── client
│ │ │ └── README.md
│ │ ├── server
│ │ │ ├── component-config.json
│ │ │ ├── boot
│ │ │ │ ├── authentication.js
│ │ │ │ ├── root.js
│ │ │ │ └── create-sample-models.js
│ │ │ ├── middleware.development.json
│ │ │ ├── datasources.json
│ │ │ ├── config.json
│ │ │ ├── model-config.json
│ │ │ ├── server.js
│ │ │ └── middleware.json
│ │ ├── .gitignore
│ │ └── common
│ │ │ └── models
│ │ │ └── coffee-shop.json
│ ├── lambda-wrapper.js
│ ├── .editorconfig
│ ├── .eslintrc.json
│ ├── package.json
│ ├── README.md
│ ├── serverless.yml
│ └── .snyk
└── lb4-express
│ ├── .prettierignore
│ ├── src
│ ├── __tests__
│ │ ├── mocha.opts
│ │ └── acceptance
│ │ │ ├── ping.controller.acceptance.ts
│ │ │ ├── test-helper.ts
│ │ │ ├── express.acceptance.ts
│ │ │ └── note.acceptance.ts
│ ├── models
│ │ ├── index.ts
│ │ └── note.model.ts
│ ├── controllers
│ │ ├── index.ts
│ │ ├── ping.controller.ts
│ │ └── note.controller.ts
│ ├── datasources
│ │ ├── index.ts
│ │ └── ds.datasource.ts
│ ├── observers
│ │ ├── index.ts
│ │ └── hello.observer.ts
│ ├── repositories
│ │ ├── index.ts
│ │ └── note.repository.ts
│ ├── migrate.ts
│ ├── index.ts
│ ├── lambda-wrapper.js
│ ├── sequence.ts
│ ├── application.ts
│ └── server.ts
│ ├── .prettierrc
│ ├── .eslintrc.js
│ ├── data
│ └── ds.json
│ ├── tsconfig.json
│ ├── .vscode
│ ├── settings.json
│ └── tasks.json
│ ├── public
│ ├── express.html
│ ├── notes.html
│ └── index.html
│ ├── LICENSE
│ ├── serverless.yml
│ ├── package.json
│ ├── README.md
│ └── CHANGELOG.md
├── LICENSE
├── .gitignore
└── README.md
/examples/lb3-express/.eslintignore:
--------------------------------------------------------------------------------
1 | /lib/client/
2 |
--------------------------------------------------------------------------------
/examples/lb4-express/.prettierignore:
--------------------------------------------------------------------------------
1 | dist
2 | *.json
3 |
--------------------------------------------------------------------------------
/examples/lb3-express/lib/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "loopback"
3 | }
--------------------------------------------------------------------------------
/examples/lb3-express/lib/.yo-rc.json:
--------------------------------------------------------------------------------
1 | {
2 | "generator-loopback": {}
3 | }
--------------------------------------------------------------------------------
/examples/lb4-express/src/__tests__/mocha.opts:
--------------------------------------------------------------------------------
1 | --recursive
2 | --require source-map-support/register
3 |
--------------------------------------------------------------------------------
/examples/lb3-express/lib/client/README.md:
--------------------------------------------------------------------------------
1 | ## Client
2 |
3 | This is the place for your application front-end files.
4 |
--------------------------------------------------------------------------------
/examples/lb4-express/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "bracketSpacing": false,
3 | "singleQuote": true,
4 | "printWidth": 80,
5 | "trailingComma": "all",
6 | "arrowParens": "avoid"
7 | }
8 |
--------------------------------------------------------------------------------
/examples/lb3-express/lib/server/component-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "loopback-component-explorer": {
3 | "mountPath": "/explorer",
4 | "generateOperationScopedModels": true
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/examples/lb3-express/lib/server/boot/authentication.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function enableAuthentication(server) {
4 | // enable authentication
5 | server.enableAuth();
6 | };
7 |
--------------------------------------------------------------------------------
/examples/lb3-express/lambda-wrapper.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const serverless = require ('serverless-http');
4 |
5 | const app = require('./lib/server/server');
6 |
7 | exports.handler = serverless(app);
8 |
--------------------------------------------------------------------------------
/examples/lb3-express/lib/server/middleware.development.json:
--------------------------------------------------------------------------------
1 | {
2 | "final:after": {
3 | "strong-error-handler": {
4 | "params": {
5 | "debug": true,
6 | "log": true
7 | }
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/examples/lb3-express/lib/.gitignore:
--------------------------------------------------------------------------------
1 | *.csv
2 | *.dat
3 | *.iml
4 | *.log
5 | *.out
6 | *.pid
7 | *.seed
8 | *.sublime-*
9 | *.swo
10 | *.swp
11 | *.tgz
12 | *.xml
13 | .DS_Store
14 | .idea
15 | .project
16 | .strong-pm
17 | coverage
18 | node_modules
19 | npm-debug.log
20 |
--------------------------------------------------------------------------------
/examples/lb3-express/lib/server/boot/root.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function(server) {
4 | // Install a `/` route that returns server status
5 | var router = server.loopback.Router();
6 | router.get('/', server.loopback.status());
7 | server.use(router);
8 | };
9 |
--------------------------------------------------------------------------------
/examples/lb4-express/src/models/index.ts:
--------------------------------------------------------------------------------
1 | // Copyright IBM Corp. 2019. All Rights Reserved.
2 | // Node module: @loopback/example-express-composition
3 | // This file is licensed under the MIT License.
4 | // License text available at https://opensource.org/licenses/MIT
5 |
6 | export * from './note.model';
7 |
--------------------------------------------------------------------------------
/examples/lb4-express/src/controllers/index.ts:
--------------------------------------------------------------------------------
1 | // Copyright IBM Corp. 2019. All Rights Reserved.
2 | // Node module: @loopback/example-express-composition
3 | // This file is licensed under the MIT License.
4 | // License text available at https://opensource.org/licenses/MIT
5 |
6 | export * from './note.controller';
7 |
--------------------------------------------------------------------------------
/examples/lb4-express/src/datasources/index.ts:
--------------------------------------------------------------------------------
1 | // Copyright IBM Corp. 2019. All Rights Reserved.
2 | // Node module: @loopback/example-express-composition
3 | // This file is licensed under the MIT License.
4 | // License text available at https://opensource.org/licenses/MIT
5 |
6 | export * from './ds.datasource';
7 |
--------------------------------------------------------------------------------
/examples/lb4-express/src/observers/index.ts:
--------------------------------------------------------------------------------
1 | // Copyright IBM Corp. 2019. All Rights Reserved.
2 | // Node module: @loopback/example-express-composition
3 | // This file is licensed under the MIT License.
4 | // License text available at https://opensource.org/licenses/MIT
5 |
6 | export * from './hello.observer';
7 |
--------------------------------------------------------------------------------
/examples/lb4-express/src/repositories/index.ts:
--------------------------------------------------------------------------------
1 | // Copyright IBM Corp. 2019. All Rights Reserved.
2 | // Node module: @loopback/example-express-composition
3 | // This file is licensed under the MIT License.
4 | // License text available at https://opensource.org/licenses/MIT
5 |
6 | export * from './note.repository';
7 |
--------------------------------------------------------------------------------
/examples/lb4-express/.eslintrc.js:
--------------------------------------------------------------------------------
1 | // Copyright IBM Corp. 2020. All Rights Reserved.
2 | // Node module: @loopback/example-express-composition
3 | // This file is licensed under the MIT License.
4 | // License text available at https://opensource.org/licenses/MIT
5 |
6 | module.exports = {
7 | extends: ['@loopback/eslint-config'],
8 | };
9 |
--------------------------------------------------------------------------------
/examples/lb4-express/data/ds.json:
--------------------------------------------------------------------------------
1 | {
2 | "ids": {
3 | "Note": 3
4 | },
5 | "models": {
6 | "Note": {
7 | "1": "{\"title\":\"Things I need to buy\",\"content\":\"milk, cereal, and waffles\",\"id\":1}",
8 | "2": "{\"title\":\"Great frameworks\",\"content\":\"LoopBack is a great framework\",\"id\":2}"
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/examples/lb3-express/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig helps developers define and maintain consistent
2 | # coding styles between different editors and IDEs
3 | # http://editorconfig.org
4 |
5 | root = true
6 |
7 | [*]
8 | indent_style = space
9 | indent_size = 2
10 | end_of_line = lf
11 | charset = utf-8
12 | trim_trailing_whitespace = true
13 | insert_final_newline = true
14 |
--------------------------------------------------------------------------------
/examples/lb4-express/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema":"http://json.schemastore.org/tsconfig",
3 | "extends":"@loopback/build/config/tsconfig.common.json",
4 | "compilerOptions": {
5 | "outDir":"dist",
6 | "rootDir":"src",
7 | "composite":false,
8 | "allowJs": true
9 | },
10 | "include":[
11 | "src/**/*",
12 | "src/**/*.json"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/examples/lb3-express/lib/server/datasources.json:
--------------------------------------------------------------------------------
1 | {
2 | "db": {
3 | "name": "db",
4 | "connector": "memory"
5 | },
6 | "mysql": {
7 | "name": "mysql",
8 | "connector": "mysql",
9 | "host": "${DB_HOST}",
10 | "port": "${DB_PORT}",
11 | "database": "${DB_NAME}",
12 | "connectTimeout": 600000,
13 | "user": "${DB_USERNAME}",
14 | "password": "${DB_PASSWORD}"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/examples/lb3-express/lib/common/models/coffee-shop.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "CoffeeShop",
3 | "base": "PersistedModel",
4 | "idInjection": true,
5 | "forceId": false,
6 | "options": {
7 | "validateUpsert": true
8 | },
9 | "properties": {
10 | "name": {
11 | "type": "string",
12 | "required": true
13 | },
14 | "city": {
15 | "type": "string"
16 | }
17 | },
18 | "validations": [],
19 | "relations": {},
20 | "acls": [],
21 | "methods": {}
22 | }
23 |
--------------------------------------------------------------------------------
/examples/lb3-express/lib/server/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "restApiRoot": "/api",
3 | "host": "0.0.0.0",
4 | "port": 3000,
5 | "remoting": {
6 | "context": false,
7 | "rest": {
8 | "handleErrors": false,
9 | "normalizeHttpPath": false,
10 | "xml": false
11 | },
12 | "json": {
13 | "strict": false,
14 | "limit": "100kb"
15 | },
16 | "urlencoded": {
17 | "extended": true,
18 | "limit": "100kb"
19 | },
20 | "cors": false
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/examples/lb4-express/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "editor.rulers": [80],
3 | "editor.tabCompletion": "on",
4 | "editor.tabSize": 2,
5 | "editor.trimAutoWhitespace": true,
6 | "editor.formatOnSave": true,
7 |
8 | "files.exclude": {
9 | "**/.DS_Store": true,
10 | "**/.git": true,
11 | "**/.hg": true,
12 | "**/.svn": true,
13 | "**/CVS": true,
14 | "dist": true,
15 | },
16 | "files.insertFinalNewline": true,
17 | "files.trimTrailingWhitespace": true,
18 |
19 | "typescript.tsdk": "./node_modules/typescript/lib"
20 | }
21 |
--------------------------------------------------------------------------------
/examples/lb3-express/lib/server/boot/create-sample-models.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function(app) {
4 | app.dataSources.mysql.automigrate('CoffeeShop', function(err) {
5 | if (err) throw err;
6 |
7 | app.models.CoffeeShop.create([{
8 | name: 'Bel Cafe',
9 | city: 'Vancouver',
10 | }, {
11 | name: 'Three Bees Coffee House',
12 | city: 'San Mateo',
13 | }, {
14 | name: 'Caffe Artigiano',
15 | city: 'Vancouver',
16 | }], function(err, coffeeShops) {
17 | if (err) throw err;
18 |
19 | console.log('Models created: \n', coffeeShops);
20 | });
21 | });
22 | };
23 |
--------------------------------------------------------------------------------
/examples/lb3-express/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "parserOptions": {
3 | "ecmaVersion": 2017
4 | },
5 | "env": {
6 | "node": true,
7 | "es6": true
8 | },
9 | "extends": "eslint:recommended",
10 | "rules": {
11 | "indent": [
12 | "error",
13 | 4
14 | ],
15 | "linebreak-style": [
16 | "error",
17 | "unix"
18 | ],
19 | "quotes": [
20 | "error",
21 | "single"
22 | ],
23 | "camelcase": [
24 | "error"
25 | ],
26 | "semi": [
27 | "warn",
28 | "always"
29 | ],
30 | "prefer-const": ["error", {
31 | "destructuring": "any",
32 | "ignoreReadBeforeAssign": false
33 | }],
34 | "strict": [
35 | "error",
36 | "global"
37 | ]
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/examples/lb4-express/public/express.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | LoopBack 4 REST API on Express
5 |
6 |
7 |
8 |
9 |
14 |
15 |
16 | Express
17 | This is the main Express page.
18 | Click here for the LoopBack main page and
19 | here to say hi.
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/examples/lb4-express/src/repositories/note.repository.ts:
--------------------------------------------------------------------------------
1 | // Copyright IBM Corp. 2019. All Rights Reserved.
2 | // Node module: @loopback/example-express-composition
3 | // This file is licensed under the MIT License.
4 | // License text available at https://opensource.org/licenses/MIT
5 |
6 | import {inject} from '@loopback/core';
7 | import {DefaultCrudRepository} from '@loopback/repository';
8 | import {DsDataSource} from '../datasources';
9 | import {Note, NoteRelations} from '../models';
10 |
11 | export class NoteRepository extends DefaultCrudRepository<
12 | Note,
13 | typeof Note.prototype.id,
14 | NoteRelations
15 | > {
16 | constructor(@inject('datasources.ds') dataSource: DsDataSource) {
17 | super(Note, dataSource);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/examples/lb4-express/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | // See https://go.microsoft.com/fwlink/?LinkId=733558
3 | // for the documentation about the tasks.json format
4 | "version": "2.0.0",
5 | "tasks": [
6 | {
7 | "label": "Watch and Compile Project",
8 | "type": "shell",
9 | "command": "npm",
10 | "args": ["--silent", "run", "build:watch"],
11 | "group": {
12 | "kind": "build",
13 | "isDefault": true
14 | },
15 | "problemMatcher": "$tsc-watch"
16 | },
17 | {
18 | "label": "Build, Test and Lint",
19 | "type": "shell",
20 | "command": "npm",
21 | "args": ["--silent", "run", "test:dev"],
22 | "group": {
23 | "kind": "test",
24 | "isDefault": true
25 | },
26 | "problemMatcher": ["$tsc", "$eslint-stylish", "$eslint-compact"]
27 | }
28 | ]
29 | }
30 |
--------------------------------------------------------------------------------
/examples/lb4-express/src/models/note.model.ts:
--------------------------------------------------------------------------------
1 | // Copyright IBM Corp. 2019. All Rights Reserved.
2 | // Node module: @loopback/example-express-composition
3 | // This file is licensed under the MIT License.
4 | // License text available at https://opensource.org/licenses/MIT
5 |
6 | import {Entity, model, property} from '@loopback/repository';
7 |
8 | @model()
9 | export class Note extends Entity {
10 | @property({
11 | type: 'number',
12 | id: true,
13 | })
14 | id?: number;
15 |
16 | @property({
17 | type: 'string',
18 | required: true,
19 | })
20 | title: string;
21 |
22 | @property({
23 | type: 'string',
24 | })
25 | content?: string;
26 |
27 | constructor(data?: Partial) {
28 | super(data);
29 | }
30 | }
31 |
32 | export interface NoteRelations {
33 | // describe navigational properties here
34 | }
35 |
36 | export type NoteWithRelations = Note & NoteRelations;
37 |
--------------------------------------------------------------------------------
/examples/lb3-express/lib/server/model-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "_meta": {
3 | "sources": [
4 | "loopback/common/models",
5 | "loopback/server/models",
6 | "../common/models",
7 | "./models"
8 | ],
9 | "mixins": [
10 | "loopback/common/mixins",
11 | "loopback/server/mixins",
12 | "../common/mixins",
13 | "./mixins"
14 | ]
15 | },
16 | "User": {
17 | "dataSource": "db"
18 | },
19 | "AccessToken": {
20 | "dataSource": "db",
21 | "public": false
22 | },
23 | "ACL": {
24 | "dataSource": "db",
25 | "public": false
26 | },
27 | "RoleMapping": {
28 | "dataSource": "db",
29 | "public": false,
30 | "options": {
31 | "strictObjectIDCoercion": true
32 | }
33 | },
34 | "Role": {
35 | "dataSource": "db",
36 | "public": false
37 | },
38 | "CoffeeShop": {
39 | "dataSource": "mysql",
40 | "public": true
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/examples/lb4-express/src/datasources/ds.datasource.ts:
--------------------------------------------------------------------------------
1 | import {inject, lifeCycleObserver, LifeCycleObserver} from '@loopback/core';
2 | import {juggler} from '@loopback/repository';
3 |
4 | const config = {
5 | name: 'ds',
6 | connector: 'memory',
7 | };
8 |
9 | // Observe application's life cycle to disconnect the datasource when
10 | // application is stopped. This allows the application to be shut down
11 | // gracefully. The `stop()` method is inherited from `juggler.DataSource`.
12 | // Learn more at https://loopback.io/doc/en/lb4/Life-cycle.html
13 | @lifeCycleObserver('datasource')
14 | export class DsDataSource extends juggler.DataSource
15 | implements LifeCycleObserver {
16 | static dataSourceName = 'ds';
17 | static readonly defaultConfig = config;
18 |
19 | constructor(
20 | @inject('datasources.config.ds', {optional: true})
21 | dsConfig: object = config,
22 | ) {
23 | super(dsConfig);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/examples/lb4-express/src/migrate.ts:
--------------------------------------------------------------------------------
1 | // Copyright IBM Corp. 2019. All Rights Reserved.
2 | // Node module: @loopback/example-express-composition
3 | // This file is licensed under the MIT License.
4 | // License text available at https://opensource.org/licenses/MIT
5 |
6 | import {ExpressServer} from './server';
7 |
8 | export async function migrate(args: string[]) {
9 | const existingSchema = args.includes('--rebuild') ? 'drop' : 'alter';
10 | console.log('Migrating schemas (%s existing schema)', existingSchema);
11 |
12 | const server = new ExpressServer();
13 | await server.boot();
14 | await server.lbApp.migrateSchema({existingSchema});
15 |
16 | // Connectors usually keep a pool of opened connections,
17 | // this keeps the process running even after all work is done.
18 | // We need to exit explicitly.
19 | process.exit(0);
20 | }
21 |
22 | migrate(process.argv).catch(err => {
23 | console.error('Cannot migrate database schema', err);
24 | process.exit(1);
25 | });
26 |
--------------------------------------------------------------------------------
/examples/lb3-express/lib/server/server.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var loopback = require('loopback');
4 | var boot = require('loopback-boot');
5 |
6 | var app = module.exports = loopback();
7 |
8 | app.start = function() {
9 | // start the web server
10 | return app.listen(function() {
11 | app.emit('started');
12 | var baseUrl = app.get('url').replace(/\/$/, '');
13 | console.log('Web server listening at: %s', baseUrl);
14 | if (app.get('loopback-component-explorer')) {
15 | var explorerPath = app.get('loopback-component-explorer').mountPath;
16 | console.log('Browse your REST API at %s%s', baseUrl, explorerPath);
17 | }
18 | });
19 | };
20 |
21 | // Bootstrap the application, configure models, datasources and middleware.
22 | // Sub-apps like REST API are mounted via boot scripts.
23 | boot(app, __dirname, function(err) {
24 | if (err) throw err;
25 |
26 | // start the server if `$ node server.js`
27 | if (require.main === module)
28 | app.start();
29 | });
30 |
--------------------------------------------------------------------------------
/examples/lb4-express/src/__tests__/acceptance/ping.controller.acceptance.ts:
--------------------------------------------------------------------------------
1 | // Copyright IBM Corp. 2019. All Rights Reserved.
2 | // Node module: @loopback/example-express-composition
3 | // This file is licensed under the MIT License.
4 | // License text available at https://opensource.org/licenses/MIT
5 |
6 | import {Client, expect} from '@loopback/testlab';
7 | import {setupExpressApplication} from './test-helper';
8 | import {ExpressServer} from '../../server';
9 |
10 | describe('PingController', () => {
11 | let server: ExpressServer;
12 | let client: Client;
13 |
14 | before('setupApplication', async () => {
15 | ({server, client} = await setupExpressApplication());
16 | });
17 |
18 | after('closes application', async () => {
19 | await server.stop();
20 | });
21 |
22 | it('invokes GET /ping', async () => {
23 | const res = await client.get('/api/ping?msg=world').expect(200);
24 | expect(res.body).to.containEql({greeting: 'Hello from LoopBack'});
25 | });
26 | });
27 |
--------------------------------------------------------------------------------
/examples/lb3-express/lib/server/middleware.json:
--------------------------------------------------------------------------------
1 | {
2 | "initial:before": {
3 | "loopback#favicon": {}
4 | },
5 | "initial": {
6 | "compression": {},
7 | "cors": {
8 | "params": {
9 | "origin": true,
10 | "credentials": true,
11 | "maxAge": 86400
12 | }
13 | },
14 | "helmet#xssFilter": {},
15 | "helmet#frameguard": {
16 | "params": { "action": "deny" }
17 | },
18 | "helmet#hsts": {
19 | "params": {
20 | "maxAge": 0,
21 | "includeSubdomains": true
22 | }
23 | },
24 | "helmet#hidePoweredBy": {},
25 | "helmet#ieNoOpen": {},
26 | "helmet#noSniff": {},
27 | "helmet#noCache": {
28 | "enabled": false
29 | }
30 | },
31 | "session": {},
32 | "auth": {},
33 | "parse": {},
34 | "routes": {
35 | "loopback#rest": {
36 | "paths": [
37 | "${restApiRoot}"
38 | ]
39 | }
40 | },
41 | "files": {},
42 | "final": {
43 | "loopback#urlNotFound": {}
44 | },
45 | "final:after": {
46 | "strong-error-handler": {}
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 BotBits (sm)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/examples/lb4-express/src/observers/hello.observer.ts:
--------------------------------------------------------------------------------
1 | // Copyright IBM Corp. 2019. All Rights Reserved.
2 | // Node module: @loopback/example-express-composition
3 | // This file is licensed under the MIT License.
4 | // License text available at https://opensource.org/licenses/MIT
5 |
6 | import {
7 | lifeCycleObserver, // The decorator
8 | LifeCycleObserver,
9 | } from '@loopback/core';
10 |
11 | /**
12 | * This class will be bound to the application as a `LifeCycleObserver` during
13 | * `boot`
14 | */
15 | @lifeCycleObserver()
16 | export class HelloObserver implements LifeCycleObserver {
17 | events: string[] = [];
18 | /*
19 | constructor(
20 | @inject(CoreBindings.APPLICATION_INSTANCE) private app: Application,
21 | ) {}
22 | */
23 |
24 | /**
25 | * This method will be invoked when the application starts
26 | */
27 | async start(): Promise {
28 | this.events.push(`${new Date()}: hello-start`);
29 | }
30 |
31 | /**
32 | * This method will be invoked when the application stops
33 | */
34 | async stop(): Promise {
35 | this.events.push(`${new Date()}: hello-stop`);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/examples/lb4-express/src/index.ts:
--------------------------------------------------------------------------------
1 | // Copyright IBM Corp. 2019,2020. All Rights Reserved.
2 | // Node module: @loopback/example-express-composition
3 | // This file is licensed under the MIT License.
4 | // License text available at https://opensource.org/licenses/MIT
5 |
6 | import {ApplicationConfig, ExpressServer} from './server';
7 |
8 | export * from './server';
9 |
10 | export async function main(options: ApplicationConfig = {}) {
11 | const server = new ExpressServer(options);
12 | await server.boot();
13 | await server.start();
14 | console.log('Server is running at http://127.0.0.1:3000');
15 | }
16 |
17 | if (require.main === module) {
18 | // Run the application
19 | const config = {
20 | rest: {
21 | port: +(process.env.PORT ?? 3000),
22 | host: process.env.HOST ?? 'localhost',
23 | openApiSpec: {
24 | // useful when used with OpenAPI-to-GraphQL to locate your application
25 | setServersFromRequest: true,
26 | },
27 | // Use the LB4 application as a route. It should not be listening.
28 | listenOnStart: false,
29 | },
30 | };
31 | main(config).catch(err => {
32 | console.error('Cannot start the application.', err);
33 | process.exit(1);
34 | });
35 | }
36 |
--------------------------------------------------------------------------------
/examples/lb4-express/src/lambda-wrapper.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {ExpressServer} = require('./server');
4 | const serverless = require('serverless-http');
5 |
6 | let app;
7 |
8 | async function main(options) {
9 | const server = new ExpressServer(options);
10 | app = serverless(server.app);
11 | await server.boot();
12 | await server.start();
13 | console.log('Server is running at http://127.0.0.1:3000');
14 | }
15 |
16 | exports.handler = async function handler(request, ...context) {
17 | if (app === undefined) {
18 | // Run the application
19 | const config = {
20 | rest: {
21 | port: +(process.env.PORT ? process.env.PORT : 3000),
22 | host: process.env.HOST ? process.env.HOST : 'localhost',
23 | openApiSpec: {
24 | // useful when used with OpenAPI-to-GraphQL to locate your application
25 | setServersFromRequest: true,
26 | },
27 | // Use the LB4 application as a route. It should not be listening.
28 | listenOnStart: false,
29 | },
30 | };
31 | await main(config).catch(err => {
32 | console.error('Cannot start the application.', err);
33 | process.exit(1);
34 | });
35 | }
36 | return app(request, ...context);
37 | };
38 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Loopback4
2 | dist
3 | tsconfig.tsbuildinfo
4 |
5 | # Serverless
6 | .serverless
7 |
8 | # Logs
9 | logs
10 | *.log
11 | npm-debug.log*
12 | yarn-debug.log*
13 | yarn-error.log*
14 |
15 | # Runtime data
16 | pids
17 | *.pid
18 | *.seed
19 | *.pid.lock
20 |
21 | # Directory for instrumented libs generated by jscoverage/JSCover
22 | lib-cov
23 |
24 | # Coverage directory used by tools like istanbul
25 | coverage
26 |
27 | # nyc test coverage
28 | .nyc_output
29 |
30 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
31 | .grunt
32 |
33 | # Bower dependency directory (https://bower.io/)
34 | bower_components
35 |
36 | # node-waf configuration
37 | .lock-wscript
38 |
39 | # Compiled binary addons (https://nodejs.org/api/addons.html)
40 | build/Release
41 |
42 | # Dependency directories
43 | node_modules/
44 | jspm_packages/
45 |
46 | # TypeScript v1 declaration files
47 | typings/
48 |
49 | # Optional npm cache directory
50 | .npm
51 |
52 | # Optional eslint cache
53 | .eslintcache
54 |
55 | # Optional REPL history
56 | .node_repl_history
57 |
58 | # Output of 'npm pack'
59 | *.tgz
60 |
61 | # Yarn Integrity file
62 | .yarn-integrity
63 |
64 | # dotenv environment variables file
65 | .env
66 |
67 | # next.js build output
68 | .next
69 |
--------------------------------------------------------------------------------
/examples/lb4-express/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) IBM Corp. 2019.
2 | Node module: @loopback/example-express-composition
3 | This project is licensed under the MIT License, full text below.
4 |
5 | --------
6 |
7 | MIT license
8 |
9 | Permission is hereby granted, free of charge, to any person obtaining a copy
10 | of this software and associated documentation files (the "Software"), to deal
11 | in the Software without restriction, including without limitation the rights
12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | copies of the Software, and to permit persons to whom the Software is
14 | furnished to do so, subject to the following conditions:
15 |
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 |
19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | THE SOFTWARE.
26 |
--------------------------------------------------------------------------------
/examples/lb4-express/src/__tests__/acceptance/test-helper.ts:
--------------------------------------------------------------------------------
1 | // Copyright IBM Corp. 2019,2020. All Rights Reserved.
2 | // Node module: @loopback/example-express-composition
3 | // This file is licensed under the MIT License.
4 | // License text available at https://opensource.org/licenses/MIT
5 |
6 | import {givenHttpServerConfig, Client, supertest} from '@loopback/testlab';
7 | import {NoteApplication} from '../../application';
8 | import {ExpressServer} from '../../server';
9 | import {Note} from '../../models/note.model';
10 |
11 | export async function setupExpressApplication(): Promise {
12 | const server = new ExpressServer({rest: givenHttpServerConfig()});
13 | await server.boot();
14 | await server.start();
15 |
16 | const lbApp = server.lbApp;
17 |
18 | const client = supertest(server.app);
19 |
20 | return {server, client, lbApp};
21 | }
22 |
23 | export interface AppWithClient {
24 | server: ExpressServer;
25 | client: Client;
26 | lbApp: NoteApplication;
27 | }
28 |
29 | /**
30 | * Generate a complete Note object for use with tests.
31 | * @param A partial (or complete) Note object.
32 | */
33 | export function givenNote(note?: Partial) {
34 | const data = Object.assign(
35 | {
36 | title: 'start essay',
37 | content: 'write thesis',
38 | },
39 | note,
40 | );
41 | return new Note(data);
42 | }
43 |
--------------------------------------------------------------------------------
/examples/lb4-express/src/sequence.ts:
--------------------------------------------------------------------------------
1 | // Copyright IBM Corp. 2019. All Rights Reserved.
2 | // Node module: @loopback/example-express-composition
3 | // This file is licensed under the MIT License.
4 | // License text available at https://opensource.org/licenses/MIT
5 |
6 | import {inject} from '@loopback/core';
7 | import {
8 | FindRoute,
9 | InvokeMethod,
10 | ParseParams,
11 | Reject,
12 | RequestContext,
13 | RestBindings,
14 | Send,
15 | SequenceHandler,
16 | } from '@loopback/rest';
17 |
18 | const SequenceActions = RestBindings.SequenceActions;
19 |
20 | export class MySequence implements SequenceHandler {
21 | constructor(
22 | @inject(SequenceActions.FIND_ROUTE) protected findRoute: FindRoute,
23 | @inject(SequenceActions.PARSE_PARAMS) protected parseParams: ParseParams,
24 | @inject(SequenceActions.INVOKE_METHOD) protected invoke: InvokeMethod,
25 | @inject(SequenceActions.SEND) public send: Send,
26 | @inject(SequenceActions.REJECT) public reject: Reject,
27 | ) {}
28 |
29 | async handle(context: RequestContext) {
30 | try {
31 | const {request, response} = context;
32 | const route = this.findRoute(request);
33 | const args = await this.parseParams(request, route);
34 | const result = await this.invoke(route, args);
35 | this.send(response, result);
36 | } catch (err) {
37 | this.reject(context, err);
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/examples/lb4-express/public/notes.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Notes
5 |
6 |
7 |
27 |
28 |
29 |
30 | Notes
31 |
32 |
33 | | Title |
34 | Content |
35 |
36 |
37 |
38 |
39 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/examples/lb4-express/src/application.ts:
--------------------------------------------------------------------------------
1 | // Copyright IBM Corp. 2019,2020. All Rights Reserved.
2 | // Node module: @loopback/example-express-composition
3 | // This file is licensed under the MIT License.
4 | // License text available at https://opensource.org/licenses/MIT
5 |
6 | import {BootMixin} from '@loopback/boot';
7 | import {ApplicationConfig} from '@loopback/core';
8 | import {RepositoryMixin} from '@loopback/repository';
9 | import {RestApplication} from '@loopback/rest';
10 | import {RestExplorerComponent} from '@loopback/rest-explorer';
11 | import {ServiceMixin} from '@loopback/service-proxy';
12 | import path from 'path';
13 | import {MySequence} from './sequence';
14 |
15 | export {ApplicationConfig};
16 |
17 | export class NoteApplication extends BootMixin(
18 | ServiceMixin(RepositoryMixin(RestApplication)),
19 | ) {
20 | constructor(options: ApplicationConfig = {}) {
21 | super(options);
22 |
23 | // Set up the custom sequence
24 | this.sequence(MySequence);
25 |
26 | // Set up default home page
27 | this.static('/', path.join(__dirname, '../public'));
28 |
29 | this.component(RestExplorerComponent);
30 |
31 | this.projectRoot = __dirname;
32 | // Customize @loopback/boot Booter Conventions here
33 | this.bootOptions = {
34 | controllers: {
35 | // Customize ControllerBooter Conventions here
36 | dirs: ['controllers'],
37 | extensions: ['.controller.js'],
38 | nested: true,
39 | },
40 | };
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/examples/lb4-express/src/controllers/ping.controller.ts:
--------------------------------------------------------------------------------
1 | // Copyright IBM Corp. 2019. All Rights Reserved.
2 | // Node module: @loopback/example-express-composition
3 | // This file is licensed under the MIT License.
4 | // License text available at https://opensource.org/licenses/MIT
5 |
6 | import {Request, RestBindings, get, ResponseObject} from '@loopback/rest';
7 | import {inject} from '@loopback/core';
8 |
9 | /**
10 | * OpenAPI response for ping()
11 | */
12 | const PING_RESPONSE: ResponseObject = {
13 | description: 'Ping Response',
14 | content: {
15 | 'application/json': {
16 | schema: {
17 | type: 'object',
18 | title: 'PingResponse',
19 | properties: {
20 | greeting: {type: 'string'},
21 | date: {type: 'string'},
22 | url: {type: 'string'},
23 | headers: {
24 | type: 'object',
25 | properties: {
26 | 'Content-Type': {type: 'string'},
27 | },
28 | additionalProperties: true,
29 | },
30 | },
31 | },
32 | },
33 | },
34 | };
35 |
36 | /**
37 | * A simple controller to bounce back http requests
38 | */
39 | export class PingController {
40 | constructor(@inject(RestBindings.Http.REQUEST) private req: Request) {}
41 |
42 | // Map to `GET /ping`
43 | @get('/ping', {
44 | responses: {
45 | '200': PING_RESPONSE,
46 | },
47 | })
48 | ping(): object {
49 | // Reply with a greeting, the current time, the url, and request headers
50 | return {
51 | greeting: 'Hello from LoopBack',
52 | date: new Date(),
53 | url: this.req.url,
54 | headers: Object.assign({}, this.req.headers),
55 | };
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/examples/lb3-express/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "serverless-loopback",
3 | "version": "0.0.0",
4 | "description": "Sample serverless project using loopback.",
5 | "author": "BotBits (sm) (https://github.com/botbits)",
6 | "keywords": [
7 | "serverless",
8 | "loopback",
9 | "lambda",
10 | "aws"
11 | ],
12 | "license": "MIT",
13 | "repository": {
14 | "type": "git",
15 | "url": "git+https://github.com/botbits/serverless-loopback.git"
16 | },
17 | "bugs": {
18 | "url": "https://github.com/botbits/serverless-loopback/issues"
19 | },
20 | "homepage": "https://github.com/botbits/serverless-loopback#readme",
21 | "engines": {
22 | "node": ">=6"
23 | },
24 | "main": "lambda-wrapper.js",
25 | "scripts": {
26 | "lint": "eslint .",
27 | "lb": "node_modules/loopback-cli/bin/loopback-cli.js",
28 | "lb-model": "node_modules/loopback-cli/bin/loopback-cli.js model",
29 | "sls-deploy": "node_modules/serverless/bin/serverless deploy --verbose",
30 | "sls-cleanup": "node_modules/serverless/bin/serverless remove --verbose",
31 | "snyk-protect": "snyk protect",
32 | "prepare": "npm run snyk-protect"
33 | },
34 | "dependencies": {
35 | "compression": "^1.0.3",
36 | "cors": "^2.5.2",
37 | "helmet": "^3.21.1",
38 | "loopback": "^3.28.0",
39 | "loopback-boot": "^2.27.1",
40 | "loopback-component-explorer": "^6.3.1",
41 | "loopback-connector-mysql": "^5.3.1",
42 | "serve-favicon": "^2.0.1",
43 | "serverless-http": "^1.8.0",
44 | "strong-error-handler": "^3.2.0",
45 | "snyk": "^1.1111.0"
46 | },
47 | "devDependencies": {
48 | "eslint": "^5.9.0",
49 | "eslint-config-loopback": "^12.0.0",
50 | "loopback-cli": "^5.2.0",
51 | "serverless": "^1.32.0"
52 | },
53 | "snyk": true
54 | }
55 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # serverless-loopback
2 | [](http://www.serverless.com)
3 | [](https://raw.githubusercontent.com/botbits/serverless-loopback/master/LICENSE)
4 | [](https://www.codacy.com/app/marcelobern/serverless-loopback?utm_source=github.com&utm_medium=referral&utm_content=botbits/serverless-loopback&utm_campaign=Badge_Grade)
5 | [](https://app.fossa.io/projects/git%2Bgithub.com%2Fbotbits%2Fserverless-loopback?ref=badge_shield)
6 |
7 | A collection of sample [loopback](https://loopback.io/) applications deployed to [AWS Lambda](https://aws.amazon.com/lambda/) using [serverless](https://serverless.com/).
8 |
9 | ## Overview
10 |
11 | The following examples are available:
12 |
13 | - [Loopback 3 (using express)](examples/lb3-express/README.md)
14 | - [Loopback 4 (via express)](examples/lb4-express/README.md)
15 |
16 | ## Using
17 |
18 | [Create a *serverless* service](https://serverless.com/framework/docs/providers/aws/cli-reference/create) from this template by using the command:
19 |
20 | `serverless create --template-url https://github.com/botbits/serverless-loopback/examples/`
21 |
22 | Or clone the git repo:
23 |
24 | `git clone https://github.com/botbits/serverless-loopback`
25 |
26 | and `cd examples` to start checking your favorite example!
27 |
28 | ## Contributing
29 |
30 | Please feel free to contribute your examples of using loopback4 with other web frameworks under the `examples` folder.
31 |
32 | ## License
33 |
34 | MIT © [BotBitsSM](https://github.com/botbits)
35 |
--------------------------------------------------------------------------------
/examples/lb4-express/serverless.yml:
--------------------------------------------------------------------------------
1 | service: serverless-loopback4-express
2 | frameWorkVersion: ">=1.72.0 <2.0.0"
3 |
4 | plugins:
5 | - serverless-offline
6 |
7 | provider:
8 | name: aws
9 | runtime: nodejs12.x
10 | stage: ${opt:stage, self:custom.defaultStage}
11 | region: us-east-1
12 | logs:
13 | restApi: true
14 |
15 | custom:
16 | serverless-offline:
17 | httpPort: 5000
18 | defaultStage: dev
19 |
20 | package:
21 | exclude:
22 | - .vscode/**
23 | - data/**
24 | - dist/__tests__/**
25 | - src/**
26 | - tsconfig.tsbuildinfo
27 |
28 | functions:
29 | loopback:
30 | handler: dist/lambda-wrapper.handler
31 | name: '${self:provider.stage}-loopback4-express'
32 | description: Sample loopback4 (via express) running in AWS lambda
33 | memorySize: 512
34 | timeout: 60
35 | events:
36 | - http: ANY /
37 | - http: ANY {proxy+}
38 |
39 | resources:
40 | # The "Outputs" that your AWS CloudFormation Stack should produce. This allows references between services.
41 | Outputs:
42 | LoopbackPostman:
43 | Description: The baseUrl value to configure for your Postman collection
44 | Value:
45 | 'Fn::Join':
46 | - ''
47 | - - 'https://'
48 | - Ref: 'ApiGatewayRestApi'
49 | - '.execute-api.'
50 | - Ref: 'AWS::Region'
51 | - '.'
52 | - Ref: 'AWS::URLSuffix'
53 | - '/${self:provider.stage}/api'
54 | LoopbackApiExplorer:
55 | Description: The URL to directly access the loopback API explorer
56 | Value:
57 | 'Fn::Join':
58 | - ''
59 | - - 'https://'
60 | - Ref: 'ApiGatewayRestApi'
61 | - '.execute-api.'
62 | - Ref: 'AWS::Region'
63 | - '.'
64 | - Ref: 'AWS::URLSuffix'
65 | - '/${self:provider.stage}/api/explorer/'
66 |
--------------------------------------------------------------------------------
/examples/lb4-express/src/server.ts:
--------------------------------------------------------------------------------
1 | // Copyright IBM Corp. 2019,2020. All Rights Reserved.
2 | // Node module: @loopback/example-express-composition
3 | // This file is licensed under the MIT License.
4 | // License text available at https://opensource.org/licenses/MIT
5 |
6 | import {once} from 'events';
7 | import express, {Request, Response} from 'express';
8 | import http from 'http';
9 | import path from 'path';
10 | import {ApplicationConfig, NoteApplication} from './application';
11 |
12 | export {ApplicationConfig};
13 |
14 | export class ExpressServer {
15 | public readonly app: express.Application;
16 | public readonly lbApp: NoteApplication;
17 | private server?: http.Server;
18 |
19 | constructor(options: ApplicationConfig = {}) {
20 | this.app = express();
21 | this.lbApp = new NoteApplication(options);
22 |
23 | // Expose the front-end assets via Express, not as LB4 route
24 | this.app.use('/api', this.lbApp.requestHandler);
25 |
26 | // Custom Express routes
27 | this.app.get('/', function (_req: Request, res: Response) {
28 | res.sendFile(path.join(__dirname, '../public/express.html'));
29 | });
30 | this.app.get('/hello', function (_req: Request, res: Response) {
31 | res.send('Hello world!');
32 | });
33 |
34 | // Serve static files in the public folder
35 | this.app.use(express.static(path.join(__dirname, '../public')));
36 | }
37 |
38 | public async boot() {
39 | await this.lbApp.boot();
40 | }
41 |
42 | public async start() {
43 | await this.lbApp.start();
44 | const port = this.lbApp.restServer.config.port ?? 3000;
45 | const host = this.lbApp.restServer.config.host ?? '127.0.0.1';
46 | this.server = this.app.listen(port, host);
47 | await once(this.server, 'listening');
48 | }
49 |
50 | // For testing purposes
51 | public async stop() {
52 | if (!this.server) return;
53 | await this.lbApp.stop();
54 | this.server.close();
55 | await once(this.server, 'close');
56 | this.server = undefined;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/examples/lb4-express/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | LoopBack 4 REST API on Express
5 |
6 |
7 |
8 |
9 |
14 |
15 |
61 |
62 |
63 |
64 |
65 |
express-composition
66 |
Version 1.0.0
67 |
68 |
69 |
70 |
71 |
72 |
73 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/examples/lb4-express/src/__tests__/acceptance/express.acceptance.ts:
--------------------------------------------------------------------------------
1 | // Copyright IBM Corp. 2019,2020. All Rights Reserved.
2 | // Node module: @loopback/example-express-composition
3 | // This file is licensed under the MIT License.
4 | // License text available at https://opensource.org/licenses/MIT
5 |
6 | import {Client, expect} from '@loopback/testlab';
7 | import {HelloObserver} from '../../observers';
8 | import {ExpressServer} from '../../server';
9 | import {setupExpressApplication} from './test-helper';
10 |
11 | describe('ExpressApplication', () => {
12 | let server: ExpressServer;
13 | let client: Client;
14 |
15 | before('setupApplication', async () => {
16 | ({server, client} = await setupExpressApplication());
17 | });
18 |
19 | after('closes application', async () => {
20 | await server.stop();
21 | });
22 |
23 | it('displays front page', async () => {
24 | await client
25 | .get('/')
26 | .expect(200)
27 | .expect('Content-Type', /text\/html/);
28 | });
29 |
30 | it('displays a static page', async () => {
31 | await client
32 | .get('/notes.html')
33 | .expect(200)
34 | .expect('Content-Type', /text\/html/)
35 | .expect(/Notes/);
36 | });
37 |
38 | it('gets hello world', async () => {
39 | await client.get('/hello').expect(200).expect('Hello world!');
40 | });
41 |
42 | it('redirects to "api/explorer" from "api/explorer"', async () => {
43 | await client
44 | .get('/api/explorer')
45 | .expect(301)
46 | // expect relative redirect so that it works seamlessly with many forms
47 | // of base path, whether within the app or applied by a reverse proxy
48 | .expect('location', './explorer/');
49 | });
50 |
51 | it('displays explorer page', async () => {
52 | await client
53 | .get('/api/explorer/')
54 | .expect(200)
55 | .expect('content-type', /html/)
56 | .expect(/url\: '\.\/openapi\.json'\,/)
57 | .expect(/LoopBack API Explorer/);
58 | });
59 |
60 | it('triggers life cycle start', async () => {
61 | const observer: HelloObserver = await server.lbApp.get(
62 | 'lifeCycleObservers.HelloObserver',
63 | );
64 | expect(observer.events.length).to.be.above(0);
65 | expect(observer.events[0]).to.match(/hello-start$/);
66 | });
67 | });
68 |
--------------------------------------------------------------------------------
/examples/lb4-express/src/__tests__/acceptance/note.acceptance.ts:
--------------------------------------------------------------------------------
1 | // Copyright IBM Corp. 2019,2020. All Rights Reserved.
2 | // Node module: @loopback/example-express-composition
3 | // This file is licensed under the MIT License.
4 | // License text available at https://opensource.org/licenses/MIT
5 |
6 | import {Client, expect} from '@loopback/testlab';
7 | import {setupExpressApplication, givenNote} from './test-helper';
8 | import {NoteApplication} from '../../application';
9 | import {NoteRepository} from '../../repositories';
10 | import {ExpressServer} from '../../server';
11 |
12 | describe('NoteApplication', () => {
13 | let server: ExpressServer;
14 | let client: Client;
15 | let lbApp: NoteApplication;
16 | let noteRepo: NoteRepository;
17 |
18 | before('setupApplication', async () => {
19 | ({server, client, lbApp} = await setupExpressApplication());
20 | await changeDataSourceConfig();
21 | await givenNoteRepository();
22 | });
23 |
24 | beforeEach(async () => {
25 | await noteRepo.deleteAll();
26 | });
27 |
28 | after('closes application', async () => {
29 | await server.stop();
30 | });
31 |
32 | it('creates a note', async function () {
33 | const note = givenNote();
34 | const response = await client.post('/api/notes').send(note).expect(200);
35 | expect(response.body).to.containDeep(note);
36 | const result = await noteRepo.findById(response.body.id);
37 | expect(result).to.containDeep(note);
38 | });
39 |
40 | it('gets notes', async () => {
41 | const note = givenNote();
42 | let response = await client.get('/api/notes').expect(200);
43 | expect(response.body).to.be.empty();
44 | await client.post('/api/notes').send(note).expect(200);
45 | response = await client.get('/api/notes').expect(200);
46 | expect(response.body).to.not.be.empty();
47 | });
48 |
49 | it('displays static front page from Note app', async () => {
50 | await client
51 | .get('/api/')
52 | .expect(200)
53 | .expect('Content-Type', /text\/html/)
54 | .expect(/express-composition/);
55 | });
56 |
57 | async function givenNoteRepository() {
58 | noteRepo = await lbApp.getRepository(NoteRepository);
59 | }
60 |
61 | async function changeDataSourceConfig() {
62 | /**
63 | * Override default config for DataSource for testing so we don't write
64 | * test data to file when using the memory connector.
65 | */
66 | lbApp.bind('datasources.config.ds').to({
67 | name: 'ds',
68 | connector: 'memory',
69 | });
70 | }
71 | });
72 |
--------------------------------------------------------------------------------
/examples/lb4-express/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@loopback/example-express-composition",
3 | "version": "2.2.3",
4 | "description": "LoopBack 4 REST API on Express",
5 | "main": "dist/index.js",
6 | "types": "dist/index.d.ts",
7 | "keywords": [
8 | "loopback-application",
9 | "loopback",
10 | "example",
11 | "tutorial",
12 | "express"
13 | ],
14 | "engines": {
15 | "node": ">=10"
16 | },
17 | "scripts": {
18 | "presls-deploy": "npm run build",
19 | "sls-deploy": "serverless deploy --verbose",
20 | "sls-cleanup": "serverless remove --verbose",
21 | "presls-offline": "npm run build",
22 | "sls-offline": "serverless offline",
23 | "build": "lb-tsc",
24 | "build:watch": "lb-tsc --watch",
25 | "clean": "lb-clean *example-express-composition*.tgz dist *.tsbuildinfo package",
26 | "lint": "npm run prettier:check && npm run eslint",
27 | "lint:fix": "npm run eslint:fix && npm run prettier:fix",
28 | "prettier:cli": "lb-prettier \"**/*.ts\" \"**/*.js\"",
29 | "prettier:check": "npm run prettier:cli -- -l",
30 | "prettier:fix": "npm run prettier:cli -- --write",
31 | "eslint": "lb-eslint --report-unused-disable-directives .",
32 | "eslint:fix": "npm run eslint -- --fix",
33 | "pretest": "npm run clean && npm run build",
34 | "test": "lb-mocha \"dist/__tests__/**/*.js\"",
35 | "posttest": "npm run lint",
36 | "test:dev": "lb-mocha --allow-console-logs dist/__tests__/**/*.js && npm run posttest",
37 | "migrate": "node ./dist/migrate",
38 | "prestart": "npm run build",
39 | "start": "node ."
40 | },
41 | "repository": {
42 | "type": "git",
43 | "url": "https://github.com/strongloop/loopback-next.git",
44 | "directory": "examples/express-composition"
45 | },
46 | "author": "IBM Corp.",
47 | "copyright.owner": "IBM Corp.",
48 | "license": "MIT",
49 | "publishConfig": {
50 | "access": "public"
51 | },
52 | "dependencies": {
53 | "@loopback/boot": "^2.3.3",
54 | "@loopback/core": "^2.8.0",
55 | "@loopback/openapi-v3": "^3.4.3",
56 | "@loopback/repository": "^2.7.0",
57 | "@loopback/rest": "^5.1.1",
58 | "@loopback/rest-explorer": "^5.0.8",
59 | "@loopback/service-proxy": "^2.3.2",
60 | "express": "^4.17.1",
61 | "serverless-http": "^2.5.0",
62 | "tslib": "^2.0.0"
63 | },
64 | "devDependencies": {
65 | "@loopback/build": "^9.0.8",
66 | "@loopback/cli": "^2.9.0",
67 | "@loopback/eslint-config": "^8.0.1",
68 | "@loopback/testlab": "^3.1.7",
69 | "@types/express": "^4.17.6",
70 | "@types/node": "^10.17.26",
71 | "eslint": "^7.2.0",
72 | "serverless": "^3.28.1",
73 | "serverless-offline": "^12.0.4",
74 | "typescript": "~3.9.5"
75 | },
76 | "gitHead": "f31b7e6de5a405a015cdd774f63d699b35d943cc"
77 | }
78 |
--------------------------------------------------------------------------------
/examples/lb4-express/src/controllers/note.controller.ts:
--------------------------------------------------------------------------------
1 | // Copyright IBM Corp. 2019,2020. All Rights Reserved.
2 | // Node module: @loopback/example-express-composition
3 | // This file is licensed under the MIT License.
4 | // License text available at https://opensource.org/licenses/MIT
5 |
6 | import {
7 | Count,
8 | CountSchema,
9 | Filter,
10 | repository,
11 | Where,
12 | } from '@loopback/repository';
13 | import {
14 | del,
15 | get,
16 | getModelSchemaRef,
17 | param,
18 | patch,
19 | post,
20 | put,
21 | requestBody,
22 | } from '@loopback/rest';
23 | import {Note} from '../models';
24 | import {NoteRepository} from '../repositories';
25 |
26 | export class NoteController {
27 | constructor(
28 | @repository(NoteRepository)
29 | public noteRepository: NoteRepository,
30 | ) {}
31 |
32 | @post('/notes', {
33 | responses: {
34 | '200': {
35 | description: 'Note model instance',
36 | content: {'application/json': {schema: getModelSchemaRef(Note)}},
37 | },
38 | },
39 | })
40 | async create(
41 | @requestBody({
42 | content: {
43 | 'application/json': {
44 | schema: getModelSchemaRef(Note, {title: 'NewNote', exclude: ['id']}),
45 | },
46 | },
47 | })
48 | note: Omit,
49 | ): Promise {
50 | return this.noteRepository.create(note);
51 | }
52 |
53 | @get('/notes/count', {
54 | responses: {
55 | '200': {
56 | description: 'Note model count',
57 | content: {'application/json': {schema: CountSchema}},
58 | },
59 | },
60 | })
61 | async count(@param.where(Note) where?: Where): Promise {
62 | return this.noteRepository.count(where);
63 | }
64 |
65 | @get('/notes', {
66 | responses: {
67 | '200': {
68 | description: 'Array of Note model instances',
69 | content: {
70 | 'application/json': {
71 | schema: {type: 'array', items: getModelSchemaRef(Note)},
72 | },
73 | },
74 | },
75 | },
76 | })
77 | async find(
78 | @param.filter(Note)
79 | filter?: Filter,
80 | ): Promise {
81 | return this.noteRepository.find(filter);
82 | }
83 |
84 | @patch('/notes', {
85 | responses: {
86 | '200': {
87 | description: 'Note PATCH success count',
88 | content: {'application/json': {schema: CountSchema}},
89 | },
90 | },
91 | })
92 | async updateAll(
93 | @requestBody({
94 | content: {
95 | 'application/json': {
96 | schema: getModelSchemaRef(Note, {partial: true}),
97 | },
98 | },
99 | })
100 | note: Partial,
101 | @param.where(Note) where?: Where,
102 | ): Promise {
103 | return this.noteRepository.updateAll(note, where);
104 | }
105 |
106 | @get('/notes/{id}', {
107 | responses: {
108 | '200': {
109 | description: 'Note model instance',
110 | content: {'application/json': {schema: getModelSchemaRef(Note)}},
111 | },
112 | },
113 | })
114 | async findById(@param.path.number('id') id: number): Promise {
115 | return this.noteRepository.findById(id);
116 | }
117 |
118 | @patch('/notes/{id}', {
119 | responses: {
120 | '204': {
121 | description: 'Note PATCH success',
122 | },
123 | },
124 | })
125 | async updateById(
126 | @param.path.number('id') id: number,
127 | @requestBody({
128 | content: {
129 | 'application/json': {
130 | schema: getModelSchemaRef(Note, {partial: true}),
131 | },
132 | },
133 | })
134 | note: Partial,
135 | ): Promise {
136 | await this.noteRepository.updateById(id, note);
137 | }
138 |
139 | @put('/notes/{id}', {
140 | responses: {
141 | '204': {
142 | description: 'Note PUT success',
143 | },
144 | },
145 | })
146 | async replaceById(
147 | @param.path.number('id') id: number,
148 | @requestBody() note: Note,
149 | ): Promise {
150 | await this.noteRepository.replaceById(id, note);
151 | }
152 |
153 | @del('/notes/{id}', {
154 | responses: {
155 | '204': {
156 | description: 'Note DELETE success',
157 | },
158 | },
159 | })
160 | async deleteById(@param.path.number('id') id: number): Promise {
161 | await this.noteRepository.deleteById(id);
162 | }
163 | }
164 |
--------------------------------------------------------------------------------
/examples/lb3-express/README.md:
--------------------------------------------------------------------------------
1 | # examples/lb3-express
2 |
3 | This example shows how to use the [serverless framework](https://www.serverless.com/framework/docs/providers/aws/) to run loopback3 (with express) in [AWS Lambda](https://docs.aws.amazon.com/lambda/latest/dg/lambda-nodejs.html).
4 |
5 | ## Overview
6 |
7 | A RDS (MySQL) database is created, along with all necessary virtual AWS infrastructure (VPC, subnets, DBSubnetGroup) to connect a lambda function running loopback to the MySQL database. The MySQL connection parameters are retrieved from lambda environment variables.
8 |
10 |
11 | Check out [this article](https://medium.com/smac-4u/serverless-loopback-9ff0d6fa539d) for a more in-depth explanation of this sample.
12 |
13 | ## About Sample Provided
14 |
15 | The sample loopback application provided was created by following the process below:
16 |
17 | 1. Using the command `npm run lb` and selecting:
18 |
19 | - What kind of application do you have in mind? `api-server (A LoopBack API server with local User auth)`
20 |
21 | 2. Adding a new MySQL database to `lib/server/datasources.json`.
22 |
23 | 3. Adding the CoffeeShop model and initializing it with data:
24 |
25 | - `lib/common/coffee-shop.json`: CoffeeShop model definition
26 | - `lib/server/model-config.json`: add CoffeeShop model so it can be loaded
27 | - `lib/server/boot/create-sample-models.js`: initialize CoffeeShop model with data
28 |
29 | ## Customizing & Deploying This Sample
30 |
31 | The following steps can be used to customize this sample to your needs and then deploy:
32 |
33 |
35 | 1. Create your own loopback models with the command `npm run lb-model`
36 |
37 | 2. The RDS `mySqlDb` in `serverless.yml` is configured to be as low cost as possible (not suitable for production!) so feel free to [customize it to your needs](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-rds-database-instance.html).
38 |
39 | 3. Deploy your project to AWS using the command `npm run sls-deploy`
40 |
41 | 4. From the serverless `Stack Outputs`, retrieve `LoopbackApiExplorer` to access the loopback4 API explorer (it should look something like `https://API_GATEWAY_ID.execute-api.AWS_REGION.amazonaws.com/SERVERLESS_STAGE/api/explorer/`). You should end up with an URL similar to `https://XXXXXXXXXX.execute-api.us-east-1.amazonaws.com/dev/api/explorer/`.
42 |
43 | *Note*: An error might be observed the first time lambda runs after (re-)creating the RDS database as the CoffeeTable model table might not be initialized before your API is invoked. This error would look something like:
44 |
45 | ```json
46 | {
47 | "error": {
48 | "statusCode": 500,
49 | "name": "Error",
50 | "message": "ER_NO_SUCH_TABLE: Table 'MY_TEST_DB.CoffeeShop' doesn't exist",
51 | "code": "ER_NO_SUCH_TABLE",
52 | "errno": 1146,
53 | "sqlMessage": "Table 'MY_TEST_DB.CoffeeShop' doesn't exist",
54 | "sqlState": "42S02",
55 | "index": 0,
56 | "sql": "SELECT count(*) as \"cnt\" FROM `CoffeeShop` ",
57 | "stack": "Error: ER_NO_SUCH_TABLE: Table 'MY_TEST_DB.CoffeeShop' doesn't exist\n at ..."
58 | }
59 | }
60 | ```
61 |
62 | Retry after a few seconds and it all should work.
63 |
64 | ## Cleaning Up The Sample
65 |
66 | Once you are done with the sample environment, avoid unnecessary AWS charges by removing your serverless deployment with the command `npm run sls-cleanup`.
67 |
68 | If you run into a cleanup [error similar to the one below](https://forum.serverless.com/t/very-long-delay-when-doing-sls-remove-of-lambda-in-a-vpc/2535), you will need to manually remove the CloudFormation stack by going to: or using the [aws-cli](https://aws.amazon.com/cli/).
69 |
70 | ```shell
71 | Serverless Error ---------------------------------------
72 |
73 | An error occurred: mySubnet2 - The subnet 'subnet-077e0f72824fe5dd3' has dependencies and cannot be deleted. (Service: AmazonEC2; Status Code: 400; Error Code: DependencyViolation; Request ID: XXX).
74 | ```
75 |
76 | ## License
77 |
78 | MIT © [BotBitsSM](https://github.com/botbits)
79 |
--------------------------------------------------------------------------------
/examples/lb3-express/serverless.yml:
--------------------------------------------------------------------------------
1 | service: serverless-loopback
2 | provider:
3 | name: aws
4 | runtime: nodejs8.10
5 | stage: ${opt:stage, self:custom.defaultStage}
6 | region: us-east-1
7 |
8 | custom:
9 | defaultStage: dev
10 | DB:
11 | dev:
12 | # HOST: MY_HOST # provide this information if DB already exists
13 | # PORT: MY_PORT # provide this information if DB already exists
14 | NAME: MY_TEST_DB
15 | USERNAME: admin
16 | PASSWORD: password
17 |
18 | functions:
19 | loopback:
20 | handler: lambda-wrapper.handler
21 | name: '${self:provider.stage}-loopback'
22 | description: Sample loopback running in AWS lambda
23 | memorySize: 512
24 | timeout: 60
25 | events:
26 | - http: ANY /
27 | - http: ANY {proxy+}
28 | environment:
29 | DB_HOST: { 'Fn::GetAtt': ['mySqlDb', 'Endpoint.Address' ] }
30 | DB_PORT: { 'Fn::GetAtt': ['mySqlDb', 'Endpoint.Port' ] }
31 | DB_NAME: '${self:custom.DB.${self:provider.stage}.NAME}'
32 | DB_USERNAME: '${self:custom.DB.${self:provider.stage}.USERNAME}' # this will show in clear text in CloudFormation
33 | DB_PASSWORD: '${self:custom.DB.${self:provider.stage}.PASSWORD}' # this will show in clear text in CloudFormation
34 | vpc:
35 | securityGroupIds:
36 | - { 'Fn::GetAtt' : ['myVPC', 'DefaultSecurityGroup'] }
37 | subnetIds:
38 | - Ref: mySubnet1
39 | - Ref: mySubnet2
40 |
41 | resources:
42 | Resources:
43 | # https://serverless.com/framework/docs/providers/aws/guide/resources#aws-cloudformation-resource-reference
44 | # uses CloudFormation syntax - https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html
45 | myVPC:
46 | Type: AWS::EC2::VPC
47 | Properties:
48 | CidrBlock: 172.31.0.0/16
49 | Tags:
50 | - Key: Name
51 | Value: ${self:service}-vpc
52 |
53 | mySubnet1:
54 | Type: AWS::EC2::Subnet
55 | Properties:
56 | AvailabilityZone: ${self:provider.region}a
57 | VpcId:
58 | Ref: myVPC
59 | CidrBlock: 172.31.0.0/20
60 |
61 | mySubnet2:
62 | Type: AWS::EC2::Subnet
63 | Properties:
64 | AvailabilityZone: ${self:provider.region}b
65 | VpcId:
66 | Ref: myVPC
67 | CidrBlock: 172.31.16.0/20
68 |
69 | myDBSubnetGroup:
70 | Type: 'AWS::RDS::DBSubnetGroup'
71 | Properties:
72 | DBSubnetGroupDescription: 'description'
73 | SubnetIds:
74 | - Ref: mySubnet1
75 | - Ref: mySubnet2
76 |
77 | mySqlDb:
78 | # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-rds-database-instance.html
79 | Type: AWS::RDS::DBInstance
80 | Properties:
81 | AllocatedStorage: '5' # minimal size for this sample
82 | BackupRetentionPeriod: 0 # disabling backups for this sample
83 | DBInstanceClass: 'db.t2.micro' # minimal size for this sample
84 | DBName: '${self:custom.DB.${self:provider.stage}.NAME}' # creating a database for this sample
85 | DBSubnetGroupName: { 'Ref' : 'myDBSubnetGroup' }
86 | Engine: 'mysql'
87 | MasterUsername: '${self:custom.DB.${self:provider.stage}.USERNAME}' # this will show in clear text in CloudFormation
88 | MasterUserPassword: '${self:custom.DB.${self:provider.stage}.PASSWORD}' # this will show in clear text in CloudFormation
89 | MultiAZ: false # disabling for this sample
90 | PubliclyAccessible: false
91 | VPCSecurityGroups:
92 | - { 'Fn::GetAtt' : ['myVPC', 'DefaultSecurityGroup'] }
93 |
94 | # The "Outputs" that your AWS CloudFormation Stack should produce. This allows references between services.
95 | Outputs:
96 | DbInstanceIdentifier:
97 | Description: The DB Name for the (MySQL) RDS created
98 | Value:
99 | Ref: mySqlDb
100 | LoopbackPostman:
101 | Description: The baseUrl value to configure for your Postman collection
102 | Value:
103 | 'Fn::Join':
104 | - ''
105 | - - 'https://'
106 | - Ref: 'ApiGatewayRestApi'
107 | - '.execute-api.'
108 | - Ref: 'AWS::Region'
109 | - '.'
110 | - Ref: 'AWS::URLSuffix'
111 | - '/${self:provider.stage}/api'
112 | LoopbackApiExplorer:
113 | Description: The URL to directly access the loopback API explorer
114 | Value:
115 | 'Fn::Join':
116 | - ''
117 | - - 'https://'
118 | - Ref: 'ApiGatewayRestApi'
119 | - '.execute-api.'
120 | - Ref: 'AWS::Region'
121 | - '.'
122 | - Ref: 'AWS::URLSuffix'
123 | - '/${self:provider.stage}/api/explorer/'
124 |
--------------------------------------------------------------------------------
/examples/lb3-express/.snyk:
--------------------------------------------------------------------------------
1 | # Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.
2 | version: v1.13.5
3 | ignore: {}
4 | # patches apply the minimum changes required to fix a vulnerability
5 | patch:
6 | SNYK-JS-LODASH-450202:
7 | - loopback > loopback-datasource-juggler > async > lodash:
8 | patched: '2019-07-06T05:03:14.104Z'
9 | - loopback-connector-mysql > lodash:
10 | patched: '2019-07-06T05:03:14.104Z'
11 | - loopback-component-explorer > lodash:
12 | patched: '2019-07-06T05:03:14.104Z'
13 | - loopback-component-explorer > loopback-swagger > lodash:
14 | patched: '2019-07-06T05:03:14.104Z'
15 | - strong-error-handler > strong-globalize > lodash:
16 | patched: '2019-07-06T05:03:14.104Z'
17 | - loopback-boot > strong-globalize > lodash:
18 | patched: '2019-07-06T05:03:14.104Z'
19 | - loopback > async > lodash:
20 | patched: '2019-07-06T05:03:14.104Z'
21 | - loopback-connector-mysql > async > lodash:
22 | patched: '2019-07-06T05:03:14.104Z'
23 | - loopback-connector-mysql > strong-globalize > lodash:
24 | patched: '2019-07-06T05:03:14.104Z'
25 | - loopback-component-explorer > strong-globalize > lodash:
26 | patched: '2019-07-06T05:03:14.104Z'
27 | - loopback > strong-globalize > lodash:
28 | patched: '2019-07-06T05:03:14.104Z'
29 | - loopback > loopback-datasource-juggler > lodash:
30 | patched: '2019-07-06T05:03:14.104Z'
31 | - loopback-component-explorer > loopback-swagger > async > lodash:
32 | patched: '2019-07-06T05:03:14.104Z'
33 | - loopback > loopback-phase > strong-globalize > lodash:
34 | patched: '2019-07-06T05:03:14.104Z'
35 | - loopback > strong-remoting > jayson > lodash:
36 | patched: '2019-07-06T05:03:14.104Z'
37 | - loopback > loopback-connector-remote > loopback-datasource-juggler > lodash:
38 | patched: '2019-07-06T05:03:14.104Z'
39 | - loopback-connector-mysql > loopback-connector > strong-globalize > lodash:
40 | patched: '2019-07-06T05:03:14.104Z'
41 | - loopback > strong-remoting > async > lodash:
42 | patched: '2019-07-06T05:03:14.104Z'
43 | - loopback-connector-mysql > loopback-connector > async > lodash:
44 | patched: '2019-07-06T05:03:14.104Z'
45 | - loopback-component-explorer > loopback-swagger > strong-globalize > lodash:
46 | patched: '2019-07-06T05:03:14.104Z'
47 | - loopback-boot > lodash:
48 | patched: '2019-07-06T05:03:14.104Z'
49 | - loopback > loopback-phase > async > lodash:
50 | patched: '2019-07-06T05:03:14.104Z'
51 | - loopback > loopback-datasource-juggler > strong-globalize > lodash:
52 | patched: '2019-07-06T05:03:14.104Z'
53 | - loopback > strong-remoting > strong-globalize > lodash:
54 | patched: '2019-07-06T05:03:14.104Z'
55 | - loopback > loopback-connector-remote > strong-remoting > jayson > lodash:
56 | patched: '2019-07-06T05:03:14.104Z'
57 | - loopback > loopback-connector-remote > strong-remoting > strong-globalize > lodash:
58 | patched: '2019-07-06T05:03:14.104Z'
59 | - loopback > loopback-connector-remote > strong-remoting > async > lodash:
60 | patched: '2019-07-06T05:03:14.104Z'
61 | - loopback > strong-remoting > loopback-phase > async > lodash:
62 | patched: '2019-07-06T05:03:14.104Z'
63 | - loopback > strong-remoting > loopback-phase > strong-globalize > lodash:
64 | patched: '2019-07-06T05:03:14.104Z'
65 | - loopback > loopback-datasource-juggler > loopback-connector > async > lodash:
66 | patched: '2019-07-06T05:03:14.104Z'
67 | - loopback > loopback-connector-remote > loopback-datasource-juggler > strong-globalize > lodash:
68 | patched: '2019-07-06T05:03:14.104Z'
69 | - loopback > loopback-datasource-juggler > loopback-connector > strong-globalize > lodash:
70 | patched: '2019-07-06T05:03:14.104Z'
71 | - loopback > strong-remoting > strong-error-handler > strong-globalize > lodash:
72 | patched: '2019-07-06T05:03:14.104Z'
73 | - loopback > loopback-connector-remote > loopback-datasource-juggler > async > lodash:
74 | patched: '2019-07-06T05:03:14.104Z'
75 | - loopback-boot > strong-globalize > g11n-pipeline > swagger-client > lodash:
76 | patched: '2019-07-06T05:03:14.104Z'
77 | - loopback > loopback-connector-remote > loopback-datasource-juggler > loopback-connector > strong-globalize > lodash:
78 | patched: '2019-07-06T05:03:14.104Z'
79 | - loopback > loopback-connector-remote > strong-remoting > loopback-phase > strong-globalize > lodash:
80 | patched: '2019-07-06T05:03:14.104Z'
81 | - loopback > loopback-connector-remote > loopback-datasource-juggler > loopback-connector > async > lodash:
82 | patched: '2019-07-06T05:03:14.104Z'
83 | - loopback > loopback-connector-remote > strong-remoting > strong-error-handler > strong-globalize > lodash:
84 | patched: '2019-07-06T05:03:14.104Z'
85 | - loopback > loopback-connector-remote > strong-remoting > loopback-phase > async > lodash:
86 | patched: '2019-07-06T05:03:14.104Z'
87 | - loopback-boot > strong-globalize > g11n-pipeline > swagger-client > isomorphic-form-data > form-data > async > lodash:
88 | patched: '2019-07-06T05:03:14.104Z'
89 | SNYK-JS-HTTPSPROXYAGENT-469131:
90 | - snyk > proxy-agent > https-proxy-agent:
91 | patched: '2019-10-05T05:08:23.949Z'
92 | - snyk > proxy-agent > pac-proxy-agent > https-proxy-agent:
93 | patched: '2019-10-05T05:08:23.949Z'
94 |
--------------------------------------------------------------------------------
/examples/lb4-express/README.md:
--------------------------------------------------------------------------------
1 | # examples/lb4-express
2 |
3 | This example shows how to use the [serverless framework](https://www.serverless.com/framework/docs/providers/aws/) to run loopback4 (with express) in [AWS Lambda](https://docs.aws.amazon.com/lambda/latest/dg/lambda-nodejs.html).
4 |
5 | ## Overview
6 |
7 | A RDS (MySQL) database is created, along with all necessary virtual AWS infrastructure (VPC, subnets, DBSubnetGroup) to connect a lambda function running loopback4 to the MySQL database. The MySQL connection parameters are retrieved from lambda environment variables.
8 |
10 |
11 |
14 |
15 | ## About Sample Provided
16 |
17 | The sample loopback4 application provided was created by following the process below:
18 |
19 | 1. Create an Express Application with LoopBack REST API by following [this tutorial](https://loopback.io/doc/en/lb4/express-with-lb4-rest-tutorial.html). We followed the shortcut by running the command `lb4 example express-composition`.
20 |
21 | 2. Remove the `file` parameter from the [memory datasource](src/datasources/ds.datasource.ts) to avoid lambda errors.
22 |
23 | 3. Create the following files required to deploying it all to AWS Lambda using the [serverless framework](https://www.serverless.com/framework/docs/providers/aws/):
24 |
25 | - [`src/lambda-wrapper.js`](src/lambda-wrapper.js): this file uses [`serverless-http`](https://www.npmjs.com/package/serverless-http) to wrap the loopback4 application via [express](https://www.npmjs.com/package/express).
26 |
27 | - [`serverless.yml`](serverless.yml): our [*serverless* service definition](https://www.serverless.com/framework/docs/providers/aws/guide/serverless.yml/). Here is where we create all AWS resources (including Lambda, and API Gateway).
28 |
29 | 4. Update your `tsconfig.json` file to include `"allowJs": true` in your `compilerOptions` section to ensire the [`src/lambda-wrapper.js`](src/lambda-wrapper.js) file is included in the loopback4 build.
30 |
31 | 5. Install the `serverless-http` module and its dependencies with command `npm install serverless-http`.
32 |
33 | 6. Install the `serverless` module and its dependencies with command `npm install -D serverless`.
34 |
35 | 7. As we planed to troubleshoot locally, we installed the `serverless-offline` module and its dependencies with command `npm install -D serverless-offline`.
36 |
37 | 8. In order to ensure your loopback4 application is built prior to deploying it to AWS Lambda or running it locally we included the following scripts in the `package.json` file:
38 |
39 | ```
40 | "presls-deploy": "npm run build",
41 | "sls-deploy": "serverless deploy --verbose",
42 | "sls-cleanup": "serverless remove --verbose",
43 | "presls-offline": "npm run build",
44 | "sls-offline": "serverless offline",
45 | ```
46 |
47 | Please note that `serverless-http` also supports [other web frameworks](https://www.npmjs.com/package/serverless-http#supported-frameworks). The loopback support indicated is for [`@loopback-rest`](https://www.npmjs.com/package/@loopback/rest). Please feel free to contribute your examples of using loopback4 with other web frameworks under the `examples` folder.
48 |
49 | ## Customizing & Deploying This Sample
50 |
51 | The following steps can be used to customize this sample to your needs and then deploy:
52 |
53 |
55 | 1. Create your own loopback models, datasources, repositories, and controllers.
56 |
57 | 2. Deploy your project to AWS using the command `npm run sls-deploy`
58 |
59 | 3. From the serverless `Stack Outputs`, retrieve `LoopbackApiExplorer` to access the loopback4 API explorer (it should look something like `https://API_GATEWAY_ID.execute-api.AWS_REGION.amazonaws.com/SERVERLESS_STAGE/api/explorer/`). You should end up with an URL similar to `https://XXXXXXXXXX.execute-api.us-east-1.amazonaws.com/dev/api/explorer/`.
60 |
61 | 4. From the lopback4 API explorer download the `openapi.json` file and [import it into Postman](https://learning.postman.com/docs/postman/collections/importing-and-exporting-data/#importing-api-specifications). After importing, make sure to edit the imported collection and change the `baseUrl` variable to the value of the serverless `LoopbackPostman` `Stack Outputs`. This will make sure Postman works with your serverless API Gateway rather than the loopback4 only path.
62 |
63 | ## Cleaning Up The Sample
64 |
65 | Once you are done with the sample environment, avoid unnecessary AWS charges by removing your serverless deployment with the command `npm run sls-cleanup`.
66 |
67 | ## Known Issues
68 |
69 | While the serverless deployment works fine, invoking the API through API explorer never reaches API Gateway as CloudFront responds with Code 403:
70 |
71 | **Response body**
72 | ```
73 | {
74 | "message": "Forbidden"
75 | }
76 | ```
77 | **Response headers**
78 | ```
79 | content-length: 24
80 | content-type: application/json
81 | date: Sun14 Jun 2020 14:14:09 GMT via: 1.1 0dfe6f02dbba7c39906cae47653ae6b3.cloudfront.net (CloudFront)
82 | x-amz-apigw-id: OOYDwFjZiYcFSAA=
83 | x-amz-cf-id: 3SvwvE27qb1KIrS34rgRRwet-QOkfZyFeJOIMUbHMgi6dA5-BgBEeg==
84 | x-amz-cf-pop: DEN50-C2
85 | x-amzn-errortype: ForbiddenException
86 | x-amzn-requestid: 31a0c024-6ffe-4c3c-b9d9-adfca9add4b0
87 | x-cache: Error from cloudfront
88 | x-firefox-spdy: h2
89 | ```
90 | ## License
91 |
92 | MIT © [BotBitsSM](https://github.com/botbits)
93 |
--------------------------------------------------------------------------------
/examples/lb4-express/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5 |
6 | ## [2.2.3](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@2.2.2...@loopback/example-express-composition@2.2.3) (2020-06-11)
7 |
8 | **Note:** Version bump only for package @loopback/example-express-composition
9 |
10 |
11 |
12 |
13 |
14 | ## [2.2.2](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@2.2.1...@loopback/example-express-composition@2.2.2) (2020-05-28)
15 |
16 | **Note:** Version bump only for package @loopback/example-express-composition
17 |
18 |
19 |
20 |
21 |
22 | ## [2.2.1](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@2.2.0...@loopback/example-express-composition@2.2.1) (2020-05-20)
23 |
24 | **Note:** Version bump only for package @loopback/example-express-composition
25 |
26 |
27 |
28 |
29 |
30 | # [2.2.0](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@2.1.1...@loopback/example-express-composition@2.2.0) (2020-05-19)
31 |
32 |
33 | ### Features
34 |
35 | * upgrade to TypeScript 3.9.x ([3300e45](https://github.com/strongloop/loopback-next/commit/3300e4569ab8410bb1285f7a54d326e9d976476d))
36 |
37 |
38 |
39 |
40 |
41 | ## [2.1.1](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@2.1.0...@loopback/example-express-composition@2.1.1) (2020-05-07)
42 |
43 | **Note:** Version bump only for package @loopback/example-express-composition
44 |
45 |
46 |
47 |
48 |
49 | # [2.1.0](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@2.0.6...@loopback/example-express-composition@2.1.0) (2020-04-29)
50 |
51 |
52 | ### Features
53 |
54 | * move datasource config from JSON to TS files ([6105456](https://github.com/strongloop/loopback-next/commit/6105456deb6d7acadc3e46867558311dce2d005c))
55 |
56 |
57 |
58 |
59 |
60 | ## [2.0.6](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@2.0.5...@loopback/example-express-composition@2.0.6) (2020-04-23)
61 |
62 | **Note:** Version bump only for package @loopback/example-express-composition
63 |
64 |
65 |
66 |
67 |
68 | ## [2.0.5](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@2.0.4...@loopback/example-express-composition@2.0.5) (2020-04-22)
69 |
70 | **Note:** Version bump only for package @loopback/example-express-composition
71 |
72 |
73 |
74 |
75 |
76 | ## [2.0.4](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@2.0.3...@loopback/example-express-composition@2.0.4) (2020-04-11)
77 |
78 | **Note:** Version bump only for package @loopback/example-express-composition
79 |
80 |
81 |
82 |
83 |
84 | ## [2.0.3](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@2.0.2...@loopback/example-express-composition@2.0.3) (2020-04-08)
85 |
86 |
87 | ### Bug Fixes
88 |
89 | * **example-express-composition:** use an assinged port number for testing ([9a0997f](https://github.com/strongloop/loopback-next/commit/9a0997f61d1afb2376cbca29fa46ad855b5a0801))
90 |
91 |
92 |
93 |
94 |
95 | ## [2.0.2](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@2.0.1...@loopback/example-express-composition@2.0.2) (2020-03-24)
96 |
97 | **Note:** Version bump only for package @loopback/example-express-composition
98 |
99 |
100 |
101 |
102 |
103 | ## [2.0.1](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@2.0.0...@loopback/example-express-composition@2.0.1) (2020-03-17)
104 |
105 | **Note:** Version bump only for package @loopback/example-express-composition
106 |
107 |
108 |
109 |
110 |
111 | # [2.0.0](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.10.4...@loopback/example-express-composition@2.0.0) (2020-03-05)
112 |
113 |
114 | ### Bug Fixes
115 |
116 | * remove ref for v4.loopback.io ([78f20c0](https://github.com/strongloop/loopback-next/commit/78f20c0ed4db5f3ce0d7b676449ba3b22526319e))
117 |
118 |
119 | ### chore
120 |
121 | * remove support for Node.js v8.x ([4281d9d](https://github.com/strongloop/loopback-next/commit/4281d9df50f0715d32879e1442a90b643ec8f542))
122 |
123 |
124 | ### Features
125 |
126 | * add `tslib` as dependency ([a6e0b4c](https://github.com/strongloop/loopback-next/commit/a6e0b4ce7b862764167cefedee14c1115b25e0a4)), closes [#4676](https://github.com/strongloop/loopback-next/issues/4676)
127 | * use [@param](https://github.com/param).filter and [@param](https://github.com/param).where decorators ([896ef74](https://github.com/strongloop/loopback-next/commit/896ef7485376b3aedcca01a40f828bf1ed9470ae))
128 |
129 |
130 | ### BREAKING CHANGES
131 |
132 | * Node.js v8.x is now end of life. Please upgrade to version
133 | 10 and above. See https://nodejs.org/en/about/releases.
134 |
135 |
136 |
137 |
138 |
139 | ## [1.10.4](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.10.3...@loopback/example-express-composition@1.10.4) (2020-02-06)
140 |
141 | **Note:** Version bump only for package @loopback/example-express-composition
142 |
143 |
144 |
145 |
146 |
147 | ## [1.10.3](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.10.2...@loopback/example-express-composition@1.10.3) (2020-02-05)
148 |
149 |
150 | ### Bug Fixes
151 |
152 | * update clean script for examples to be compatible with `lb4 example` ([d9f5741](https://github.com/strongloop/loopback-next/commit/d9f574160f6edbf73a8f728cd3695ca69297148a))
153 |
154 |
155 |
156 |
157 |
158 | ## [1.10.2](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.10.1...@loopback/example-express-composition@1.10.2) (2020-01-27)
159 |
160 | **Note:** Version bump only for package @loopback/example-express-composition
161 |
162 |
163 |
164 |
165 |
166 | ## [1.10.1](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.10.0...@loopback/example-express-composition@1.10.1) (2020-01-07)
167 |
168 | **Note:** Version bump only for package @loopback/example-express-composition
169 |
170 |
171 |
172 |
173 |
174 | # [1.10.0](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.9.2...@loopback/example-express-composition@1.10.0) (2020-01-07)
175 |
176 |
177 | ### Features
178 |
179 | * add title property to ping response schema definition ([b8b7490](https://github.com/strongloop/loopback-next/commit/b8b7490ce29d0973208ba38c3365de9091b7a795))
180 |
181 |
182 |
183 |
184 |
185 | ## [1.9.2](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.9.1...@loopback/example-express-composition@1.9.2) (2019-12-09)
186 |
187 | **Note:** Version bump only for package @loopback/example-express-composition
188 |
189 |
190 |
191 |
192 |
193 | ## [1.9.1](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.9.0...@loopback/example-express-composition@1.9.1) (2019-11-25)
194 |
195 | **Note:** Version bump only for package @loopback/example-express-composition
196 |
197 |
198 |
199 |
200 |
201 | # [1.9.0](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.8.1...@loopback/example-express-composition@1.9.0) (2019-11-12)
202 |
203 |
204 | ### Features
205 |
206 | * **cli:** generate datasource json with '.config.json` extension ([51d8f7b](https://github.com/strongloop/loopback-next/commit/51d8f7b20ec59f888fd6d0634efb47d111f00ef7))
207 |
208 |
209 |
210 |
211 |
212 | ## [1.8.1](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.8.0...@loopback/example-express-composition@1.8.1) (2019-10-24)
213 |
214 | **Note:** Version bump only for package @loopback/example-express-composition
215 |
216 |
217 |
218 |
219 |
220 | # [1.8.0](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.7.1...@loopback/example-express-composition@1.8.0) (2019-10-07)
221 |
222 |
223 | ### Features
224 |
225 | * **example-express-composition:** add code path to allow life cycle observers ([8d3401d](https://github.com/strongloop/loopback-next/commit/8d3401d))
226 |
227 |
228 |
229 |
230 |
231 | ## [1.7.1](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.7.0...@loopback/example-express-composition@1.7.1) (2019-09-28)
232 |
233 | **Note:** Version bump only for package @loopback/example-express-composition
234 |
235 |
236 |
237 |
238 |
239 | # [1.7.0](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.6.0...@loopback/example-express-composition@1.7.0) (2019-09-27)
240 |
241 |
242 | ### Features
243 |
244 | * self host oas spec by default on relative path in explorer ([887556e](https://github.com/strongloop/loopback-next/commit/887556e))
245 |
246 |
247 |
248 |
249 |
250 | # [1.6.0](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.5.6...@loopback/example-express-composition@1.6.0) (2019-09-17)
251 |
252 |
253 | ### Features
254 |
255 | * use descriptive title to describe schema of POST (create) request bodies ([8f49a45](https://github.com/strongloop/loopback-next/commit/8f49a45))
256 |
257 |
258 |
259 |
260 |
261 | ## [1.5.6](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.5.5...@loopback/example-express-composition@1.5.6) (2019-09-06)
262 |
263 | **Note:** Version bump only for package @loopback/example-express-composition
264 |
265 |
266 |
267 |
268 |
269 | ## [1.5.5](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.5.4...@loopback/example-express-composition@1.5.5) (2019-09-03)
270 |
271 | **Note:** Version bump only for package @loopback/example-express-composition
272 |
273 |
274 |
275 |
276 |
277 | ## [1.5.4](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.5.3...@loopback/example-express-composition@1.5.4) (2019-08-19)
278 |
279 | **Note:** Version bump only for package @loopback/example-express-composition
280 |
281 |
282 |
283 |
284 |
285 | ## [1.5.3](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.5.2...@loopback/example-express-composition@1.5.3) (2019-08-15)
286 |
287 | **Note:** Version bump only for package @loopback/example-express-composition
288 |
289 |
290 |
291 |
292 |
293 | ## [1.5.2](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.5.1...@loopback/example-express-composition@1.5.2) (2019-08-15)
294 |
295 | **Note:** Version bump only for package @loopback/example-express-composition
296 |
297 |
298 |
299 |
300 |
301 | ## [1.5.1](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.5.0...@loopback/example-express-composition@1.5.1) (2019-07-31)
302 |
303 | **Note:** Version bump only for package @loopback/example-express-composition
304 |
305 |
306 |
307 |
308 |
309 | # [1.5.0](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.4.6...@loopback/example-express-composition@1.5.0) (2019-07-26)
310 |
311 |
312 | ### Features
313 |
314 | * update examples and docs to use getModelSchemaRef ([99758b1](https://github.com/strongloop/loopback-next/commit/99758b1))
315 |
316 |
317 |
318 |
319 |
320 | ## [1.4.6](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.4.5...@loopback/example-express-composition@1.4.6) (2019-07-17)
321 |
322 |
323 | ### Bug Fixes
324 |
325 | * **example-express-composition:** exclude id from POST request body ([9158142](https://github.com/strongloop/loopback-next/commit/9158142))
326 |
327 |
328 |
329 |
330 |
331 | ## [1.4.5](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.4.4...@loopback/example-express-composition@1.4.5) (2019-06-28)
332 |
333 |
334 | ### Bug Fixes
335 |
336 | * **example-express-composition:** allow partial updates via PATCH ([15189ee](https://github.com/strongloop/loopback-next/commit/15189ee))
337 |
338 |
339 |
340 |
341 |
342 | ## [1.4.4](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.4.3...@loopback/example-express-composition@1.4.4) (2019-06-21)
343 |
344 | **Note:** Version bump only for package @loopback/example-express-composition
345 |
346 |
347 |
348 |
349 |
350 | ## [1.4.3](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.4.2...@loopback/example-express-composition@1.4.3) (2019-06-20)
351 |
352 | **Note:** Version bump only for package @loopback/example-express-composition
353 |
354 |
355 |
356 |
357 |
358 | ## [1.4.2](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.4.1...@loopback/example-express-composition@1.4.2) (2019-06-17)
359 |
360 |
361 | ### Bug Fixes
362 |
363 | * remove forgotten references to tslint ([faa0a92](https://github.com/strongloop/loopback-next/commit/faa0a92))
364 |
365 |
366 |
367 |
368 |
369 | ## [1.4.1](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.4.0...@loopback/example-express-composition@1.4.1) (2019-06-06)
370 |
371 | **Note:** Version bump only for package @loopback/example-express-composition
372 |
373 |
374 |
375 |
376 |
377 | # [1.4.0](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.3.3...@loopback/example-express-composition@1.4.0) (2019-06-03)
378 |
379 |
380 | ### Bug Fixes
381 |
382 | * **example-express-composition:** update migrate script file location ([8a6c072](https://github.com/strongloop/loopback-next/commit/8a6c072))
383 |
384 |
385 | ### Features
386 |
387 | * add navigational properties to find* methods ([1f0aa0b](https://github.com/strongloop/loopback-next/commit/1f0aa0b))
388 | * replace tslint with eslint ([44185a7](https://github.com/strongloop/loopback-next/commit/44185a7))
389 |
390 |
391 |
392 |
393 |
394 | ## [1.3.3](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.3.2...@loopback/example-express-composition@1.3.3) (2019-05-31)
395 |
396 | **Note:** Version bump only for package @loopback/example-express-composition
397 |
398 |
399 |
400 |
401 |
402 | ## [1.3.2](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.3.1...@loopback/example-express-composition@1.3.2) (2019-05-30)
403 |
404 | **Note:** Version bump only for package @loopback/example-express-composition
405 |
406 |
407 |
408 |
409 |
410 | ## [1.3.1](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.3.0...@loopback/example-express-composition@1.3.1) (2019-05-23)
411 |
412 | **Note:** Version bump only for package @loopback/example-express-composition
413 |
414 |
415 |
416 |
417 |
418 | # [1.3.0](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.2.11...@loopback/example-express-composition@1.3.0) (2019-05-14)
419 |
420 |
421 | ### Features
422 |
423 | * add lb3 application ([bf60011](https://github.com/strongloop/loopback-next/commit/bf60011))
424 |
425 |
426 |
427 |
428 |
429 | ## [1.2.11](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.2.10...@loopback/example-express-composition@1.2.11) (2019-05-10)
430 |
431 | **Note:** Version bump only for package @loopback/example-express-composition
432 |
433 |
434 |
435 |
436 |
437 | ## [1.2.10](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.2.9...@loopback/example-express-composition@1.2.10) (2019-05-09)
438 |
439 | **Note:** Version bump only for package @loopback/example-express-composition
440 |
441 |
442 |
443 |
444 |
445 | ## [1.2.9](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.2.8...@loopback/example-express-composition@1.2.9) (2019-05-06)
446 |
447 | **Note:** Version bump only for package @loopback/example-express-composition
448 |
449 |
450 |
451 |
452 |
453 | ## [1.2.8](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.2.7...@loopback/example-express-composition@1.2.8) (2019-04-26)
454 |
455 | **Note:** Version bump only for package @loopback/example-express-composition
456 |
457 |
458 |
459 |
460 |
461 | ## [1.2.7](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.2.6...@loopback/example-express-composition@1.2.7) (2019-04-20)
462 |
463 | **Note:** Version bump only for package @loopback/example-express-composition
464 |
465 |
466 |
467 |
468 |
469 | ## [1.2.6](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.2.5...@loopback/example-express-composition@1.2.6) (2019-04-11)
470 |
471 | **Note:** Version bump only for package @loopback/example-express-composition
472 |
473 |
474 |
475 |
476 |
477 | ## [1.2.5](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.2.4...@loopback/example-express-composition@1.2.5) (2019-04-09)
478 |
479 | **Note:** Version bump only for package @loopback/example-express-composition
480 |
481 |
482 |
483 |
484 |
485 | ## [1.2.4](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.2.3...@loopback/example-express-composition@1.2.4) (2019-04-05)
486 |
487 | **Note:** Version bump only for package @loopback/example-express-composition
488 |
489 |
490 |
491 |
492 |
493 | ## [1.2.3](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.2.2...@loopback/example-express-composition@1.2.3) (2019-03-22)
494 |
495 | **Note:** Version bump only for package @loopback/example-express-composition
496 |
497 |
498 |
499 |
500 |
501 | ## [1.2.2](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.2.1...@loopback/example-express-composition@1.2.2) (2019-03-22)
502 |
503 | **Note:** Version bump only for package @loopback/example-express-composition
504 |
505 |
506 |
507 |
508 |
509 | ## [1.2.1](https://github.com/strongloop/loopback-next/compare/@loopback/example-express-composition@1.2.0...@loopback/example-express-composition@1.2.1) (2019-03-12)
510 |
511 |
512 | ### Bug Fixes
513 |
514 | * **example-express-composition:** update npm files ([d0fb755](https://github.com/strongloop/loopback-next/commit/d0fb755))
515 | * **example-express-composition:** use rest options ([7e22757](https://github.com/strongloop/loopback-next/commit/7e22757))
516 |
517 |
518 |
519 |
520 |
521 | # 1.2.0 (2019-03-01)
522 |
523 |
524 | ### Bug Fixes
525 |
526 | * **example-express-composition:** fix name of example ([3a9daf6](https://github.com/strongloop/loopback-next/commit/3a9daf6))
527 | * **example-express-composition:** remove prepublishOnly and lbApp.start() ([c095a6c](https://github.com/strongloop/loopback-next/commit/c095a6c))
528 |
529 |
530 | ### Features
531 |
532 | * add express example ([dd2400e](https://github.com/strongloop/loopback-next/commit/dd2400e))
533 |
534 |
535 |
536 |
537 |
538 | # 1.1.0 (2019-03-01)
539 |
540 |
541 | ### Features
542 |
543 | * add express example ([dd2400e](https://github.com/strongloop/loopback-next/commit/dd2400e))
544 |
545 |
546 |
547 |
548 |
549 | # Change Log
550 |
--------------------------------------------------------------------------------