Skip to content

Commit 20257a1

Browse files
refactor(sandbox): refactor feature toggle example sandbox (#2236)
* refactor(feature-toggle): refactor code refactor code MIGRATION CHANGE: migration-20230612141912- refactor code migration-20210913104858- refactor code 0 * refactor(feature-toggle): lint issues lint issues 0 lint issues
1 parent f5fc1e1 commit 20257a1

File tree

7 files changed

+186
-31
lines changed

7 files changed

+186
-31
lines changed

sandbox/feature-toggle-example/README.md

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,45 @@
33
This application is generated using [LoopBack 4 CLI](https://loopback.io/doc/en/lb4/Command-line-interface.html) with the
44
[initial project layout](https://loopback.io/doc/en/lb4/Loopback-application-layout.html).
55

6-
## Install dependencies
6+
## STEP 1: Install dependencies
77

8-
By default, dependencies were installed when this application was generated.
9-
Whenever dependencies in `package.json` are changed, run the following command:
8+
To install the project dependencies, run the following command:
109

1110
```sh
1211
npm install
1312
```
13+
## STEP 2: Set up Environment Variables
14+
1. Copy the .env.example file to .env:
1415

15-
To only install resolved dependencies in `package-lock.json`:
16+
```sh
17+
cp .env.example .env
18+
```
19+
2. Open the .env file and configure the necessary environment variables (e.g., database connection settings, JWT secret keys).
1620

21+
## STEP 3: Database Migration
22+
Run the following command to migrate the database:
1723
```sh
18-
npm ci
24+
npm run db:migrate
1925
```
2026

21-
## Run the application
27+
## STEP 4: Set up JWT Asymmetric Authentication
28+
This project uses JWT tokens for authentication. Ensure you have the following:
29+
* A private key (JWT_PRIVATE_KEY) for signing the JWT tokens.
30+
* A public key (JWT_PUBLIC_KEY) for verifying the JWT tokens.
31+
32+
Add these keys to the .env file or ensure they are properly configured in your authentication service.
2233

34+
## STEP 5: Start the application
35+
Once everything is set up, you can start the Node.js application with the following command:
2336
```sh
2437
npm start
2538
```
39+
This will start the server, and you can begin testing the API.
2640

27-
You can also run `node .` to skip the build step.
41+
## STEP 6: Testing the API
42+
After starting the application, you can test the API using Swagger UI. Open your browser and visit:
2843

29-
Open http://127.0.0.1:3000 in your browser.
44+
http://127.0.0.1:3000 Replace the URL according to your configuration
3045

3146
## Rebuild the project
3247

@@ -55,8 +70,6 @@ npm run lint:fix
5570
```
5671

5772
## Other useful commands
58-
59-
- `npm run migrate`: Migrate database schemas for models
6073
- `npm run openapi-spec`: Generate OpenAPI spec into a file
6174
- `npm run docker:build`: Build a Docker image for this application
6275
- `npm run docker:run`: Run this application inside a Docker container
@@ -67,6 +80,11 @@ npm run lint:fix
6780
npm test
6881
```
6982

83+
## Troubleshooting
84+
* Ensure that your database is correctly configured and running.
85+
* Make sure that the JWT private and public keys are properly set up in the .env file.
86+
* If you encounter issues with Swagger UI not loading, verify that the server has successfully started and that the correct port is specified.
87+
7088
## What's next
7189

7290
Please check out [LoopBack 4 documentation](https://loopback.io/doc/en/lb4/) to
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
'use strict';
2+
3+
var dbm;
4+
var type;
5+
var seed;
6+
var fs = require('fs');
7+
var path = require('path');
8+
var Promise;
9+
10+
/**
11+
* We receive the dbmigrate dependency from dbmigrate initially.
12+
* This enables us to not have to rely on NODE_PATH.
13+
*/
14+
exports.setup = function (options, seedLink) {
15+
dbm = options.dbmigrate;
16+
type = dbm.dataType;
17+
seed = seedLink;
18+
Promise = options.Promise;
19+
};
20+
21+
exports.up = function (db) {
22+
var filePath = path.join(
23+
__dirname,
24+
'sqls',
25+
'20230612141912-update-tables-up.sql',
26+
);
27+
return new Promise(function (resolve, reject) {
28+
fs.readFile(filePath, {encoding: 'utf-8'}, function (err, data) {
29+
if (err) return reject(err);
30+
console.log('received data: ' + data);
31+
32+
resolve(data);
33+
});
34+
}).then(function (data) {
35+
return db.runSql(data);
36+
});
37+
};
38+
39+
exports.down = function (db) {
40+
var filePath = path.join(
41+
__dirname,
42+
'sqls',
43+
'20230612141912-update-tables-down.sql',
44+
);
45+
return new Promise(function (resolve, reject) {
46+
fs.readFile(filePath, {encoding: 'utf-8'}, function (err, data) {
47+
if (err) return reject(err);
48+
console.log('received data: ' + data);
49+
50+
resolve(data);
51+
});
52+
}).then(function (data) {
53+
return db.runSql(data);
54+
});
55+
};
56+
57+
exports._meta = {
58+
version: 1,
59+
};

sandbox/feature-toggle-example/migrations/sqls/20210913104858-initial-up.sql

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,30 @@ GRANT ALL ON SCHEMA main TO public;
55

66
CREATE TABLE main.features (
77
id uuid DEFAULT md5(random()::text || clock_timestamp()::text)::uuid NOT NULL,
8-
name varchar(50) NOT NULL ,
9-
key varchar(50) NOT NULL ,
10-
description varchar(50) ,
11-
default_value bool DEFAULT true NOT NULL ,
8+
name text NOT NULL ,
9+
key text NOT NULL ,
10+
description text ,
11+
default_value text ,
12+
type text ,
1213
CONSTRAINT pk_features_id PRIMARY KEY ( id )
1314
);
1415

1516
CREATE TABLE main.strategies (
1617
id uuid DEFAULT md5(random()::text || clock_timestamp()::text)::uuid NOT NULL,
17-
name varchar(50) NOT NULL ,
18-
key varchar(50) NOT NULL ,
19-
priority integer ,
18+
name text NOT NULL ,
19+
key text NOT NULL ,
20+
priority integer ,
2021
CONSTRAINT pk_strategies_id PRIMARY KEY ( id )
2122
);
2223

23-
CREATE TABLE main.feature_toggles (
24-
id uuid DEFAULT md5(random()::text || clock_timestamp()::text)::uuid NOT NULL,
25-
feature_key varchar(50) NOT NULL ,
24+
CREATE TABLE main.feature_values (
25+
id uuid DEFAULT md5(random()::text || clock_timestamp()::text)::uuid NOT NULL,
26+
feature_key varchar(50) NOT NULL ,
2627
strategy_key varchar(50) NOT NULL ,
27-
strategy_entity_id uuid ,
28-
status bool DEFAULT true NOT NULL ,
29-
CONSTRAINT pk_feature_toggles_id PRIMARY KEY ( id )
28+
strategy_entity_id uuid NULL,
29+
status bool DEFAULT true NOT NULL ,
30+
value text,
31+
CONSTRAINT pk_feature_values_id PRIMARY KEY ( id )
3032
);
3133

3234
INSERT INTO main.strategies(name, key, priority)
@@ -36,7 +38,4 @@ INSERT INTO main.strategies(name, key, priority)
3638
VALUES ('Tenant', 'Tenant', '2');
3739

3840
INSERT INTO main.strategies(name, key, priority)
39-
VALUES ('User', 'User', '3');
40-
41-
INSERT INTO main.features(name, key, default_value)
42-
VALUES ('Calendar', 'Calendar', 'true');
41+
VALUES ('User', 'User', '3');
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
ALTER TABLE main.features
2+
drop column metadata,
3+
drop column created_by,
4+
drop column modified_by ,
5+
drop column created_on ,
6+
drop column modified_on
7+
drop column deleted ,
8+
drop column deleted_on ,
9+
drop column deleted_by;
10+
11+
12+
ALTER TABLE main.strategies
13+
drop column created_by,
14+
drop column modified_by ,
15+
drop column created_on ,
16+
drop column modified_on
17+
drop column deleted ,
18+
drop column deleted_on ,
19+
drop column deleted_by;
20+
21+
ALTER TABLE main.feature_values
22+
drop column created_by,
23+
drop column modified_by ,
24+
drop column created_on ,
25+
drop column modified_on
26+
drop column deleted ,
27+
drop column deleted_on ,
28+
drop column deleted_by;
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/* Replace with your SQL commands */
2+
3+
ALTER TABLE main.features
4+
ADD metadata TEXT,
5+
ADD created_by varchar(100),
6+
ADD modified_by varchar(100),
7+
ADD created_on timestamptz DEFAULT CURRENT_TIMESTAMP NOT NULL ,
8+
ADD modified_on timestamptz DEFAULT CURRENT_TIMESTAMP NOT NULL ,
9+
ADD deleted bool DEFAULT false NOT NULL ,
10+
ADD deleted_on timestamptz ,
11+
ADD deleted_by uuid ;
12+
13+
ALTER TABLE main.strategies
14+
ADD created_by varchar(100),
15+
ADD modified_by varchar(100),
16+
ADD created_on timestamptz DEFAULT CURRENT_TIMESTAMP NOT NULL ,
17+
ADD modified_on timestamptz DEFAULT CURRENT_TIMESTAMP NOT NULL ,
18+
ADD deleted bool DEFAULT false NOT NULL ,
19+
ADD deleted_on timestamptz ,
20+
ADD deleted_by uuid ;
21+
22+
ALTER TABLE main.feature_values
23+
ADD created_by varchar(100),
24+
ADD modified_by varchar(100),
25+
ADD created_on timestamptz DEFAULT CURRENT_TIMESTAMP NOT NULL ,
26+
ADD modified_on timestamptz DEFAULT CURRENT_TIMESTAMP NOT NULL ,
27+
ADD deleted bool DEFAULT false NOT NULL ,
28+
ADD deleted_on timestamptz ,
29+
ADD deleted_by uuid ;

sandbox/feature-toggle-example/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@
3535
"start": "node -r source-map-support/register .",
3636
"clean": "lb-clean dist *.tsbuildinfo .eslintcache",
3737
"rebuild": "npm run clean && npm run build",
38-
"db:migrate": "./node_modules/db-migrate/bin/db-migrate up --config './migrations/database.json'",
39-
"db:migrate:down": "./node_modules/db-migrate/bin/db-migrate down --config './migrations/database.json'",
40-
"db:migrate:reset": "./node_modules/db-migrate/bin/db-migrate reset --config './migrations/database.json'"
38+
"db:migrate": "../../node_modules/db-migrate/bin/db-migrate up --config './migrations/database.json'",
39+
"db:migrate:down": "../../node_modules/db-migrate/bin/db-migrate down --config './migrations/database.json'",
40+
"db:migrate:reset": "../../node_modules/db-migrate/bin/db-migrate reset --config './migrations/database.json'"
4141
},
4242
"repository": {
4343
"type": "git",

sandbox/feature-toggle-example/src/application.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@ import {
2222
} from 'loopback4-authorization';
2323
import path from 'path';
2424
import {MySequence} from './sequence';
25+
import {
26+
BearerVerifierBindings,
27+
BearerVerifierComponent,
28+
BearerVerifierConfig,
29+
BearerVerifierType,
30+
ServiceSequence,
31+
} from '@sourceloop/core';
32+
import {AuthenticationComponent} from 'loopback4-authentication';
2533
dotenv.config();
2634

2735
export {ApplicationConfig};
@@ -46,10 +54,24 @@ export class FeatureToggleExampleApplication extends BootMixin(
4654

4755
this.bind(FeatureToggleBindings.Config).to({
4856
bindControllers: true,
49-
useCustomSequence: false,
57+
useCustomSequence: true,
5058
});
5159
this.component(FeatureToggleServiceComponent);
5260

61+
this.sequence(ServiceSequence);
62+
63+
// Mount authentication component for default sequence
64+
this.component(AuthenticationComponent);
65+
// Mount bearer verifier component
66+
this.bind(BearerVerifierBindings.Config).to({
67+
authServiceUrl: '',
68+
useSymmetricEncryption: true,
69+
type: BearerVerifierType.service,
70+
} as BearerVerifierConfig);
71+
this.component(BearerVerifierComponent);
72+
73+
// Mount authorization component for default sequence
74+
5375
this.bind(AuthorizationBindings.CONFIG).to({
5476
allowAlwaysPaths: ['/explorer'],
5577
});

0 commit comments

Comments
 (0)