Skip to main content

Envizage SDK

About the SDK

The Envizage SDK is a set of Javascript methods that can be used to facilitate interaction with the Envizage API. The SDK can be used in both client-side and server-side (Node.js) Javascript and Typescript code. Type declarations are included.

Http client

The SDK requires an HTTP client implementation. The user can implement their own client or use a custom client implementation included in the SDK.

The @envizage/model NPM package is a peer dependency for the SDK. It includes interfaces and mappings for entities used in the API. Make sure that a version equal to or newer than the minimum specified in the SDK project is installed in your project. You can install the @envizage/model package using the following command:

npm install ---save @envizage/model

or using Yarn:

yarn add @envizage/model

Install Envizage's SDK package using NPM:

npm install ---save @envizage/services

or using Yarn:

yarn add @envizage/services

Usage

HTTP client

An HTTP client implementation is required as a dependency for all other services included in the SDK. The HTTP client that will be injected has to implement the IHttpClient interface:

export interface IHttpClient {
get: <T>(url: string, params?: Map<string, string>, headerMap?: string[][]) => Promise<T>,

post: <T, U>(url: string, body: T, params?: Map<string, string>, headerMap?: string[][]) => Promise<U>,

put: <T, U>(url: string, body: T, params?: Map<string, string>, headerMap?: string[][]) => Promise<U>,

remove: <T>(url: string, params?: Map<string, string>, headerMap?: string[][]) => Promise<T>
}

A user of the SDK can either implement that interface or import a ready fetch-based implementation that comes with the SDK:

import { HttpClient } from "@envizage/services";

A wrapper is also available to intercept requests before/after the HTTP client interacts with the API that can be used to add headers to HTTP requests. The following example intercepts HTTP requests and adds the basic headers required in every request to the API:

import { withInterceptor, HttpClient } from '@envizage/services';

const simpleClient = withInterceptor((url, params, headerMap, body) => {
const clonedHeaders = headerMap ? (JSON.parse(JSON.stringify(headerMap)) as [string, string][]) : [];
clonedHeaders.push(['Accept', 'application/json']);
clonedHeaders.push(['Content-type', 'application/json']);

return {
url, params, headerMap: clonedHeaders, body
}
})(HttpClient);

User authentication

Envizage uses the OpenIDConnect protocol to authenticate users. Users can be authenticated using the Authorization Code Flow and the Resource Owner Password Credentials (ROPC) Flow. Both flows together with the Client Credentials Flow (which can be used to authenticate a client application) are documented in the API Reference. We assume that a valid user access token has been obtained using any of the supported OpenIDConnect flows. Examples of how to obtain a token can be found for a front-end application or a backend application.

Service initialization

Each service is a class that needs to be instantiated to access the API. A new object can simply be created and used in any Javascript app. Note that all services require authorization headers added to the HTTP requests so the HTTP client has to accomodate that requirement.

import { HttpClient, LivingExpenseService } from '@envizage/services';

const apiUrl = 'https://api.envizage.me';

//We assume that a user token has been obtained and stored in the session storage of the browser.
const token = sessionStorage.getItem('access_token');

const unauthorizedClient = withInterceptor((url, params, headerMap, body) => {
const clonedHeaders = headerMap ? (JSON.parse(JSON.stringify(headerMap)) as [string, string][]) : [];
clonedHeaders.push(['Accept', 'application/json']);
clonedHeaders.push(['Content-type', 'application/json']);

return {
url, params, headerMap: clonedHeaders, body
}
})(HttpClient);

const authorizedClient = withInterceptor((url, params, headerMap, body) => {
const clonedHeaders = headerMap ? (JSON.parse(JSON.stringify(headerMap)) as [string, string][]) : [];
clonedHeaders.push(['Authorization', 'Bearer ' + token]);
return {
url, params, headerMap: clonedHeaders, body
}
})(unauthorizedClient);

const livingExpenseService = new LivingExpenseService(authorizedClient, apiUrl);

const livingExpenseResponse = await livingExpenseService.query({
page: 0,
size: 2000,
sort: PageableSort.ASC
});

Setup a simple scenario

Following the previous steps, the user is able to create and setup a new scenario by utilizing the services that Envizage SDK provides.

First things first, the user should provide the HTTP client and the authenticated HTTP client in app's module providers array. For authentication purposes, use the token that has been fetched and stored in local storage from previous steps. Create a new component named scenario-builder and use Envizage SDK's services in order to create and setup a new scenario like the following example:

