Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ sudo: false

language: node_js
node_js:
- '8'
- '12'

addons:
sonarcloud:
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2019 Rogerio F. da Cunha (petruki) and Contributors
Copyright (c) 2019 Roger Floriano (petruki) and Contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"main": "./src/index.js",
"types": "./src/index.d.ts",
"author": {
"name": "Rogerio Petruki",
"name": "Roger Floriano",
"email": "switcher.project@gmail.com"
},
"keywords": [
Expand Down Expand Up @@ -40,6 +40,6 @@
"url": "https://github.com/petruki/switcher-client-master"
},
"engines": {
"node": ">= 8.0.0"
"node": "^12.0.0"
}
}
127 changes: 73 additions & 54 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,93 +7,112 @@

![Switcher API: JavaScript Client: Cloud-based Feature Flag API](https://github.com/petruki/switcherapi-assets/blob/master/logo/switcherapi_js_client.png)

# Install
`npm install switcher-client`

# About
Module for working with Switcher-API.
Client JavaScript for working with Switcher-API.
https://github.com/petruki/switcher-api

Switcher Client is a friendly lib to interact with the Switcher API by:
- Simplifying validations throughout your remote Switcher configuration.
- Able to work offline using a snapshot claimed from your remote Switcher-API.
- Able to run in silent mode that will prevent your application to not be 100% dependent on the online API.
- Being flexible in order to remove the complexity of multi-staging (add as many environments as you want).
- Being friendly by making possible to manipulate switchers without changing your online switchers. (useful for automated tests).
- Being secure by using OAuth 2 flow. Requests are made using tokens that will validate your domain, component, environment and API key.
Tokens have an expiration time and are not stored. The Switcher Client is responsible to renew it using your settings.

# Example
1) Configure your client
- Able to work offline using a snapshot file downloaded from your remote Switcher-API Domain.
- Silent mode automatically enables a contingent sub-process in case of connectivity issues.
- Built-in mock implementation for automated testing.
- Easy to setup. Switcher Context is responsible to manage all the complexity between your application and API.

# Usage

## Install
`npm install switcher-client`

## Module initialization
The context properties stores all information regarding connectivity and strategy settings.

```js
const Switcher = require("switcher-client");

const apiKey = 'API Key';
const environment = 'default';
const domain = 'Your Domain Name';
const component = 'Android';
const url = 'http://localhost:3000/criteria';
const environment = 'default'; // Production = default
const domain = 'My Domain';
const component = 'MyApp';
const url = 'https://switcher-load-balance.herokuapp.com';
```
- **apiKey**: Obtained after creating your domain using the Switcher-API project.
- **environment**: You can run multiple environments. Production environment is 'default' which is created automatically after creating the domain.
- **domain**: This is your business name identification.
- **component**: This is the name of the application that will be using this API.
- **url**: Endpoint of your Swither-API.

2) Options - you can also activate features such as offline and silent mode
- **apiKey**: Switcher-API key generated after creating a domain..
- **environment**: Environment name. Production environment is named as 'default'.
- **domain**: Domain name.
- **component**: Application name.
- **url**: Swither-API endpoint.

## Options
You can also activate features such as offline and silent mode:

```js
const offline = true;
const snapshotLocation = './snapshot/default.json';
const snapshotLocation = './snapshot/';
const silentMode = true;
const retryAfter = '5m';

let switcher = new Switcher(url, apiKey, domain, component, environment, {
offline, snapshotLocation, silentMode, retryAfter
});
```

- **offline**: If activated, the client will only fetch the configuration inside your snapshot file. The default value is 'false'.
- **snapshotLocation**: Location of your snapshot. The default value is './snapshot/default.json'.
- **silentMode**: If activated, all connections errors will be ignored and the client will automatically fetch the configuration into your snapshot.
- **retryAfter** : Set the duration you want the client to try to reach the online API again. (see moment documentation for time signature). The default value is 5m.
- **snapshotLocation**: Location of snapshot files. The default value is './snapshot/'.
- **silentMode**: If activated, all connectivity issues will be ignored and the client will automatically fetch the configuration into your snapshot file.
- **retryAfter** : Time given to the module to re-establish connectivity with the API - e.g. 5s (s: seconds - m: minutes - h: hours).


## Executing
There are a few different ways to call the API using the JavaScript module.
Here are some examples:

1. **No parameters**
Invoking the API can be done by instantiating the switcher and calling *isItOn* passing its key as a parameter.

3) Create the client
```js
const switcher = new Switcher(url, apiKey, domain, component, environment)
//or - using silent mode
const switcher = new Switcher(url, apiKey, domain, component, environment, { silentMode: true })
//or - using offline mode
const switcher = new Switcher(url, apiKey, domain, component, environment, { offline: true })
const switcher = new Switcher(url, apiKey, domain, component, environment);
await switcher.isItOn('FEATURE01');
```

## Invoking switchers
**Scenario 1**
2. **Promise**
Using promise is another way to call the API if you want, like:

