Skip to content

Commit

Permalink
docs(parameters): add typedoc api docs (#1283)
Browse files Browse the repository at this point in the history
* docs(parameters): add typedoc api docs (#1283)

* chore(docs): fix minor issues in api docs examples

* chore(docs): add note for maxAge start caching after the first api call

---------

Co-authored-by: Alexander Melnyk <[email protected]>
  • Loading branch information
dreamorosi and Alexander Melnyk authored Mar 16, 2023
1 parent 97339d9 commit 8a47e76
Show file tree
Hide file tree
Showing 24 changed files with 1,997 additions and 68 deletions.
1 change: 1 addition & 0 deletions packages/parameters/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ module.exports = {
'coveragePathIgnorePatterns': [
'/node_modules/',
'/types/',
'/src/docs.ts', // this file is only used for documentation
],
'coverageThreshold': {
'global': {
Expand Down
2 changes: 1 addition & 1 deletion packages/parameters/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"license": "MIT-0",
"main": "./lib/index.js",
"types": "./lib/index.d.ts",
"typedocMain": "src/file_that_does_not_exist_so_its_ignored_from_api_docs.ts",
"typedocMain": "src/docs.ts",
"files": [
"lib"
],
Expand Down
71 changes: 59 additions & 12 deletions packages/parameters/src/BaseProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,33 +9,54 @@ import type { BaseProviderInterface, GetMultipleOptionsInterface, GetOptionsInte
// These providers are dinamycally intialized on first use of the helper functions
const DEFAULT_PROVIDERS: Record<string, BaseProvider> = {};

/**
* Base class for all providers.
*
* As an abstract class, it should not be used directly, but rather extended by other providers.
*
* It implements the common logic for all providers, such as caching, transformation, etc.
* Each provider that extends this class must implement the `_get` and `_getMultiple` abstract methods.
*
* These methods are responsible for retrieving the values from the underlying parameter store. They are
* called by the `get` and `getMultiple` methods, which are responsible for caching and transformation.
*
* If there are multiple calls to the same parameter but in a different transform, they will be stored multiple times.
* This allows us to optimize by transforming the data only once per retrieval, thus there is no need to transform cached values multiple times.
*
* However, this means that we need to make multiple calls to the underlying parameter store if we need to return it in different transforms.
*
* Since the number of supported transform is small and the probability that a given parameter will always be used in a specific transform,
* this should be an acceptable tradeoff.
*/
abstract class BaseProvider implements BaseProviderInterface {
protected store: Map<string, ExpirableValue>;

public constructor() {
this.store = new Map();
}

/**
* Add a value to the cache.
*
* @param {string} key - Key of the cached value
* @param {string | Uint8Array | Record<string, unknown>} value - Value to be cached
* @param {number} maxAge - Maximum age in seconds for the value to be cached
*/
public addToCache(key: string, value: string | Uint8Array | Record<string, unknown>, maxAge: number): void {
if (maxAge <= 0) return;

this.store.set(key, new ExpirableValue(value, maxAge));
}

/**
* Clear the cache.
*/
public clearCache(): void {
this.store.clear();
}

/**
* Retrieve a parameter value or return the cached value
*
* If there are multiple calls to the same parameter but in a different transform, they will be stored multiple times.
* This allows us to optimize by transforming the data only once per retrieval, thus there is no need to transform cached values multiple times.
*
* However, this means that we need to make multiple calls to the underlying parameter store if we need to return it in different transforms.
*
* Since the number of supported transform is small and the probability that a given parameter will always be used in a specific transform,
* this should be an acceptable tradeoff.
* Retrieve a parameter value or return the cached value.
*
* @param {string} name - Parameter name
* @param {GetOptionsInterface} options - Options to configure maximum age, trasformation, AWS SDK options, or force fetch
Expand Down Expand Up @@ -68,6 +89,13 @@ abstract class BaseProvider implements BaseProviderInterface {
return value;
}

/**
* Retrieve multiple parameter values or return the cached values.
*
* @param {string} path - Parameters path
* @param {GetMultipleOptionsInterface} options - Options to configure maximum age, trasformation, AWS SDK options, or force fetch
* @returns
*/
public async getMultiple(path: string, options?: GetMultipleOptionsInterface): Promise<undefined | Record<string, unknown>> {
const configs = new GetMultipleOptions(options || {});
const key = [ path, configs.transform ].toString();
Expand Down Expand Up @@ -97,7 +125,7 @@ abstract class BaseProvider implements BaseProviderInterface {
}

/**
* Check whether a key has expired in the cache or not
* Check whether a key has expired in the cache or not.
*
* It returns true if the key is expired or not present in the cache.
*
Expand All @@ -111,15 +139,15 @@ abstract class BaseProvider implements BaseProviderInterface {
}

/**
* Retrieve parameter value from the underlying parameter store
* Retrieve parameter value from the underlying parameter store.
*
* @param {string} name - Parameter name
* @param {unknown} options - Options to pass to the underlying implemented method
*/
protected abstract _get(name: string, options?: unknown): Promise<string | Uint8Array | undefined>;

/**
* Retrieve multiple parameter values from the underlying parameter store
* Retrieve multiple parameter values from the underlying parameter store.
*
* @param {string} path - Parameter name
* @param {unknown} options - Options to pass to the underlying implementated method
Expand All @@ -128,6 +156,16 @@ abstract class BaseProvider implements BaseProviderInterface {

}

/**
* Utility function to transform a value.
*
* It supports JSON and binary transformations, as well as an 'auto' mode that will try to transform the value based on the key.
*
* @param {string | Uint8Array | undefined} value - Value to be transformed
* @param {TransformOptions} transform - Transform to be applied, can be 'json', 'binary', or 'auto'
* @param {boolean} throwOnTransformError - Whether to throw an error if the transformation fails, when transforming multiple values this can be set to false
* @param {string} key - Key of the value to be transformed, used to determine the transformation method when using 'auto'
*/
const transformValue = (value: string | Uint8Array | undefined, transform: TransformOptions, throwOnTransformError: boolean, key: string): string | Record<string, unknown> | undefined => {
try {
const normalizedTransform = transform.toLowerCase();
Expand Down Expand Up @@ -159,6 +197,15 @@ const transformValue = (value: string | Uint8Array | undefined, transform: Trans
}
};

/**
* Utility function to transform multiple values.
*
* It iterates over the values and applies the transformation to each one by calling the `transformValue` function.
*
* @param {Record<string, string | undefined>} value - Values to be transformed
* @param {TransformOptions} transform - Transform to be applied, can be 'json', 'binary', or 'auto'
* @param {boolean} throwOnTransformError - Whether to throw an error if the transformation fails, when transforming multiple values this can be set to false
*/
const transformValues = (value: Record<string, string | undefined>, transform: TransformOptions, throwOnTransformError: boolean): Record<string, string | Record<string, unknown> | undefined> => {
const transformedValues: Record<string, string | Record<string, unknown> | undefined> = {};
for (const [ entryKey, entryValue ] of Object.entries(value)) {
Expand Down
3 changes: 3 additions & 0 deletions packages/parameters/src/Exceptions.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
class GetParameterError extends Error {}

/**
* Error thrown when a transform fails.
*/
class TransformParameterError extends Error {
public constructor(transform: string, message: string) {
super(message);
Expand Down
16 changes: 16 additions & 0 deletions packages/parameters/src/ExpirableValue.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,31 @@
import type { ExpirableValueInterface } from './types';

/**
* Class to represent a value that can expire.
*
* Upon creation, the value is assigned a TTL (time to live) that is calculated
* by adding the current time with the maximum age.
*/
class ExpirableValue implements ExpirableValueInterface {
public ttl: number;
public value: string | Uint8Array | Record<string, unknown>;

/**
*
* @param value - Value to be cached
* @param maxAge - Maximum age in seconds for the value to be cached
*/
public constructor(value: string | Uint8Array | Record<string, unknown>, maxAge: number) {
this.value = value;
const timeNow = new Date();
this.ttl = timeNow.setSeconds(timeNow.getSeconds() + maxAge);
}

/**
* Check if the value has expired.
*
* @returns {boolean} - True if the value has expired, false otherwise
*/
public isExpired(): boolean {
return this.ttl < Date.now();
}
Expand Down
5 changes: 5 additions & 0 deletions packages/parameters/src/GetMultipleOptions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { DEFAULT_MAX_AGE_SECS } from './constants';
import type { GetMultipleOptionsInterface, TransformOptions } from './types';

/**
* Options for the `getMultiple` method.
*
* It merges the default options with the provided options.
*/
class GetMultipleOptions implements GetMultipleOptionsInterface {
public forceFetch: boolean = false;
public maxAge: number = DEFAULT_MAX_AGE_SECS;
Expand Down
5 changes: 5 additions & 0 deletions packages/parameters/src/GetOptions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { DEFAULT_MAX_AGE_SECS } from './constants';
import type { GetOptionsInterface, TransformOptions } from './types';

/**
* Options for the `get` method.
*
* It merges the default options with the provided options.
*/
class GetOptions implements GetOptionsInterface {
public forceFetch: boolean = false;
public maxAge: number = DEFAULT_MAX_AGE_SECS;
Expand Down
Loading

0 comments on commit 8a47e76

Please sign in to comment.