providers: [...{ 
provide: HTTP_CLIENT,
useFactory: () => withInterceptor((url, params, headerMap, body) => {
if (!headerMap) {
headerMap = [];
}
if (headerMap.filter(h => h[0].toLowerCase() === 'content-type').length === 0) {
headerMap.push(['content-type', 'application/json'])
}
return { url, params, headerMap, body };
})(HttpClient)},
{
provide: AUTHENTICATED_CLIENT,
deps: [OAuthService],
useFactory: (oAuthService: OAuthService) => withInterceptor((url, params, headerMap, body ) => {
if (!headerMap) {
headerMap = [];
}
headerMap.push(['accept', 'application/json, text/plain, */*']);
if (url.indexOf('/scenarios') >= 0) {
headerMap.push(['X-Requested-Version', '5.0'])
}
const authToken = oAuthService.getAccessToken();
headerMap.push(['Authorization', 'Bearer ' + authToken]);
return {
url,
params,
headerMap,
body
};
})(HttpClient)}
...},
{
provide: ScenarioService,
deps: [AUTHENTICATED_CLIENT, BASE_URL],
useFactory: (client, baseUrl) => new ScenarioService(client, baseUrl)
},
{
provide: PortfolioAssetService,
deps: [AUTHENTICATED_CLIENT, BASE_URL],
useFactory: (client, baseUrl) => new PortfolioAssetService(client, baseUrl)
},
{
provide: EarnedIncomeForPersonService,
deps: [AUTHENTICATED_CLIENT, BASE_URL],
useFactory: (client, baseUrl) => new EarnedIncomeForPersonService(client, baseUrl)
},
{
provide: LivingExpenseForPersonService,
deps: [AUTHENTICATED_CLIENT, BASE_URL],
useFactory: (client, baseUrl) => new LivingExpenseForPersonService(client, baseUrl)
},
{
provide: PensionAnnuityIncomeForPersonService,
deps: [AUTHENTICATED_CLIENT, BASE_URL],
useFactory: (client, baseUrl) => new PensionAnnuityIncomeForPersonService(client, baseUrl)
},
{
provide: PortfolioAssetForPersonService,
deps: [AUTHENTICATED_CLIENT, BASE_URL],
useFactory: (client, baseUrl) => new PortfolioAssetForPersonService(client, baseUrl)
},
{
provide: PortfolioContributionExpenseService,
deps: [AUTHENTICATED_CLIENT, BASE_URL],
useFactory: (client, baseUrl) => new PortfolioContributionExpenseService(client, baseUrl)
},
{
provide: PortfolioFinancialAssetForPersonService,
deps: [AUTHENTICATED_CLIENT, BASE_URL],
useFactory: (client, baseUrl) => new PortfolioFinancialAssetForPersonService(client, baseUrl)
},
{
provide: PrimaryPersonService,
deps: [AUTHENTICATED_CLIENT, BASE_URL],
useFactory: (client, baseUrl) => new PrimaryPersonService(client, baseUrl)
},
{
provide: ResultsService,
deps: [AUTHENTICATED_CLIENT, BASE_URL],
useFactory: (client, baseUrl) => new ResultsService(client, baseUrl)
},
{
provide: ScenarioService,
deps: [AUTHENTICATED_CLIENT, BASE_URL],
useFactory: (client, baseUrl) => new ScenarioService(client, baseUrl)
},
{
provide: TypedGoalForPersonService,
deps: [AUTHENTICATED_CLIENT, BASE_URL],
useFactory: (client, baseUrl) => new TypedGoalForPersonService(client, baseUrl)
},
{
provide: TypedGoalService,
deps: [AUTHENTICATED_CLIENT, BASE_URL],
useFactory: (client, baseUrl) => new TypedGoalService(client, baseUrl)
},
...}]

First we define the models that are needed to passed as parameters in the services. After that we use the SDK's services in order to create and setup a simple scenario. Finally, we utilize the replace(), execute() and get() methods to run a simulation and get the results. In this example we use the RxJS library. RxJS operators are utilized in order create an observable (defer), call the services sequentially (switchMap) or in parallel(forkJoin), implement businness logic between tha calls (tap) etc. As you may noticed, createAndSetupScenario() method is called upon component initialization, however the user is able to call and use Envizage SDK whenever and wherever is needed in the app, for instance when an event or action is triggered.