Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(parameters): AppConfigProvider #1200

Merged
111 changes: 111 additions & 0 deletions packages/parameters/src/AppConfigProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { BaseProvider, DEFAULT_PROVIDERS } from 'BaseProvider';
import {
AppConfigDataClient,
StartConfigurationSessionCommand,
GetLatestConfigurationCommand,
} from '@aws-sdk/client-appconfigdata';
import type {
StartConfigurationSessionCommandInput,
GetLatestConfigurationCommandInput,
} from '@aws-sdk/client-appconfigdata';
import type { AppConfigGetOptionsInterface } from './types/AppConfigProvider';

class AppConfigProvider extends BaseProvider {
public client: AppConfigDataClient;
private application?: string;
private environment?: string;
private token: string | undefined;

/**
* It initializes the AppConfigProvider class with an optional set of options like region: 'us-west-1'.
* *
* @param {AppConfigDataClientConfig} options
*/
public constructor(options: AppConfigGetOptionsInterface = {}) {
super();
this.client = new AppConfigDataClient(options.config || {});
this.environment = options.environment;
this.application = options.application || 'service_undefined'; // TODO: get value from ENV VARIABLES
}

/**
* Retrieve a parameter value from AWS App config.
*
* @param {string} name - Name of the configuration
* @param {StartConfigurationSessionCommandInput} [sdkOptions] - SDK options to propagate to `StartConfigurationSession` API call
* @returns {Promise<string | undefined>}
*/
protected async _get(
name: string,
options?: AppConfigGetOptionsInterface
): Promise<string | undefined> {
/**
* The new AppConfig APIs require two API calls to return the configuration
* First we start the session and after that we retrieve the configuration
* We need to store the token to use in the next execution
**/
if (!this.token) {
const sessionOptions: StartConfigurationSessionCommandInput = {
ConfigurationProfileIdentifier: name,
EnvironmentIdentifier: this.environment,
ApplicationIdentifier: this.application,
};
if (options && options.hasOwnProperty('sdkOptions')) {
Object.assign(sessionOptions, options.sdkOptions);
dreamorosi marked this conversation as resolved.
Show resolved Hide resolved
}

const sessionCommand = new StartConfigurationSessionCommand(
sessionOptions
);

const session = await this.client.send(sessionCommand);
this.token = session.InitialConfigurationToken;
}

const getConfigurationCommand = new GetLatestConfigurationCommand({
ConfigurationToken: this.token,
});
const response = await this.client.send(getConfigurationCommand);

// Should we cache and flush the token after 24 hours?
// NextPollConfigurationToken expires in 24 hours after the last request and causes `BadRequestException`
dreamorosi marked this conversation as resolved.
Show resolved Hide resolved
this.token = response.NextPollConfigurationToken;

const configuration = response.Configuration;

// should we convert Uint8Array to string?
dreamorosi marked this conversation as resolved.
Show resolved Hide resolved
const utf8decoder = new TextDecoder();
const value = configuration ? utf8decoder.decode(configuration) : undefined;

return value;
}

/**
* Retrieving multiple parameter values is not supported with AWS App Config Provider.
*
* @throws Not Implemented Error.
*/
protected async _getMultiple(
path: string,
dreamorosi marked this conversation as resolved.
Show resolved Hide resolved
sdkOptions?: Partial<GetLatestConfigurationCommandInput>
dreamorosi marked this conversation as resolved.
Show resolved Hide resolved
): Promise<Record<string, string | undefined>> {
return this._notImplementedError();
}

private _notImplementedError(): never {
throw new Error('Not Implemented');
}
}

const getAppConfig = (
name: string,
options?: AppConfigGetOptionsInterface
): Promise<undefined | string | Record<string, unknown>> => {
if (!DEFAULT_PROVIDERS.hasOwnProperty('appconfig')) {
DEFAULT_PROVIDERS.appconfig = new AppConfigProvider(options);
}

return DEFAULT_PROVIDERS.appconfig.get(name, options);
};

export { AppConfigProvider, getAppConfig };
18 changes: 18 additions & 0 deletions packages/parameters/src/types/AppConfigProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { StartConfigurationSessionCommandInput, AppConfigDataClientConfig } from '@aws-sdk/client-appconfigdata';
import type { GetOptionsInterface } from 'types/BaseProvider';

/**
* Options for the AppConfigProvider get method.
*
* @interface AppConfigGetOptionsInterface
* @extends {GetOptionsInterface}
* @property {Partial<StartConfigurationSessionCommandInput>} sdkOptions - Options for the AWS SDK.
*/
interface AppConfigGetOptionsInterface extends Omit<GetOptionsInterface, 'sdkOptions'> {
application?: string
config?: AppConfigDataClientConfig
environment?: string
sdkOptions?: Partial<StartConfigurationSessionCommandInput>
}

export { AppConfigGetOptionsInterface };