You want to setup the input of your switch before using it and call 'isItOn' some elsewhere.
```js
switcher.prepare('MY_KEY', [Switcher.StrategiesType.VALUE, 'USER_1')
switcher.isItOn()
switcher.isItOnPromise('KEY')
.then(result => console.log('Result:', result))
.catch(error => console.log(error));
```

**Scenario 2**
3. **Strategy validation - preparing input**
Loading information into the switcher can be made by using *prepare*, in case you want to include input from a different place of your code. Otherwise, it is also possible to include everything in the same call.

You want to call isItOn without preparing, as simple as this:
```js
switcher.isItOn('KEY')
switcher.prepare('FEATURE01', [Switcher.StrategiesType.VALUE, 'USER_1');
switcher.isItOn();
```

**Scenario 3**
4. **Strategy validation - all-in-one execution**
All-in-one method is fast and include everything you need to execute a complex call to the API.

Using promise is another way to call the API if you want:
```js
switcher.isItOnPromise('KEY')
.then(result => console.log('Promise result:', result))
.catch(error => console.log(error));
await switcher.isItOn('FEATURE01',
[Switcher.StrategiesType.VALUE, 'User 1',
Switcher.StrategiesType.NETWORK, '192.168.0.1']
);
```

## Bypassing switchers
You can also bypass your switcher configuration by invoking 'assume'. This is perfect for your test code where you want to test both scenarios when the switcher is true and false.
## Built-in mock feature
You can also bypass your switcher configuration by invoking 'Switcher.assume'. This is perfect for your test code where you want to test both scenarios when the switcher is true and false.

```js
switcher.assume('KEY').true()
switcher.isItOn('KEY') // it is going to be true
Switcher.assume('FEATURE01').true();
switcher.isItOn('FEATURE01'); // true

Switcher.forget('FEATURE01');
switcher.isItOn('FEATURE01'); // Now, it's going to return the result retrieved from the API or the Snaopshot file
```

Invoke forget to remove any switch assumption, like this:
## Snapshot version check
For convenience, an implementation of a domain version checker is available if you have external processes that manage snapshot files.

```js
switcher.forget('KEY')
switcher.checkSnapshot();
```
26 changes: 26 additions & 0 deletions snapshot/dev.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"data": {
"domain": {
"name": "currency-api",
"description": "Currency API",
"version": 1588557288037,
"activated": true,
"group": [
{
"name": "Rollout 2030",
"description": "Changes that will be applied during the rollout",
"activated": true,
"config": [
{
"key": "FF2FOR2030",
"description": "Feature Flag",
"activated": false,
"strategies": [],
"components": []
}
]
}
]
}
}
}
1 change: 1 addition & 0 deletions sonar-project.properties
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ sonar.javascript.lcov.reportPaths=coverage/lcov.info
sonar.sources=src
sonar.tests=test
sonar.language=js
sonar.exclusions=src/**/*.d.ts

sonar.dynamicAnalysis=reuseReports
# Encoding of the source code. Default is default system encoding
Expand Down
81 changes: 64 additions & 17 deletions src/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import Key from "./lib/key";

declare class Switcher {

constructor(url: string, apiKey: string, domain: string, component: string, environment: string, options?: SwitcherOptions);
constructor(
url: string,
apiKey: string,
domain: string,
component: string,
environment: string,
options?: SwitcherOptions);

url: string;
token: string;
Expand All @@ -10,14 +18,66 @@ declare class Switcher {
key: string;
input: string[];
exp: number;
bypassedKeys: Key;
snapshot?: string;

/**
* Validate the input provided to access the API
*/
validate(): void;

/**
* Pre-set input values before calling the API
*
* @param key
* @param input
*/
prepare(key: string, input?: string[]): void;

/**
* Execute async criteria
*
* @param key
* @param input
*/
isItOn(key?: string, input?: string[]): boolean;

/**
* Execute async criteria
*
* @param key
* @param input
*/
isItOnPromise(key?: string, input?: string[]): Promise<boolean>;
assume(key: string): Key;
forget(key: string): void;

/**
* Read snapshot file locally and store in a parsed JSON object
*/
loadSnapshot(): void;

/**
* Verifies if the current snapshot file is updated.
* Return true if an update has been made.
*/
checkSnapshot(): boolean;

/**
* Remove snapshot from real-time update
*/
unloadSnapshot(): void;

/**
* Force a switcher value to return a given value by calling one of both methods - true() false()
*
* @param key
*/
static assume(key: string): Key;

/**
* Remove forced value from a switcher
*
* @param key
*/
static forget(key: string): void;
}

declare interface SwitcherOptions {
Expand All @@ -27,17 +87,4 @@ declare interface SwitcherOptions {
retryAfter: string;
}

declare class Key {

constructor(key: string);

key: string;
valaue: boolean;

true(): void;
false(): void;
getKey(): string;
getValue(): boolean;
}

export = Switcher;
Loading