From 64508c737dc64b5b260902e5b551d1cd40b3c41e Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Thu, 9 Feb 2023 13:14:38 +0100 Subject: [PATCH 01/17] docs: updated typedoc/parameters config --- packages/parameters/package.json | 2 +- packages/parameters/src/docs.ts | 4 ++++ typedoc.js | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 packages/parameters/src/docs.ts diff --git a/packages/parameters/package.json b/packages/parameters/package.json index 469e72f70b..754508eca9 100644 --- a/packages/parameters/package.json +++ b/packages/parameters/package.json @@ -30,7 +30,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" ], diff --git a/packages/parameters/src/docs.ts b/packages/parameters/src/docs.ts new file mode 100644 index 0000000000..028b2bbc6b --- /dev/null +++ b/packages/parameters/src/docs.ts @@ -0,0 +1,4 @@ +export * from './appconfig'; +export * from './ssm'; +export * from './secrets'; +export * from './dynamodb'; \ No newline at end of file diff --git a/typedoc.js b/typedoc.js index de645c6431..d3e9d58c9d 100644 --- a/typedoc.js +++ b/typedoc.js @@ -3,6 +3,7 @@ module.exports = { exclude: [ '**/node_modules/**', '**/*.test.ts', '**/*.json' ], name: 'aws-lambda-powertools-typescript', excludePrivate: true, + excludeInternal: true, entryPointStrategy: 'packages', readme: './README.md', }; \ No newline at end of file From d05cb7fa4329e2e95507dc6c74595c3ef2774b14 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Thu, 9 Feb 2023 14:17:22 +0100 Subject: [PATCH 02/17] chore: update jest config --- packages/parameters/jest.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/parameters/jest.config.js b/packages/parameters/jest.config.js index 6c267d005e..d7114e8417 100644 --- a/packages/parameters/jest.config.js +++ b/packages/parameters/jest.config.js @@ -25,6 +25,7 @@ module.exports = { 'coveragePathIgnorePatterns': [ '/node_modules/', '/types/', + '/src/docs.ts', // this file is only used for documentation ], 'coverageThreshold': { 'global': { From 25c239a4ea574d83bb6d60c819b61a8dd0201db6 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Tue, 21 Feb 2023 18:36:05 +0100 Subject: [PATCH 03/17] docs: wrote api docs for BaseProvider --- packages/parameters/src/BaseProvider.ts | 71 +++++++++++++++---- packages/parameters/src/Exceptions.ts | 3 + packages/parameters/src/ExpirableValue.ts | 16 +++++ packages/parameters/src/GetMultipleOptions.ts | 5 ++ packages/parameters/src/GetOptions.ts | 5 ++ packages/parameters/src/types/BaseProvider.ts | 47 ++++++++++++ 6 files changed, 135 insertions(+), 12 deletions(-) diff --git a/packages/parameters/src/BaseProvider.ts b/packages/parameters/src/BaseProvider.ts index b2fc4efc1c..e9456d8e00 100644 --- a/packages/parameters/src/BaseProvider.ts +++ b/packages/parameters/src/BaseProvider.ts @@ -9,6 +9,25 @@ import type { BaseProviderInterface, GetMultipleOptionsInterface, GetOptionsInte // These providers are dinamycally intialized on first use of the helper functions const DEFAULT_PROVIDERS: Record = {}; +/** + * 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; @@ -16,26 +35,28 @@ abstract class BaseProvider implements BaseProviderInterface { this.store = new Map(); } + /** + * Add a value to the cache. + * + * @param {string} key - Key of the cached value + * @param {string | Uint8Array | Record} 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, 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 @@ -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> { const configs = new GetMultipleOptions(options || {}); const key = [ path, configs.transform ].toString(); @@ -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. * @@ -111,7 +139,7 @@ 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 @@ -119,7 +147,7 @@ abstract class BaseProvider implements BaseProviderInterface { protected abstract _get(name: string, options?: unknown): Promise; /** - * 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 @@ -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 | undefined => { try { const normalizedTransform = transform.toLowerCase(); @@ -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} 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, transform: TransformOptions, throwOnTransformError: boolean): Record | undefined> => { const transformedValues: Record | undefined> = {}; for (const [ entryKey, entryValue ] of Object.entries(value)) { diff --git a/packages/parameters/src/Exceptions.ts b/packages/parameters/src/Exceptions.ts index 845577e453..09712bb60c 100644 --- a/packages/parameters/src/Exceptions.ts +++ b/packages/parameters/src/Exceptions.ts @@ -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); diff --git a/packages/parameters/src/ExpirableValue.ts b/packages/parameters/src/ExpirableValue.ts index 7dcc3a2473..35f6c13be8 100644 --- a/packages/parameters/src/ExpirableValue.ts +++ b/packages/parameters/src/ExpirableValue.ts @@ -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; + /** + * + * @param value - Value to be cached + * @param maxAge - Maximum age in seconds for the value to be cached + */ public constructor(value: string | Uint8Array | Record, 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(); } diff --git a/packages/parameters/src/GetMultipleOptions.ts b/packages/parameters/src/GetMultipleOptions.ts index 5f03a0ee3e..1b1b0180c6 100644 --- a/packages/parameters/src/GetMultipleOptions.ts +++ b/packages/parameters/src/GetMultipleOptions.ts @@ -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; diff --git a/packages/parameters/src/GetOptions.ts b/packages/parameters/src/GetOptions.ts index 807962a5aa..254412f127 100644 --- a/packages/parameters/src/GetOptions.ts +++ b/packages/parameters/src/GetOptions.ts @@ -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; diff --git a/packages/parameters/src/types/BaseProvider.ts b/packages/parameters/src/types/BaseProvider.ts index 1a0ae3fa9a..63c72e8734 100644 --- a/packages/parameters/src/types/BaseProvider.ts +++ b/packages/parameters/src/types/BaseProvider.ts @@ -1,21 +1,68 @@ +/** + * Type for the transform option. + */ type TransformOptions = 'auto' | 'binary' | 'json'; +/** + * Options for the `get` method. + * + * @property {number} maxAge - Maximum age of the value in the cache, in seconds. + * @property {boolean} forceFetch - Force fetch the value from the parameter store, ignoring the cache. + * @property {unknown} sdkOptions - Options to pass to the underlying SDK. + * @property {TransformOptions} transform - Transform to be applied, can be 'json', 'binary', or 'auto'. + */ interface GetOptionsInterface { + /** + * Maximum age of the value in the cache, in seconds. + */ maxAge?: number + /** + * Force fetch the value from the parameter store, ignoring the cache. + */ forceFetch?: boolean + /** + * Options to pass to the underlying SDK. + */ sdkOptions?: unknown + /** + * Transform to be applied, can be 'json', 'binary', or 'auto'. + */ transform?: TransformOptions } +/** + * Options for the `getMultiple` method. + * + * @property {number} maxAge - Maximum age of the value in the cache, in seconds. + * @property {boolean} forceFetch - Force fetch the value from the parameter store, ignoring the cache. + * @property {unknown} sdkOptions - Options to pass to the underlying SDK. + * @property {TransformOptions} transform - Transform to be applied, can be 'json', 'binary', or 'auto'. + * @property {boolean} throwOnTransformError - Whether to throw an error if a value cannot be transformed. + */ interface GetMultipleOptionsInterface extends GetOptionsInterface { + /** + * Whether to throw an error if a value cannot be transformed. + */ throwOnTransformError?: boolean } +/** + * Interface for a value that can expire. + */ interface ExpirableValueInterface { + /** + * Value of the parameter. + */ value: string | Uint8Array | Record + /** + * Expiration timestamp of the value. + */ ttl: number } +/** + * Interface for a parameter store provider. + */ interface BaseProviderInterface { get(name: string, options?: GetOptionsInterface): Promise> getMultiple(path: string, options?: GetMultipleOptionsInterface): Promise> From 6ef198506a01be952f4625d0bea63d429fab4e23 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Tue, 21 Feb 2023 20:03:59 +0100 Subject: [PATCH 04/17] docs: wrote api docs for SecretsProvider --- .../parameters/src/secrets/SecretsProvider.ts | 166 ++++++++++++++++++ packages/parameters/src/secrets/getSecret.ts | 100 +++++++++++ .../parameters/src/types/SecretsProvider.ts | 11 ++ 3 files changed, 277 insertions(+) diff --git a/packages/parameters/src/secrets/SecretsProvider.ts b/packages/parameters/src/secrets/SecretsProvider.ts index 12a6703783..80f9ac12e8 100644 --- a/packages/parameters/src/secrets/SecretsProvider.ts +++ b/packages/parameters/src/secrets/SecretsProvider.ts @@ -9,6 +9,146 @@ import type { SecretsGetOptionsInterface } from '../types/SecretsProvider'; +/** + * ## Intro + * The Parameters utility provides a SecretsProvider that allows to retrieve secrets from AWS Secrets Manager. + * + * ## Getting started + * + * This utility supports AWS SDK v3 for JavaScript only. This allows the utility to be modular, and you to install only + * the SDK packages you need and keep your bundle size small. + * + * To use the provider, you must install the Parameters utility and the AWS SDK v3 for JavaScript for Secrets Manager: + * + * ```sh + * npm install @aws-lambda-powertools/parameters @aws-sdk/client-secrets-manager + * ``` + * + * ## Basic usage + * + * @example + * ```typescript + * import { SecretsProvider } from '@aws-lambda-powertools/parameters/secrets'; + * + * const secretsProvider = new SecretsProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a single secret + * const secret = await secretsProvider.get('my-secret'); + * }; + * ``` + * + * If you want to retrieve secrets without customizing the provider, you can use the {@link getSecret} function instead. + * + * ## Advanced usage + * + * ### Caching + * + * By default, the provider will cache parameters retrieved in-memory for 5 seconds. + * You can adjust how long values should be kept in cache by using the `maxAge` parameter. + * + * @example + * ```typescript + * import { SecretsProvider } from '@aws-lambda-powertools/parameters/secrets'; + * + * const secretsProvider = new SecretsProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a single secret and cache it for 10 seconds + * const secret = await secretsProvider.get('my-secret', { maxAge: 10 }); + * }; + * ``` + * + * If instead you'd like to always ensure you fetch the latest parameter from the store regardless if already available in cache, use the `forceFetch` parameter. + * + * @example + * ```typescript + * import { SecretsProvider } from '@aws-lambda-powertools/parameters/secrets'; + * + * const secretsProvider = new SecretsProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a single secret and always fetch the latest value + * const secret = await secretsProvider.get('my-secret', { forceFetch: true }); + * }; + * ``` + * + * ### Transformations + * + * For parameters stored in JSON or Base64 format, you can use the transform argument for deserialization. + * + * @example + * ```typescript + * import { SecretsProvider } from '@aws-lambda-powertools/parameters/secrets'; + * + * const secretsProvider = new SecretsProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a single secret and deserialize it as JSON + * const secret = await secretsProvider.get('my-secret', { transform: 'json' }); + * }; + * ``` + * + * ### Extra SDK options + * + * When retrieving a secret, you can pass extra options to the AWS SDK v3 for JavaScript client by using the `sdkOptions` parameter. + * + * @example + * ```typescript + * import { SecretsProvider } from '@aws-lambda-powertools/parameters/secrets'; + * + * const secretsProvider = new SecretsProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a single secret and pass extra options to the AWS SDK v3 for JavaScript client + * const secret = await secretsProvider.get('my-secret', { + * sdkOptions: { + * VersionId: 1, + * }, + * }); + * }; + * ``` + * + * This object accepts the same options as the [AWS SDK v3 for JavaScript Secrets Manager client](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-secrets-manager/interfaces/getsecretvaluecommandinput.html). + * + * ### Customize AWS SDK v3 for JavaScript client + * + * By default, the provider will create a new Secrets Manager client using the default configuration. + * + * You can customize the client by passing a custom configuration object to the provider. + * + * @example + * ```typescript + * import { SecretsProvider } from '@aws-lambda-powertools/parameters/secrets'; + * + * const secretsProvider = new SecretsProvider({ + * clientConfig: { region: 'eu-west-1' }, + * }); + * ``` + * + * This object accepts the same options as the [AWS SDK v3 for JavaScript Secrets Manager client](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-secrets-manager/interfaces/secretsmanagerclientconfig.html). + * + * Otherwise, if you want to use a custom client altogether, you can pass it to the provider. + * + * @example + * ```typescript + * import { SecretsProvider } from '@aws-lambda-powertools/parameters/secrets'; + * import { SecretsManagerClient } from '@aws-sdk/client-secrets-manager'; + * + * const client = new SecretsManagerClient({ region: 'eu-west-1' }); + * const secretsProvider = new SecretsProvider({ + * awsSdkV3Client: client, + * }); + * ``` + * + * This object must be an instance of the [AWS SDK v3 for JavaScript Secrets Manager client](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-secrets-manager/classes/secretsmanagerclient.html). + * + * For more usage examples, see [our documentation](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/). + * + * @class + * @implements {BaseProvider} + * @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/ + */ class SecretsProvider extends BaseProvider { public client: SecretsManagerClient; @@ -28,6 +168,32 @@ class SecretsProvider extends BaseProvider { } + /** + * Retrieve a secret from AWS Secrets Manager. + * + * @example + * ```typescript + * import { SecretsProvider } from '@aws-lambda-powertools/parameters/secrets'; + * + * const secretsProvider = new SecretsProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a single secret + * const secret = await secretsProvider.get('my-secret'); + * }; + * ``` + * + * You can customize the retrieval of the secret by passing options to the function: + * * `maxAge` - The maximum age of the value in cache before fetching a new one (in seconds) (default: 5) + * * `forceFetch` - Whether to always fetch a new value from the store regardless if already available in cache + * * `transform` - Whether to transform the value before returning it. Supported values: `json`, `base64` + * * `sdkOptions` - Extra options to pass to the AWS SDK v3 for JavaScript client + * + * For usage examples check {@link SecretsProvider}. + * + * @param {string} name - The name of the secret + * @param {SecretsGetOptionsInterface} options - Options to customize the retrieval of the secret + */ public async get( name: string, options?: SecretsGetOptionsInterface diff --git a/packages/parameters/src/secrets/getSecret.ts b/packages/parameters/src/secrets/getSecret.ts index 92f123e6e5..64298ea155 100644 --- a/packages/parameters/src/secrets/getSecret.ts +++ b/packages/parameters/src/secrets/getSecret.ts @@ -2,6 +2,106 @@ import { DEFAULT_PROVIDERS } from '../BaseProvider'; import { SecretsProvider } from './SecretsProvider'; import type { SecretsGetOptionsInterface } from '../types/SecretsProvider'; +/** + * ## Intro + * The Parameters utility provides a SecretsProvider that allows to retrieve secrets from AWS Secrets Manager. + * + * ## Getting started + * + * This utility supports AWS SDK v3 for JavaScript only. This allows the utility to be modular, and you to install only + * the SDK packages you need and keep your bundle size small. + * + * To use the provider, you must install the Parameters utility and the AWS SDK v3 for JavaScript for Secrets Manager: + * + * ```sh + * npm install @aws-lambda-powertools/parameters @aws-sdk/client-secrets-manager + * ``` + * + * ## Basic usage + * + * @example + * ```typescript + * import { getSecret } from '@aws-lambda-powertools/parameters/secrets'; + * + * export const handler = async (): Promise => { + * // Retrieve a single secret + * const secret = await getSecret('my-secret'); + * }; + * ``` + * + * ## Advanced usage + * + * ### Caching + * + * By default, the provider will cache parameters retrieved in-memory for 5 seconds. + * You can adjust how long values should be kept in cache by using the `maxAge` parameter. + * + * @example + * ```typescript + * import { getSecret } from '@aws-lambda-powertools/parameters/secrets'; + * + * export const handler = async (): Promise => { + * // Retrieve a single secret and cache it for 10 seconds + * const secret = await getSecret('my-secret', { maxAge: 10 }); + * }; + * ``` + * + * If instead you'd like to always ensure you fetch the latest parameter from the store regardless if already available in cache, use the `forceFetch` parameter. + * + * @example + * ```typescript + * import { getSecret } from '@aws-lambda-powertools/parameters/secrets'; + * + * export const handler = async (): Promise => { + * // Retrieve a single secret and always fetch the latest value + * const secret = await getSecret('my-secret', { forceFetch: true }); + * }; + * ``` + * + * ### Transformations + * + * For parameters stored in JSON or Base64 format, you can use the transform argument for deserialization. + * + * @example + * ```typescript + * import { getSecret } from '@aws-lambda-powertools/parameters/secrets'; + * + * export const handler = async (): Promise => { + * // Retrieve a single secret and deserialize it as JSON + * const secret = await getSecret('my-secret', { transform: 'json' }); + * ``` + * + * ### Extra SDK options + * + * When retrieving a secret, you can pass extra options to the AWS SDK v3 for JavaScript client by using the `sdkOptions` parameter. + * + * @example + * ```typescript + * import { getSecret } from '@aws-lambda-powertools/parameters/secrets'; + * + * export const handler = async (): Promise => { + * // Retrieve a single secret and pass extra options to the AWS SDK v3 for JavaScript client + * const secret = await getSecret('my-secret', { + * sdkOptions: { + * VersionId: 1, + * }, + * }); + * }; + * ``` + * + * This object accepts the same options as the [AWS SDK v3 for JavaScript Secrets Manager client](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-secrets-manager/interfaces/getsecretvaluecommandinput.html). + * + * ### Built-in provider class + * + * For greater flexibility such as configuring the underlying SDK client used by built-in providers, you can use the {@link SecretsProvider} class. + * + * For more usage examples, see [our documentation](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/). + * + * + * @param {string} name - The name of the secret to retrieve + * @param {SecretsGetOptionsInterface} options - Options to configure the provider + * @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/ + */ const getSecret = async (name: string, options?: SecretsGetOptionsInterface): Promise> => { if (!DEFAULT_PROVIDERS.hasOwnProperty('secrets')) { DEFAULT_PROVIDERS.secrets = new SecretsProvider(); diff --git a/packages/parameters/src/types/SecretsProvider.ts b/packages/parameters/src/types/SecretsProvider.ts index 757f38b18b..f64a29531b 100644 --- a/packages/parameters/src/types/SecretsProvider.ts +++ b/packages/parameters/src/types/SecretsProvider.ts @@ -11,8 +11,19 @@ interface SecretsProviderOptionsWithClientInstance { clientConfig?: never } +/** + * Options to configure the SecretsProvider. + */ type SecretsProviderOptions = SecretsProviderOptionsWithClientConfig | SecretsProviderOptionsWithClientInstance; +/** + * Options to configure the retrieval of a secret. + * + * @property {number} maxAge - Maximum age of the value in the cache, in seconds. + * @property {boolean} forceFetch - Force fetch the value from the parameter store, ignoring the cache. + * @property {Omit, 'SecretId'>} sdkOptions - Options to pass to the underlying SDK. + * @property {TransformOptions} transform - Transform to be applied, can be 'json' or 'binary'. + */ interface SecretsGetOptionsInterface extends GetOptionsInterface { sdkOptions?: Omit, 'SecretId'> } From 10f5810404241cc2ec208017a882b34c5aa186ef Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Wed, 22 Feb 2023 19:30:25 +0100 Subject: [PATCH 05/17] docs: updates api docs for SecretsProvider --- .../parameters/src/secrets/SecretsProvider.ts | 32 +++++++++++++------ packages/parameters/src/secrets/getSecret.ts | 17 +++++----- 2 files changed, 32 insertions(+), 17 deletions(-) diff --git a/packages/parameters/src/secrets/SecretsProvider.ts b/packages/parameters/src/secrets/SecretsProvider.ts index 80f9ac12e8..c8d1e56b77 100644 --- a/packages/parameters/src/secrets/SecretsProvider.ts +++ b/packages/parameters/src/secrets/SecretsProvider.ts @@ -33,7 +33,7 @@ import type { * const secretsProvider = new SecretsProvider(); * * export const handler = async (): Promise => { - * // Retrieve a single secret + * // Retrieve a secret * const secret = await secretsProvider.get('my-secret'); * }; * ``` @@ -54,8 +54,8 @@ import type { * const secretsProvider = new SecretsProvider(); * * export const handler = async (): Promise => { - * // Retrieve a single secret and cache it for 10 seconds - * const secret = await secretsProvider.get('my-secret', { maxAge: 10 }); + * // Retrieve a secret and cache it for 10 seconds + * const secret = await secretsProvider.get('my-secret', { maxAge: 10 }); * }; * ``` * @@ -68,7 +68,7 @@ import type { * const secretsProvider = new SecretsProvider(); * * export const handler = async (): Promise => { - * // Retrieve a single secret and always fetch the latest value + * // Retrieve a secret and always fetch the latest value * const secret = await secretsProvider.get('my-secret', { forceFetch: true }); * }; * ``` @@ -84,8 +84,8 @@ import type { * const secretsProvider = new SecretsProvider(); * * export const handler = async (): Promise => { - * // Retrieve a single secret and deserialize it as JSON - * const secret = await secretsProvider.get('my-secret', { transform: 'json' }); + * // Retrieve a secret and parse it as JSON + * const secret = await secretsProvider.get('my-secret', { transform: 'json' }); * }; * ``` * @@ -100,7 +100,7 @@ import type { * const secretsProvider = new SecretsProvider(); * * export const handler = async (): Promise => { - * // Retrieve a single secret and pass extra options to the AWS SDK v3 for JavaScript client + * // Retrieve a secret and pass extra options to the AWS SDK v3 for JavaScript client * const secret = await secretsProvider.get('my-secret', { * sdkOptions: { * VersionId: 1, @@ -152,6 +152,11 @@ import type { class SecretsProvider extends BaseProvider { public client: SecretsManagerClient; + /** + * It initializes the SecretsProvider class. + * + * @param {SecretsProviderOptions} config - The configuration object. + */ public constructor (config?: SecretsProviderOptions) { super(); @@ -178,7 +183,7 @@ class SecretsProvider extends BaseProvider { * const secretsProvider = new SecretsProvider(); * * export const handler = async (): Promise => { - * // Retrieve a single secret + * // Retrieve a secret * const secret = await secretsProvider.get('my-secret'); * }; * ``` @@ -186,13 +191,14 @@ class SecretsProvider extends BaseProvider { * You can customize the retrieval of the secret by passing options to the function: * * `maxAge` - The maximum age of the value in cache before fetching a new one (in seconds) (default: 5) * * `forceFetch` - Whether to always fetch a new value from the store regardless if already available in cache - * * `transform` - Whether to transform the value before returning it. Supported values: `json`, `base64` + * * `transform` - Whether to transform the value before returning it. Supported values: `json`, `binary` * * `sdkOptions` - Extra options to pass to the AWS SDK v3 for JavaScript client * * For usage examples check {@link SecretsProvider}. * * @param {string} name - The name of the secret * @param {SecretsGetOptionsInterface} options - Options to customize the retrieval of the secret + * @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/ */ public async get( name: string, @@ -211,6 +217,12 @@ class SecretsProvider extends BaseProvider { return super.getMultiple(path); } + /** + * Retrieve a configuration from AWS AppConfig. + * + * @param {string} name - Name of the configuration or its ID + * @param {SecretsGetOptionsInterface} options - SDK options to propagate to the AWS SDK v3 for JavaScript client + */ protected async _get( name: string, options?: SecretsGetOptionsInterface @@ -229,6 +241,8 @@ class SecretsProvider extends BaseProvider { /** * Retrieving multiple parameter values is not supported with AWS Secrets Manager. + * + * @throws Not Implemented Error. */ protected async _getMultiple( _path: string, diff --git a/packages/parameters/src/secrets/getSecret.ts b/packages/parameters/src/secrets/getSecret.ts index 64298ea155..a6b39b3229 100644 --- a/packages/parameters/src/secrets/getSecret.ts +++ b/packages/parameters/src/secrets/getSecret.ts @@ -24,7 +24,7 @@ import type { SecretsGetOptionsInterface } from '../types/SecretsProvider'; * import { getSecret } from '@aws-lambda-powertools/parameters/secrets'; * * export const handler = async (): Promise => { - * // Retrieve a single secret + * // Retrieve a secret * const secret = await getSecret('my-secret'); * }; * ``` @@ -41,8 +41,8 @@ import type { SecretsGetOptionsInterface } from '../types/SecretsProvider'; * import { getSecret } from '@aws-lambda-powertools/parameters/secrets'; * * export const handler = async (): Promise => { - * // Retrieve a single secret and cache it for 10 seconds - * const secret = await getSecret('my-secret', { maxAge: 10 }); + * // Retrieve a secret and cache it for 10 seconds + * const secret = await getSecret('my-secret', { maxAge: 10 }); * }; * ``` * @@ -53,22 +53,23 @@ import type { SecretsGetOptionsInterface } from '../types/SecretsProvider'; * import { getSecret } from '@aws-lambda-powertools/parameters/secrets'; * * export const handler = async (): Promise => { - * // Retrieve a single secret and always fetch the latest value + * // Retrieve a secret and always fetch the latest value * const secret = await getSecret('my-secret', { forceFetch: true }); * }; * ``` * * ### Transformations * - * For parameters stored in JSON or Base64 format, you can use the transform argument for deserialization. + * For parameters stored as JSON or base64-encoded strings, you can use the transform argument set to `json` or `binary` for deserialization. * * @example * ```typescript * import { getSecret } from '@aws-lambda-powertools/parameters/secrets'; * * export const handler = async (): Promise => { - * // Retrieve a single secret and deserialize it as JSON - * const secret = await getSecret('my-secret', { transform: 'json' }); + * // Retrieve a secret and parse it as JSON + * const secret = await getSecret('my-secret', { transform: 'json' }); + * }; * ``` * * ### Extra SDK options @@ -80,7 +81,7 @@ import type { SecretsGetOptionsInterface } from '../types/SecretsProvider'; * import { getSecret } from '@aws-lambda-powertools/parameters/secrets'; * * export const handler = async (): Promise => { - * // Retrieve a single secret and pass extra options to the AWS SDK v3 for JavaScript client + * // Retrieve a secret and pass extra options to the AWS SDK v3 for JavaScript client * const secret = await getSecret('my-secret', { * sdkOptions: { * VersionId: 1, From b07816151889983301e695d49b7206187557fa8f Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Wed, 22 Feb 2023 19:36:21 +0100 Subject: [PATCH 06/17] docs: updates api docs for SecretsProvider --- .../parameters/src/types/SecretsProvider.ts | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/packages/parameters/src/types/SecretsProvider.ts b/packages/parameters/src/types/SecretsProvider.ts index f64a29531b..152dff709b 100644 --- a/packages/parameters/src/types/SecretsProvider.ts +++ b/packages/parameters/src/types/SecretsProvider.ts @@ -1,27 +1,48 @@ import type { GetOptionsInterface } from './BaseProvider'; import type { SecretsManagerClient, SecretsManagerClientConfig, GetSecretValueCommandInput } from '@aws-sdk/client-secrets-manager'; +/** + * Base interface for SecretsProviderOptions. + * + * @interface + * @property {SecretsManagerClientConfig} [clientConfig] - Optional configuration to pass during client initialization, e.g. AWS region. + * @property {never} [awsSdkV3Client] - This property should never be passed. + */ interface SecretsProviderOptionsWithClientConfig { clientConfig?: SecretsManagerClientConfig awsSdkV3Client?: never } +/** + * Interface for SecretsProviderOptions with awsSdkV3Client property. + * + * @interface + * @extends SecretsProviderOptionsWithClientConfig + * @property {SecretsManagerClient} [awsSdkV3Client] - Optional AWS SDK v3 client to pass during SecretsProvider class instantiation + * @property {never} [clientConfig] - This property should never be passed. + */ interface SecretsProviderOptionsWithClientInstance { awsSdkV3Client?: SecretsManagerClient clientConfig?: never } /** - * Options to configure the SecretsProvider. + * Options for the SecretsProvider class constructor. + * + * @type SecretsProviderOptions + * @property {AppConfigDataClientConfig} [clientConfig] - Optional configuration to pass during client initialization, e.g. AWS region. Mutually exclusive with awsSdkV3Client. + * @property {AppConfigDataClient} [awsSdkV3Client] - Optional AWS SDK v3 client to pass during SecretsProvider class instantiation. Mutually exclusive with clientConfig. */ type SecretsProviderOptions = SecretsProviderOptionsWithClientConfig | SecretsProviderOptionsWithClientInstance; /** * Options to configure the retrieval of a secret. * + * @interface SecretsGetOptionsInterface + * @extends {GetOptionsInterface} * @property {number} maxAge - Maximum age of the value in the cache, in seconds. * @property {boolean} forceFetch - Force fetch the value from the parameter store, ignoring the cache. - * @property {Omit, 'SecretId'>} sdkOptions - Options to pass to the underlying SDK. + * @property {GetSecretValueCommandInput} sdkOptions - Options to pass to the underlying SDK. * @property {TransformOptions} transform - Transform to be applied, can be 'json' or 'binary'. */ interface SecretsGetOptionsInterface extends GetOptionsInterface { From 146720e27c88229cd07b9063294b9a8fa9fb56f6 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Wed, 22 Feb 2023 19:36:41 +0100 Subject: [PATCH 07/17] docs: wrote api docs for AppConfigProvider --- .../src/appconfig/AppConfigProvider.ts | 204 ++++++++++++++++-- .../parameters/src/appconfig/getAppConfig.ts | 117 +++++++++- .../parameters/src/types/AppConfigProvider.ts | 3 + ...pConfigProvider.class.test.functionCode.ts | 6 +- 4 files changed, 309 insertions(+), 21 deletions(-) diff --git a/packages/parameters/src/appconfig/AppConfigProvider.ts b/packages/parameters/src/appconfig/AppConfigProvider.ts index 9e9e2b0152..4ecc1d426f 100644 --- a/packages/parameters/src/appconfig/AppConfigProvider.ts +++ b/packages/parameters/src/appconfig/AppConfigProvider.ts @@ -10,6 +10,163 @@ import type { AppConfigGetOptionsInterface, } from '../types/AppConfigProvider'; +/** + * ## Intro + * The Parameters utility provides an AppConfigProvider that allows to retrieve configuration profiles from AWS AppConfig. + * + * ## Getting started + * + * This utility supports AWS SDK v3 for JavaScript only. This allows the utility to be modular, and you to install only + * the SDK packages you need and keep your bundle size small. + * + * To use the provider, you must install the Parameters utility and the AWS SDK v3 for JavaScript for AppConfig: + * + * ```sh + * npm install @aws-lambda-powertools/parameters @aws-sdk/client-appconfigdata + * ``` + * + * ## Basic usage + * + * @example + * ```typescript + * import { AppConfigProvider } from '@aws-lambda-powertools/parameters/appconfig'; + * + * const configProvider = new AppConfigProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a configuration profile + * const encodedConfig = await configProvider.get('my-config'); + * const config = new TextDecoder('utf-8').decode(encodedConfig); + * }; + * ``` + * If you want to retrieve configs without customizing the provider, you can use the {@link getAppConfig} function instead. + * + * ## Advanced usage + * + * ### Caching + * + * By default, the provider will cache parameters retrieved in-memory for 5 seconds. + * You can adjust how long values should be kept in cache by using the `maxAge` parameter. + * + * @example + * ```typescript + * import { AppConfigProvider } from '@aws-lambda-powertools/parameters/appconfig'; + * + * const configProvider = new AppConfigProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a configuration profile and cache it for 10 seconds + * const encodedConfig = await configProvider.get('my-config'); + * const config = new TextDecoder('utf-8').decode(encodedConfig); + * }; + * ``` + * + * If instead you'd like to always ensure you fetch the latest parameter from the store regardless if already available in cache, use the `forceFetch` parameter. + * + * @example + * ```typescript + * import { AppConfigProvider } from '@aws-lambda-powertools/parameters/appconfig'; + * + * const configProvider = new AppConfigProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a config and always fetch the latest value + * const config = await configProvider.get('my-config', { forceFetch: true }); + * const config = new TextDecoder('utf-8').decode(encodedConfig); + * }; + * ``` + * + * ### Transformations + * + * For configurations stored as freeform JSON, Freature Flag, you can use the transform argument for deserialization. This will return a JavaScript object instead of a string. + * + * @example + * ```typescript + * import { AppConfigProvider } from '@aws-lambda-powertools/parameters/appconfig'; + * + * const configProvider = new AppConfigProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a JSON config or Feature Flag and parse it as JSON + * const config = await configProvider.get('my-config', { transform: 'json' }); + * }; + * ``` + * + * For configurations that are instead stored as base64-encoded binary data, you can use the transform argument set to `binary` for decoding. This will return a decoded string. + * + * @example + * ```typescript + * import { AppConfigProvider } from '@aws-lambda-powertools/parameters/appconfig'; + * + * const configProvider = new AppConfigProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a base64-encoded string and decode it + * const config = await configProvider.get('my-config', { transform: 'binary' }); + * }; + * ``` + * + * ### Extra SDK options + * + * When retrieving a configuration profile, you can pass extra options to the AWS SDK v3 for JavaScript client by using the `sdkOptions` parameter. + * + * @example + * ```typescript + * import { AppConfigProvider } from '@aws-lambda-powertools/parameters/appconfig'; + * + * const configProvider = new AppConfigProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a config and pass extra options to the AWS SDK v3 for JavaScript client + * const config = await configProvider.get('my-config', { + * sdkOptions: { + * RequiredMinimumPollIntervalInSeconds: 60, + * }, + * }); + * const config = new TextDecoder('utf-8').decode(encodedConfig); + * }; + * ``` + * + * This object accepts the same options as the [AWS SDK v3 for JavaScript AppConfigData client](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-appconfigdata/interfaces/startconfigurationsessioncommandinput.html). + * + * ### Customize AWS SDK v3 for JavaScript client + * + * By default, the provider will create a new AppConfigData client using the default configuration. + * + * You can customize the client by passing a custom configuration object to the provider. + * + * @example + * ```typescript + * import { AppConfigProvider } from '@aws-lambda-powertools/parameters/appconfig'; + * + * const configProvider = new AppConfigProvider({ + * clientConfig: { region: 'eu-west-1' }, + * }); + * ``` + * + * This object accepts the same options as the [AWS SDK v3 for JavaScript AppConfig Data client](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-appconfigdata/interfaces/appconfigdataclientconfig.html). + * + * Otherwise, if you want to use a custom client altogether, you can pass it to the provider. + * + * @example + * ```typescript + * import { AppConfigProvider } from '@aws-lambda-powertools/parameters/appconfig'; + * import { AppConfigDataClient } from '@aws-sdk/client-appconfigdata'; + * + * const client = new AppConfigDataClient({ region: 'eu-west-1' }); + * const configProvider = new AppConfigProvider({ + * awsSdkV3Client: client, + * }); + * ``` + * + * This object must be an instance of the [AWS SDK v3 for JavaScript AppConfig Data client](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-appconfigdata/classes/appconfigdataclient.html). + * + * For more usage examples, see [our documentation](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/). + * + * @param {string} name - The name of the configuration profile or its ID + * @param {GetAppConfigCombinedInterface} options - Options to configure the provider + * @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/ + */ class AppConfigProvider extends BaseProvider { public client: AppConfigDataClient; protected configurationTokenStore: Map = new Map(); @@ -17,9 +174,9 @@ class AppConfigProvider extends BaseProvider { private environment: string; /** - * It initializes the AppConfigProvider class'. + * It initializes the AppConfigProvider class. * * - * @param {AppConfigProviderOptions} options + * @param {AppConfigProviderOptions} options - The configuration object. */ public constructor(options: AppConfigProviderOptions) { super(); @@ -44,7 +201,32 @@ class AppConfigProvider extends BaseProvider { } /** - * Retrieve a configuration from AWS App config. + * Retrieve a secret from AWS AppConfig. + * + * @example + * ```typescript + * import { AppConfigProvider } from '@aws-lambda-powertools/parameters/appconfig'; + * + * const configProvider = new AppConfigProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a configuration profile + * const encodedConfig = await configProvider.get('my-config'); + * const config = new TextDecoder('utf-8').decode(encodedConfig); + * }; + * ``` + * + * You can customize the retrieval of the secret by passing options to the function: + * * `maxAge` - The maximum age of the value in cache before fetching a new one (in seconds) (default: 5) + * * `forceFetch` - Whether to always fetch a new value from the store regardless if already available in cache + * * `transform` - Whether to transform the value before returning it. Supported values: `json`, `binary` + * * `sdkOptions` - Extra options to pass to the AWS SDK v3 for JavaScript client + * + * For usage examples check {@link AppConfigProvider}. + * + * @param {string} name - The name of the configuration profile or its ID + * @param {GetAppConfigCombinedInterface} options - Options to configure the provider + * @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/ */ public async get( name: string, @@ -54,7 +236,7 @@ class AppConfigProvider extends BaseProvider { } /** - * Retrieving multiple configurations is not supported by AWS App Config Provider. + * Retrieving multiple configurations is not supported by AWS AppConfig. */ public async getMultiple( path: string, @@ -64,11 +246,10 @@ class AppConfigProvider extends BaseProvider { } /** - * Retrieve a configuration from AWS App config. + * Retrieve a configuration from AWS AppConfig. * - * @param {string} name - Name of the configuration + * @param {string} name - Name of the configuration or its ID * @param {AppConfigGetOptionsInterface} options - SDK options to propagate to `StartConfigurationSession` API call - * @returns {Promise} */ protected async _get( name: string, @@ -80,7 +261,6 @@ class AppConfigProvider extends BaseProvider { * First we start the session and after that we retrieve the configuration * We need to store { name: token } pairs to use in the next execution **/ - if (!this.configurationTokenStore.has(name)) { const sessionOptions: StartConfigurationSessionCommandInput = { @@ -117,7 +297,7 @@ class AppConfigProvider extends BaseProvider { } /** - * Retrieving multiple configurations is not supported by AWS App Config Provider API. + * Retrieving multiple configurations is not supported by AWS AppConfig. * * @throws Not Implemented Error. */ @@ -125,11 +305,7 @@ class AppConfigProvider extends BaseProvider { _path: string, _sdkOptions?: unknown ): Promise> { - return this._notImplementedError(); - } - - private _notImplementedError(): never { - throw new Error('Not Implemented'); + throw new Error('Method not implemented.'); } } diff --git a/packages/parameters/src/appconfig/getAppConfig.ts b/packages/parameters/src/appconfig/getAppConfig.ts index ca336ea777..7613e0d942 100644 --- a/packages/parameters/src/appconfig/getAppConfig.ts +++ b/packages/parameters/src/appconfig/getAppConfig.ts @@ -2,11 +2,120 @@ import { AppConfigProvider, DEFAULT_PROVIDERS } from './AppConfigProvider'; import type { GetAppConfigCombinedInterface } from '../types/AppConfigProvider'; /** - * Gets the AppConfig data for the specified name. + * ## Intro + * The Parameters utility provides an AppConfigProvider that allows to retrieve configuration profiles from AWS AppConfig. + * + * ## Getting started + * + * This utility supports AWS SDK v3 for JavaScript only. This allows the utility to be modular, and you to install only + * the SDK packages you need and keep your bundle size small. + * + * To use the provider, you must install the Parameters utility and the AWS SDK v3 for JavaScript for AppConfig: + * + * ```sh + * npm install @aws-lambda-powertools/parameters @aws-sdk/client-appconfigdata + * ``` * - * @param {string} name - The configuration profile ID or the configuration profile name. - * @param {GetAppConfigCombinedInterface} options - Options for the AppConfigProvider and the get method. - * @returns {Promise>} A promise that resolves to the AppConfig data or undefined if not found. + * ## Basic usage + * + * @example + * ```typescript + * import { getAppConfig } from '@aws-lambda-powertools/parameters/appconfig'; + * + * export const handler = async (): Promise => { + * // Retrieve a configuration profile + * const encodedConfig = await getAppConfig('my-config'); + * const config = new TextDecoder('utf-8').decode(encodedConfig); + * }; + * ``` + * + * ## Advanced usage + * + * ### Caching + * + * By default, the provider will cache parameters retrieved in-memory for 5 seconds. + * You can adjust how long values should be kept in cache by using the `maxAge` parameter. + * + * @example + * ```typescript + * import { getAppConfig } from '@aws-lambda-powertools/parameters/appconfig'; + * + * export const handler = async (): Promise => { + * // Retrieve a configuration profile and cache it for 10 seconds + * const encodedConfig = await getAppConfig('my-config'); + * const config = new TextDecoder('utf-8').decode(encodedConfig); + * }; + * ``` + * + * If instead you'd like to always ensure you fetch the latest parameter from the store regardless if already available in cache, use the `forceFetch` parameter. + * + * @example + * ```typescript + * import { getAppConfig } from '@aws-lambda-powertools/parameters/appconfig'; + * + * export const handler = async (): Promise => { + * // Retrieve a config and always fetch the latest value + * const config = await getAppConfig('my-config', { forceFetch: true }); + * const config = new TextDecoder('utf-8').decode(encodedConfig); + * }; + * ``` + * + * ### Transformations + * + * For configurations stored as freeform JSON, Freature Flag, you can use the transform argument for deserialization. This will return a JavaScript object instead of a string. + * + * @example + * ```typescript + * import { getAppConfig } from '@aws-lambda-powertools/parameters/appconfig'; + * + * export const handler = async (): Promise => { + * // Retrieve a JSON config or Feature Flag and parse it as JSON + * const config = await getAppConfig('my-config', { transform: 'json' }); + * }; + * ``` + * + * For configurations that are instead stored as base64-encoded binary data, you can use the transform argument set to `binary` for decoding. This will return a decoded string. + * + * @example + * ```typescript + * import { getAppConfig } from '@aws-lambda-powertools/parameters/appconfig'; + * + * export const handler = async (): Promise => { + * // Retrieve a base64-encoded string and decode it + * const config = await getAppConfig('my-config', { transform: 'binary' }); + * }; + * ``` + * + * ### Extra SDK options + * + * When retrieving a configuration profile, you can pass extra options to the AWS SDK v3 for JavaScript client by using the `sdkOptions` parameter. + * + * @example + * ```typescript + * import { getAppConfig } from '@aws-lambda-powertools/parameters/appconfig'; + * + * export const handler = async (): Promise => { + * // Retrieve a config and pass extra options to the AWS SDK v3 for JavaScript client + * const config = await getAppConfig('my-config', { + * sdkOptions: { + * RequiredMinimumPollIntervalInSeconds: 60, + * }, + * }); + * const config = new TextDecoder('utf-8').decode(encodedConfig); + * }; + * ``` + * + * This object accepts the same options as the [AWS SDK v3 for JavaScript AppConfigData client](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-appconfigdata/interfaces/startconfigurationsessioncommandinput.html). + * + * ### Built-in provider class + * + * For greater flexibility such as configuring the underlying SDK client used by built-in providers, you can use the {@link AppConfigProvider} class. + * + * For more usage examples, see [our documentation](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/). + * + * @param {string} name - The name of the configuration profile or its ID + * @param {GetAppConfigCombinedInterface} options - Options to configure the provider + * @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/ */ const getAppConfig = ( name: string, diff --git a/packages/parameters/src/types/AppConfigProvider.ts b/packages/parameters/src/types/AppConfigProvider.ts index 007bca8a50..ab6ff2868a 100644 --- a/packages/parameters/src/types/AppConfigProvider.ts +++ b/packages/parameters/src/types/AppConfigProvider.ts @@ -59,7 +59,10 @@ type AppConfigProviderOptions = AppConfigProviderOptionsWithClientConfig | AppCo * * @interface AppConfigGetOptionsInterface * @extends {GetOptionsInterface} + * @property {number} maxAge - Maximum age of the value in the cache, in seconds. + * @property {boolean} forceFetch - Force fetch the value from the parameter store, ignoring the cache. * @property {StartConfigurationSessionCommandInput} [sdkOptions] - Required options to start configuration session. + * @property {TransformOptions} transform - Transform to be applied, can be 'json' or 'binary'. */ interface AppConfigGetOptionsInterface extends Omit { sdkOptions?: Omit< diff --git a/packages/parameters/tests/e2e/appConfigProvider.class.test.functionCode.ts b/packages/parameters/tests/e2e/appConfigProvider.class.test.functionCode.ts index 11d8feb01f..8d3df5445b 100644 --- a/packages/parameters/tests/e2e/appConfigProvider.class.test.functionCode.ts +++ b/packages/parameters/tests/e2e/appConfigProvider.class.test.functionCode.ts @@ -73,10 +73,10 @@ export const handler = async (_event: unknown, _context: Context): Promise // Test 3 - get a free-form base64-encoded plain text and apply binary transformation (should return a decoded string) await _call_get(freeFormBase64encodedPlainText, 'get-freeform-base64-plaintext-binary', { transform: 'binary' }); - // Test 5 - get a feature flag and apply json transformation (should return an object) + // Test 4 - get a feature flag and apply json transformation (should return an object) await _call_get(featureFlagName, 'get-feature-flag-binary', { transform: 'json' }); - // Test 6 + // Test 5 // get parameter twice with middleware, which counts the number of requests, we check later if we only called AppConfig API once try { providerWithMiddleware.clearCache(); @@ -94,7 +94,7 @@ export const handler = async (_event: unknown, _context: Context): Promise }); } - // Test 7 + // Test 6 // get parameter twice, but force fetch 2nd time, we count number of SDK requests and check that we made two API calls try { providerWithMiddleware.clearCache(); From 452ca89ea63205441b2c697cd84cd1ba27e71225 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Thu, 23 Feb 2023 11:44:52 +0100 Subject: [PATCH 08/17] fix: error message --- packages/parameters/tests/unit/AppConfigProvider.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/parameters/tests/unit/AppConfigProvider.test.ts b/packages/parameters/tests/unit/AppConfigProvider.test.ts index 56365d882c..bf10013df0 100644 --- a/packages/parameters/tests/unit/AppConfigProvider.test.ts +++ b/packages/parameters/tests/unit/AppConfigProvider.test.ts @@ -236,7 +236,7 @@ describe('Class: AppConfigProvider', () => { }; const path = '/my/path'; const provider = new AppConfigProvider(config); - const errorMessage = 'Not Implemented'; + const errorMessage = 'Method not implemented.'; // Act & Assess await expect(provider.getMultiple(path)).rejects.toThrow(errorMessage); From 8209b07e9901212a7688978ca1edaca6b6f27ab3 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Thu, 23 Feb 2023 18:49:16 +0100 Subject: [PATCH 09/17] fix: wording and spacing --- .../parameters/src/appconfig/AppConfigProvider.ts | 14 +++++--------- packages/parameters/src/types/AppConfigProvider.ts | 14 +++++++------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/packages/parameters/src/appconfig/AppConfigProvider.ts b/packages/parameters/src/appconfig/AppConfigProvider.ts index 4ecc1d426f..84a83cc68d 100644 --- a/packages/parameters/src/appconfig/AppConfigProvider.ts +++ b/packages/parameters/src/appconfig/AppConfigProvider.ts @@ -56,7 +56,7 @@ import type { * * export const handler = async (): Promise => { * // Retrieve a configuration profile and cache it for 10 seconds - * const encodedConfig = await configProvider.get('my-config'); + * const encodedConfig = await configProvider.get('my-config', { maxAge: 10 }); * const config = new TextDecoder('utf-8').decode(encodedConfig); * }; * ``` @@ -140,7 +140,7 @@ import type { * import { AppConfigProvider } from '@aws-lambda-powertools/parameters/appconfig'; * * const configProvider = new AppConfigProvider({ - * clientConfig: { region: 'eu-west-1' }, + * clientConfig: { region: 'eu-west-1' }, * }); * ``` * @@ -155,17 +155,13 @@ import type { * * const client = new AppConfigDataClient({ region: 'eu-west-1' }); * const configProvider = new AppConfigProvider({ - * awsSdkV3Client: client, + * awsSdkV3Client: client, * }); * ``` * * This object must be an instance of the [AWS SDK v3 for JavaScript AppConfig Data client](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-appconfigdata/classes/appconfigdataclient.html). * * For more usage examples, see [our documentation](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/). - * - * @param {string} name - The name of the configuration profile or its ID - * @param {GetAppConfigCombinedInterface} options - Options to configure the provider - * @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/ */ class AppConfigProvider extends BaseProvider { public client: AppConfigDataClient; @@ -201,7 +197,7 @@ class AppConfigProvider extends BaseProvider { } /** - * Retrieve a secret from AWS AppConfig. + * Retrieve a configuration profile from AWS AppConfig. * * @example * ```typescript @@ -216,7 +212,7 @@ class AppConfigProvider extends BaseProvider { * }; * ``` * - * You can customize the retrieval of the secret by passing options to the function: + * You can customize the retrieval of the configuration profile by passing options to the function: * * `maxAge` - The maximum age of the value in cache before fetching a new one (in seconds) (default: 5) * * `forceFetch` - Whether to always fetch a new value from the store regardless if already available in cache * * `transform` - Whether to transform the value before returning it. Supported values: `json`, `binary` diff --git a/packages/parameters/src/types/AppConfigProvider.ts b/packages/parameters/src/types/AppConfigProvider.ts index ab6ff2868a..4e80c225cf 100644 --- a/packages/parameters/src/types/AppConfigProvider.ts +++ b/packages/parameters/src/types/AppConfigProvider.ts @@ -8,9 +8,9 @@ import type { GetOptionsInterface } from 'types/BaseProvider'; /** * Base interface for AppConfigProviderOptions. * - * @interface - * @property {string} environment - The environment ID or the environment name. - * @property {string} [application] - The application ID or the application name. + * @interface + * @property {string} environment - The environment ID or the environment name. + * @property {string} [application] - The application ID or the application name. */ interface AppConfigProviderOptionsBaseInterface { environment: string @@ -20,10 +20,10 @@ interface AppConfigProviderOptionsBaseInterface { /** * Interface for AppConfigProviderOptions with clientConfig property. * - * @interface - * @extends AppConfigProviderOptionsBaseInterface - * @property {AppConfigDataClientConfig} [clientConfig] - Optional configuration to pass during client initialization, e.g. AWS region. - * @property {never} [awsSdkV3Client] - This property should never be passed. + * @interface + * @extends AppConfigProviderOptionsBaseInterface + * @property {AppConfigDataClientConfig} [clientConfig] - Optional configuration to pass during client initialization, e.g. AWS region. + * @property {never} [awsSdkV3Client] - This property should never be passed. */ interface AppConfigProviderOptionsWithClientConfig extends AppConfigProviderOptionsBaseInterface { clientConfig?: AppConfigDataClientConfig From d9ca10a48aebc0d39b2da689d7dbdfcd3844b488 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Thu, 23 Feb 2023 18:52:21 +0100 Subject: [PATCH 10/17] docs: added DynamoDBProvider api --- .../src/dynamodb/DynamoDBProvider.ts | 295 ++++++++++++++++++ .../parameters/src/types/DynamoDBProvider.ts | 55 +++- 2 files changed, 347 insertions(+), 3 deletions(-) diff --git a/packages/parameters/src/dynamodb/DynamoDBProvider.ts b/packages/parameters/src/dynamodb/DynamoDBProvider.ts index 58f0f2456b..66445c0090 100644 --- a/packages/parameters/src/dynamodb/DynamoDBProvider.ts +++ b/packages/parameters/src/dynamodb/DynamoDBProvider.ts @@ -9,6 +9,225 @@ import type { GetItemCommandInput, QueryCommandInput } from '@aws-sdk/client-dyn import { marshall, unmarshall } from '@aws-sdk/util-dynamodb'; import type { PaginationConfiguration } from '@aws-sdk/types'; +/** + * ## Intro + * The Parameters utility provides a DynamoDBProvider that allows to retrieve values from Amazon DynamoDB. + * + * ## Getting started + * + * This utility supports AWS SDK v3 for JavaScript only. This allows the utility to be modular, and you to install only + * the SDK packages you need and keep your bundle size small. + * + * To use the provider, you must install the Parameters utility and the AWS SDK v3 for JavaScript for AppConfig: + * + * ```sh + * npm install @aws-lambda-powertools/parameters @aws-sdk/client-dynamodb + * ``` + * + * ## Basic usage + * + * Retrieve a value from DynamoDB: + * + * @example + * ```typescript + * import { DynamoDBProvider } from '@aws-lambda-powertools/parameters/dynamodb'; + * + * const tableProvider = new DynamoDBProvider({ + * tableName: 'my-table', + * }); + * + * export const handler = async (): Promise => { + * // Retrieve a value from DynamoDB + * const value = await tableProvider.get('my-value-key'); + * }; + * ``` + * + * You can also retrieve multiple values at once: + * + * @example + * ```typescript + * import { DynamoDBProvider } from '@aws-lambda-powertools/parameters/dynamodb'; + * + * const tableProvider = new DynamoDBProvider({ + * tableName: 'my-table', + * }); + * + * export const handler = async (): Promise => { + * // Retrieve multiple values from DynamoDB + * const values = await tableProvider.getMultiple('my-values-path'); + * }; + * + * ## Advanced usage + * + * ### Caching + * + * By default, the provider will cache parameters retrieved in-memory for 5 seconds. + * You can adjust how long values should be kept in cache by using the `maxAge` parameter. + * + * @example + * ```typescript + * import { DynamoDBProvider } from '@aws-lambda-powertools/parameters/dynamodb'; + * + * const tableProvider = new DynamoDBProvider({ + * tableName: 'my-table', + * }); + * + * export const handler = async (): Promise => { + * // Retrieve a value and cache it for 10 seconds + * const value = await tableProvider.get('my-value-key', { maxAge: 10 }); + * // Retrieve multiple values and cache them for 20 seconds + * const values = await tableProvider.getMultiple('my-values-path', { maxAge: 20 }); + * }; + * ``` + * + * If instead you'd like to always ensure you fetch the latest parameter from the store regardless if already available in cache, use the `forceFetch` parameter. + * + * @example + * ```typescript + * import { DynamoDBProvider } from '@aws-lambda-powertools/parameters/dynamodb'; + * + * const tableProvider = new DynamoDBProvider({ + * tableName: 'my-table', + * }); + * + * export const handler = async (): Promise => { + * // Retrieve a value and skip cache + * const value = await tableProvider.get('my-value-key', { forceFetch: true }); + * // Retrieve multiple values and skip cache + * const values = await tableProvider.getMultiple('my-values-path', { forceFetch: true }); + * }; + * ``` + * + * ### Transformations + * + * For configurations stored as freeform JSON, Freature Flag, you can use the transform argument for deserialization. This will return a JavaScript object instead of a string. + * + * @example + * ```typescript + * import { DynamoDBProvider } from '@aws-lambda-powertools/parameters/dynamodb'; + * + * const tableProvider = new DynamoDBProvider({ + * tableName: 'my-table', + * }); + * + * export const handler = async (): Promise => { + * // Retrieve a value and parse it as JSON + * const value = await tableProvider.get('my-value-key', { transform: 'json' }); + * // Retrieve multiple values and parse them as JSON + * const values = await tableProvider.getMultiple('my-values-path', { transform: 'json' }); + * }; + * ``` + * + * For values that are instead stored as base64-encoded binary data, you can use the transform argument set to `binary` for decoding. This will return a decoded string. + * + * @example + * ```typescript + * import { DynamoDBProvider } from '@aws-lambda-powertools/parameters/dynamodb'; + * + * const tableProvider = new DynamoDBProvider({ + * tableName: 'my-table', + * }); + * + * export const handler = async (): Promise => { + * // Retrieve a base64-encoded string and decode it + * const value = await tableProvider.get('my-value-key', { transform: 'binary' }); + * // Retrieve multiple base64-encoded strings and decode them + * const values = await tableProvider.getMultiple('my-values-path', { transform: 'binary' }); + * }; + * ``` + * + * When retrieving multiple values, you can also use the `transform` argument set to `auto` to let the provider automatically detect the type of transformation to apply. + * The provider will use the suffix of the sort key (`sk`) to determine the transformation to apply. For example, if the sort key is `my-value-key.json`, the provider will + * automatically parse the value as JSON. Likewise, if the sort key is `my-value-key.binary`, the provider will automatically decode the value as base64-encoded binary data. + * + * @example + * ```typescript + * import { DynamoDBProvider } from '@aws-lambda-powertools/parameters/dynamodb'; + * + * const tableProvider = new DynamoDBProvider({ + * tableName: 'my-table', + * }); + * + * export const handler = async (): Promise => { + * // Retrieve multiple values and automatically detect the transformation to apply + * const values = await tableProvider.getMultiple('my-values-path', { transform: 'auto' }); + * }; + * + * ### Custom key names + * + * By default, the provider will use the following key names: `id` for the partition key, `sk` for the sort key, and `value` for the value. + * You can adjust the key names by using the `keyAttr`, `sortAttr`, and `valueAttr` parameters. + * + * @example + * ```typescript + * import { DynamoDBProvider } from '@aws-lambda-powertools/parameters/dynamodb'; + * + * const tableProvider = new DynamoDBProvider({ + * tableName: 'my-table', + * keyAttr: 'key', + * sortAttr: 'sort', + * valueAttr: 'val', + * }); + * ``` + * + * ### Extra SDK options + * + * When retrieving values, you can pass extra options to the AWS SDK v3 for JavaScript client by using the `sdkOptions` parameter. + * + * @example + * ```typescript + * import { DynamoDBProvider } from '@aws-lambda-powertools/parameters/dynamodb'; + * + * const tableProvider = new DynamoDBProvider({ + * tableName: 'my-table', + * }); + * + * export const handler = async (): Promise => { + * // Retrieve a value and pass extra options to the AWS SDK v3 for JavaScript client + * const value = await tableProvider.get('my-value-key', { + * sdkOptions: { + * ConsistentRead: true, + * }, + * }); + * }; + * ``` + * + * The objects accept the same options as respectively the [AWS SDK v3 for JavaScript PutItem command](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-dynamodb/classes/putitemcommand.html) and the [AWS SDK v3 for JavaScript DynamoDB client Query command](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-dynamodb/classes/querycommand.html). + * + * ### Customize AWS SDK v3 for JavaScript client + * + * By default, the provider will create a new DynamoDB client using the default configuration. + * + * You can customize the client by passing a custom configuration object to the provider. + * + * @example + * ```typescript + * import { DynamoDBProvider } from '@aws-lambda-powertools/parameters/dynamodb'; + * + * const tableProvider = new DynamoDBProvider({ + * clientConfig: { region: 'eu-west-1' }, + * }); + * ``` + * + * This object accepts the same options as the [AWS SDK v3 for JavaScript DynamoDB client constructor](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-dynamodb/classes/dynamodbclient.html). + * + * Otherwise, if you want to use a custom client altogether, you can pass it to the provider. + * + * @example + * ```typescript + * import { DynamoDBProvider } from '@aws-lambda-powertools/parameters/dynamodb'; + * import { DynamoDBClient } from '@aws-sdk/client-dynamodb'; + * + * const client = new DynamoDBClient({ region: 'eu-west-1' }); + * const tableProvider = new DynamoDBProvider({ + * awsSdkV3Client: client, + * }); + * ``` + * + * This object must be an instance of the [AWS SDK v3 for JavaScript DynamoDB client](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-dynamodb/classes/dynamodbclient.html). + * + * For more usage examples, see [our documentation](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/). + */ class DynamoDBProvider extends BaseProvider { public client: DynamoDBClient; protected keyAttr: string = 'id'; @@ -16,6 +235,11 @@ class DynamoDBProvider extends BaseProvider { protected tableName: string; protected valueAttr: string = 'value'; + /** + * It initializes the DynamoDBProvider class. + * * + * @param {DynamoDBProviderOptions} config - The configuration object. + */ public constructor(config: DynamoDBProviderOptions) { super(); @@ -36,6 +260,35 @@ class DynamoDBProvider extends BaseProvider { if (config.valueAttr) this.valueAttr = config.valueAttr; } + /** + * Retrieve a value from Amazon DynamoDB. + * + * @example + * ```typescript + * import { DynamoDBProvider } from '@aws-lambda-powertools/parameters/dynamodb'; + * + * const tableProvider = new DynamoDBProvider({ + * tableName: 'my-table', + * }); + * + * export const handler = async (): Promise => { + * // Retrieve a single value + * const value = await tableProvider.get('my-value-key'); + * }; + * ``` + * + * You can customize the retrieval of the value by passing options to the function: + * * `maxAge` - The maximum age of the value in cache before fetching a new one (in seconds) (default: 5) + * * `forceFetch` - Whether to always fetch a new value from the store regardless if already available in cache + * * `transform` - Whether to transform the value before returning it. Supported values: `json`, `binary` + * * `sdkOptions` - Extra options to pass to the AWS SDK v3 for JavaScript client + * + * For usage examples check {@link DynamoDBProvider}. + * + * @param {string} name - The name of the value to retrieve (i.e. the partition key) + * @param {DynamoDBGetOptionsInterface} options - Options to configure the provider + * @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/ + */ public async get( name: string, options?: DynamoDBGetOptionsInterface @@ -43,6 +296,36 @@ class DynamoDBProvider extends BaseProvider { return super.get(name, options) as Promise>; } + /** + * Retrieve multiple values from Amazon DynamoDB. + * + * @example + * ```typescript + * import { DynamoDBProvider } from '@aws-lambda-powertools/parameters/dynamodb'; + * + * const tableProvider = new DynamoDBProvider({ + * tableName: 'my-table', + * }); + * + * export const handler = async (): Promise => { + * // Retrieve multiple values + * const values = await tableProvider.getMultiple('my-values-path'); + * }; + * ``` + * + * You can customize the retrieval of the values by passing options to the function: + * * `maxAge` - The maximum age of the value in cache before fetching a new one (in seconds) (default: 5) + * * `forceFetch` - Whether to always fetch a new value from the store regardless if already available in cache + * * `transform` - Whether to transform the value before returning it. Supported values: `json`, `binary` + * * `sdkOptions` - Extra options to pass to the AWS SDK v3 for JavaScript client + * * `throwOnTransformError` - Whether to throw an error if the transform fails (default: `true`) + * + * For usage examples check {@link DynamoDBProvider}. + * + * @param {string} path - The path of the values to retrieve (i.e. the partition key) + * @param {DynamoDBGetMultipleOptionsInterface} options - Options to configure the provider + * @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/ + */ public async getMultiple( path: string, options?: DynamoDBGetMultipleOptionsInterface @@ -50,6 +333,12 @@ class DynamoDBProvider extends BaseProvider { return super.getMultiple(path, options); } + /** + * Retrieve an item from Amazon DynamoDB. + * + * @param {string} name - Key of the item to retrieve (i.e. the partition key) + * @param {DynamoDBGetOptionsInterface} options - SDK options to propagate to `GetItemCommand` API call + */ protected async _get( name: string, options?: DynamoDBGetOptionsInterface @@ -68,6 +357,12 @@ class DynamoDBProvider extends BaseProvider { return result.Item ? unmarshall(result.Item)[this.valueAttr] : undefined; } + /** + * Retrieve multiple items from Amazon DynamoDB. + * + * @param {string} path - The path of the values to retrieve (i.e. the partition key) + * @param {DynamoDBGetMultipleOptionsInterface} options - Options to configure the provider + */ protected async _getMultiple( path: string, options?: DynamoDBGetMultipleOptionsInterface diff --git a/packages/parameters/src/types/DynamoDBProvider.ts b/packages/parameters/src/types/DynamoDBProvider.ts index 140bf50fd2..075f123838 100644 --- a/packages/parameters/src/types/DynamoDBProvider.ts +++ b/packages/parameters/src/types/DynamoDBProvider.ts @@ -1,6 +1,15 @@ import type { GetOptionsInterface, GetMultipleOptionsInterface } from './BaseProvider'; import type { DynamoDBClient, GetItemCommandInput, QueryCommandInput, DynamoDBClientConfig } from '@aws-sdk/client-dynamodb'; +/** + * Base interface for DynamoDBProviderOptions. + * + * @interface + * @property {string} tableName - The DynamoDB table name. + * @property {string} [keyAttr] - The DynamoDB table key attribute name. Defaults to 'id'. + * @property {string} [sortAttr] - The DynamoDB table sort attribute name. Defaults to 'sk'. + * @property {string} [valueAttr] - The DynamoDB table value attribute name. Defaults to 'value'. + */ interface DynamoDBProviderOptionsBaseInterface { tableName: string keyAttr?: string @@ -8,30 +17,70 @@ interface DynamoDBProviderOptionsBaseInterface { valueAttr?: string } +/** + * Interface for DynamoDBProviderOptions with clientConfig property. + * + * @interface + * @extends DynamoDBProviderOptionsBaseInterface + * @property {AppConfigDataClientConfig} [clientConfig] - Optional configuration to pass during client initialization, e.g. AWS region. + * @property {never} [awsSdkV3Client] - This property should never be passed. + */ interface DynamoDBProviderOptionsWithClientConfig extends DynamoDBProviderOptionsBaseInterface { clientConfig?: DynamoDBClientConfig awsSdkV3Client?: never } +/** + * Interface for DynamoDBProviderOptions with awsSdkV3Client property. + * + * @interface + * @extends DynamoDBProviderOptionsBaseInterface + * @property {AppConfigDataClient} [awsSdkV3Client] - Optional AWS SDK v3 client to pass during AppConfigProvider class instantiation + * @property {never} [clientConfig] - This property should never be passed. + */ interface DynamoDBProviderOptionsWithClientInstance extends DynamoDBProviderOptionsBaseInterface { awsSdkV3Client?: DynamoDBClient clientConfig?: never } +/** + * Options for the AppConfigProvider class constructor. + * + * @type AppConfigProviderOptions + * @property {string} tableName - The DynamoDB table name. + * @property {string} [keyAttr] - The DynamoDB table key attribute name. Defaults to 'id'. + * @property {string} [sortAttr] - The DynamoDB table sort attribute name. Defaults to 'sk'. + * @property {string} [valueAttr] - The DynamoDB table value attribute name. Defaults to 'value'. + * @property {AppConfigDataClientConfig} [clientConfig] - Optional configuration to pass during client initialization, e.g. AWS region. Mutually exclusive with awsSdkV3Client. + * @property {AppConfigDataClient} [awsSdkV3Client] - Optional AWS SDK v3 client to pass during DynamoDBProvider class instantiation. Mutually exclusive with clientConfig. + */ type DynamoDBProviderOptions = DynamoDBProviderOptionsWithClientConfig | DynamoDBProviderOptionsWithClientInstance; /** * Options for the DynamoDBProvider get method. - * + * * @interface DynamoDBGetOptionsInterface * @extends {GetOptionsInterface} - * @property {boolean} decrypt - If true, the parameter will be decrypted. - * @property {Partial} sdkOptions - Options for the AWS SDK. + * @property {number} maxAge - Maximum age of the value in the cache, in seconds. + * @property {boolean} forceFetch - Force fetch the value from the parameter store, ignoring the cache. + * @property {GetItemCommandInput} [sdkOptions] - Additional options to pass to the AWS SDK v3 client. + * @property {TransformOptions} transform - Transform to be applied, can be 'json' or 'binary'. */ interface DynamoDBGetOptionsInterface extends GetOptionsInterface { sdkOptions?: Omit, 'Key' | 'TableName' | 'ProjectionExpression'> } +/** + * Options for the DynamoDBProvider getMultiple method. + * + * @interface DynamoDBGetMultipleOptionsInterface + * @extends {GetMultipleOptionsInterface} + * @property {number} maxAge - Maximum age of the value in the cache, in seconds. + * @property {boolean} forceFetch - Force fetch the value from the parameter store, ignoring the cache. + * @property {QueryCommandInput} [sdkOptions] - Additional options to pass to the AWS SDK v3 client. + * @property {TransformOptions} transform - Transform to be applied, can be 'json' or 'binary'. + * @property {boolean} throwOnTransformError - Whether to throw an error if the transform fails (default: `true`) + */ interface DynamoDBGetMultipleOptionsInterface extends GetMultipleOptionsInterface { sdkOptions?: Partial } From fb82e2c9afb19fedb31dc36c59bc5d3432c049f7 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Thu, 23 Feb 2023 18:53:01 +0100 Subject: [PATCH 11/17] chore: spacing --- packages/parameters/src/types/AppConfigProvider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/parameters/src/types/AppConfigProvider.ts b/packages/parameters/src/types/AppConfigProvider.ts index 4e80c225cf..e69fc256c0 100644 --- a/packages/parameters/src/types/AppConfigProvider.ts +++ b/packages/parameters/src/types/AppConfigProvider.ts @@ -61,7 +61,7 @@ type AppConfigProviderOptions = AppConfigProviderOptionsWithClientConfig | AppCo * @extends {GetOptionsInterface} * @property {number} maxAge - Maximum age of the value in the cache, in seconds. * @property {boolean} forceFetch - Force fetch the value from the parameter store, ignoring the cache. - * @property {StartConfigurationSessionCommandInput} [sdkOptions] - Required options to start configuration session. + * @property {StartConfigurationSessionCommandInput} [sdkOptions] - Additional options to pass to the AWS SDK v3 client. * @property {TransformOptions} transform - Transform to be applied, can be 'json' or 'binary'. */ interface AppConfigGetOptionsInterface extends Omit { From 9592deb25ae3f1eb63313a085155c24e83c39078 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Thu, 23 Feb 2023 19:58:13 +0100 Subject: [PATCH 12/17] chore: spacing --- packages/parameters/src/dynamodb/DynamoDBProvider.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/parameters/src/dynamodb/DynamoDBProvider.ts b/packages/parameters/src/dynamodb/DynamoDBProvider.ts index 66445c0090..d178542894 100644 --- a/packages/parameters/src/dynamodb/DynamoDBProvider.ts +++ b/packages/parameters/src/dynamodb/DynamoDBProvider.ts @@ -21,7 +21,7 @@ import type { PaginationConfiguration } from '@aws-sdk/types'; * To use the provider, you must install the Parameters utility and the AWS SDK v3 for JavaScript for AppConfig: * * ```sh - * npm install @aws-lambda-powertools/parameters @aws-sdk/client-dynamodb + * npm install @aws-lambda-powertools/parameters @aws-sdk/client-dynamodb @aws-sdk/util-dynamodb * ``` * * ## Basic usage @@ -100,7 +100,7 @@ import type { PaginationConfiguration } from '@aws-sdk/types'; * * ### Transformations * - * For configurations stored as freeform JSON, Freature Flag, you can use the transform argument for deserialization. This will return a JavaScript object instead of a string. + * For values stored as JSON you can use the transform argument for deserialization. This will return a JavaScript object instead of a string. * * @example * ```typescript @@ -152,6 +152,7 @@ import type { PaginationConfiguration } from '@aws-sdk/types'; * // Retrieve multiple values and automatically detect the transformation to apply * const values = await tableProvider.getMultiple('my-values-path', { transform: 'auto' }); * }; + * ``` * * ### Custom key names * @@ -237,7 +238,7 @@ class DynamoDBProvider extends BaseProvider { /** * It initializes the DynamoDBProvider class. - * * + * * @param {DynamoDBProviderOptions} config - The configuration object. */ public constructor(config: DynamoDBProviderOptions) { @@ -337,7 +338,7 @@ class DynamoDBProvider extends BaseProvider { * Retrieve an item from Amazon DynamoDB. * * @param {string} name - Key of the item to retrieve (i.e. the partition key) - * @param {DynamoDBGetOptionsInterface} options - SDK options to propagate to `GetItemCommand` API call + * @param {DynamoDBGetOptionsInterface} options - Options to customize the retrieval */ protected async _get( name: string, @@ -361,7 +362,7 @@ class DynamoDBProvider extends BaseProvider { * Retrieve multiple items from Amazon DynamoDB. * * @param {string} path - The path of the values to retrieve (i.e. the partition key) - * @param {DynamoDBGetMultipleOptionsInterface} options - Options to configure the provider + * @param {DynamoDBGetMultipleOptionsInterface} options - Options to customize the retrieval */ protected async _getMultiple( path: string, From cf25415c122a251c44c4ff72481d2ab3e372de5b Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Thu, 23 Feb 2023 19:58:28 +0100 Subject: [PATCH 13/17] docs: added SSMProvider api --- packages/parameters/src/ssm/SSMProvider.ts | 383 +++++++++++++++++- packages/parameters/src/ssm/getParameter.ts | 135 ++++++ packages/parameters/src/ssm/getParameters.ts | 140 ++++++- .../parameters/src/ssm/getParametersByName.ts | 161 +++++++- packages/parameters/src/types/SSMProvider.ts | 61 ++- 5 files changed, 869 insertions(+), 11 deletions(-) diff --git a/packages/parameters/src/ssm/SSMProvider.ts b/packages/parameters/src/ssm/SSMProvider.ts index dd45070162..822e94c1b5 100644 --- a/packages/parameters/src/ssm/SSMProvider.ts +++ b/packages/parameters/src/ssm/SSMProvider.ts @@ -24,11 +24,254 @@ import type { } from '../types/SSMProvider'; import type { PaginationConfiguration } from '@aws-sdk/types'; +/** + * ## Intro + * The Parameters utility provides a SSMProvider that allows to retrieve parameters from AWS Systems Manager. + * + * ## Getting started + * + * This utility supports AWS SDK v3 for JavaScript only. This allows the utility to be modular, and you to install only + * the SDK packages you need and keep your bundle size small. + * + * To use the provider, you must install the Parameters utility and the AWS SDK v3 for JavaScript for AppConfig: + * + * ```sh + * npm install @aws-lambda-powertools/parameters @aws-sdk/client-ssm + * ``` + * + * ## Basic usage + * + * Retrieve a parameter from SSM: + * + * @example + * ```typescript + * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; + * + * const parametersProvider = new SSMProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a parameter from SSM + * const parameter = await parametersProvider.get('/my-parameter'); + * }; + * ``` + * + * If you want to retrieve a parameter without customizing the provider, you can use the {@link getParameter} function instead. + * + * You can also retrieve parameters at once. If you want to get multiple parameters under the same path, you can use the `getMultiple` method. + * + * @example + * ```typescript + * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; + * + * const parametersProvider = new SSMProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve multiple parameters by path from SSM + * const parameters = await parametersProvider.getMultiple('/my-parameters-path'); + * }; + * + * If you don't need to customize the provider, you can also use the {@link getParameters} function instead. + * + * If instead you want to retrieve multiple parameters by name, you can use the `getParametersByName` method. + * + * @example + * ```typescript + * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; + * + * const parametersProvider = new SSMProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve multiple parameters by name from SSM + * const parameters = await parametersProvider.getParametersByName({ + * '/my-parameter-1': {}, // Use default options + * '/my-parameter-2': { transform: 'json' }, // Parse the value as JSON + * }); + * }; + * ``` + * + * If you don't need to customize the provider, you can also use the {@link getParametersByName} function instead. + * + * ## Advanced usage + * + * ### Caching + * + * By default, the provider will cache parameters retrieved in-memory for 5 seconds. + * You can adjust how long values should be kept in cache by using the `maxAge` parameter. + * + * @example + * ```typescript + * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; + * + * const parametersProvider = new SSMProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a parameter and cache it for 10 seconds + * const parameter = await parametersProvider.get('/my-parameter', { maxAge: 10 }); + * // Retrieve multiple parameters by path and cache them for 20 seconds + * const parameters = await parametersProvider.getMultiple('/my-parameters-path', { maxAge: 20 }); + * }; + * ``` + * + * When using the `getParametersByName` method, you can set a different `maxAge` for each parameter or set a default `maxAge` for all parameters. + * + * @example + * ```typescript + * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; + * + * const parametersProvider = new SSMProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve multiple parameters by name and cache them individually + * const parameters = await parametersProvider.getParametersByName({ + * '/my-parameter-1': { maxAge: 10 }, // Cache for 10 seconds + * '/my-parameter-2': { maxAge: 10 }, // Cache for 20 seconds + * }); + * // Retrieve multiple parameters by name and cache them all for 20 seconds + * const parameters = await parametersProvider.getParametersByName({ + * '/my-parameter-1': {}, + * '/my-parameter-2': {}, + * }, { maxAge: 20 }); + * }; + * ``` + * + * If instead you'd like to always ensure you fetch the latest parameter from the store regardless if already available in cache, use the `forceFetch` parameter. + * + * @example + * ```typescript + * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; + * + * const parametersProvider = new SSMProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a parameter and skip cache + * const parameter = await parametersProvider.get('/my-parameter', { forceFetch: true }); + * // Retrieve multiple parameters and skip cache + * const parameters = await parametersProvider.getMultiple('/my-parameters-path', { forceFetch: true }); + * }; + * ``` + * + * Likewise, you can use the `forceFetch` parameter with the `getParametersByName` method both for individual parameters and for all parameters. + * + * ### Decryption + * + * If you want to retrieve a parameter that is encrypted, you can use the `decrypt` parameter. This parameter is compatible with `get`, `getMultiple` and `getParametersByName`. + * + * @example + * ```typescript + * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; + * + * const parametersProvider = new SSMProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a parameter and decrypt it + * const parameter = await parametersProvider.get('/my-parameter', { decrypt: true }); + * // Retrieve multiple parameters and decrypt them + * const parameters = await parametersProvider.getMultiple('/my-parameters-path', { decrypt: true }); + * }; + * ``` + * + * ### Transformations + * + * For parameters stored as JSON you can use the transform argument for deserialization. This will return a JavaScript object instead of a string. + * + * @example + * ```typescript + * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; + * + * const parametersProvider = new SSMProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a parameter and parse it as JSON + * const parameter = await parametersProvider.get('/my-parameter', { transform: 'json' }); + * // Retrieve multiple parameters and parse them as JSON + * const parameters = await parametersProvider.getMultiple('/my-parameters-path', { transform: 'json' }); + * }; + * ``` + * + * For parameters that are instead stored as base64-encoded binary data, you can use the transform argument set to `binary` for decoding. This will return a decoded string. + * + * @example + * ```typescript + * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; + * + * const parametersProvider = new SSMProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a base64-encoded string and decode it + * const parameter = await parametersProvider.get('/my-parameter', { transform: 'binary' }); + * // Retrieve multiple base64-encoded strings and decode them + * const parameters = await parametersProvider.getMultiple('/my-parameters-path', { transform: 'binary' }); + * }; + * ``` + * + * Both type of transformations are compatible also with the `getParametersByName` method. + * + * ### Extra SDK options + * + * When retrieving parameters, you can pass extra options to the AWS SDK v3 for JavaScript client by using the `sdkOptions` parameter. + * + * @example + * ```typescript + * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; + * + * const parametersProvider = new SSMProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a parameter and pass extra options to the AWS SDK v3 for JavaScript client + * const parameter = await parametersProvider.get('/my-parameter', { + * sdkOptions: { + * WithDecryption: true, + * }, + * }); + * }; + * ``` + * + * The objects accept the same options as respectively the [AWS SDK v3 for JavaScript GetParameter command](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-ssm/classes/getparametercommand.html) and the [AWS SDK v3 for JavaScript GetParametersByPath command](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-ssm/classes/getparametersbypathcommand.html). + * + * ### Customize AWS SDK v3 for JavaScript client + * + * By default, the provider will create a new SSM client using the default configuration. + * + * You can customize the client by passing a custom configuration object to the provider. + * + * @example + * ```typescript + * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; + * + * const parametersProvider = new SSMProvider({ + * clientConfig: { region: 'eu-west-1' }, + * }); + * ``` + * + * This object accepts the same options as the [AWS SDK v3 for JavaScript SSM client constructor](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-ssm/classes/ssmclient.html#constructor). + * + * Otherwise, if you want to use a custom client altogether, you can pass it to the provider. + * + * @example + * ```typescript + * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; + * import { SSMClient } from '@aws-sdk/client-ssm'; + * + * const client = new SSMClient({ region: 'eu-west-1' }); + * const parametersProvider = new SSMProvider({ + * awsSdkV3Client: client, + * }); + * ``` + * + * This object must be an instance of the [AWS SDK v3 for JavaScript SSM client](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-ssm/classes/ssmclient.html). + * + * For more usage examples, see [our documentation](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/). + */ class SSMProvider extends BaseProvider { public client: SSMClient; protected errorsKey = '_errors'; protected maxGetParametersItems = 10; + /** + * It initializes the SSMProvider class. + * + * @param {SSMProviderOptions} config - The configuration object. + */ public constructor(config?: SSMProviderOptions) { super(); @@ -44,6 +287,34 @@ class SSMProvider extends BaseProvider { } } + /** + * Retrieve a value from AWS Systems Manager. + * + * @example + * ```typescript + * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; + * + * const parametersProvider = new SSMProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve a parameter from SSM + * const parameter = await parametersProvider.get('/my-parameter'); + * }; + * ``` + * + * You can customize the retrieval of the value by passing options to the function: + * * `maxAge` - The maximum age of the value in cache before fetching a new one (in seconds) (default: 5) + * * `forceFetch` - Whether to always fetch a new value from the store regardless if already available in cache + * * `transform` - Whether to transform the value before returning it. Supported values: `json`, `binary` + * * `sdkOptions` - Extra options to pass to the AWS SDK v3 for JavaScript client + * * `decrypt` - Whether to decrypt the value before returning it. + * + * For usage examples check {@link SSMProvider}. + * + * @param {string} name - The name of the value to retrieve (i.e. the partition key) + * @param {SSMGetOptionsInterface} options - Options to configure the provider + * @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/ + */ public async get( name: string, options?: SSMGetOptionsInterface | undefined @@ -51,6 +322,36 @@ class SSMProvider extends BaseProvider { return super.get(name, options) as Promise | undefined>; } + /** + * Retrieve multiple values from AWS Systems Manager. + * + * @example + * ```typescript + * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; + * + * const parametersProvider = new SSMProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve multiple parameters from SSM + * const parameters = await parametersProvider.getMultiple('/my-parameters-path'); + * }; + * ``` + * + * You can customize the retrieval of the values by passing options to the function: + * * `maxAge` - The maximum age of the value in cache before fetching a new one (in seconds) (default: 5) + * * `forceFetch` - Whether to always fetch a new value from the store regardless if already available in cache + * * `transform` - Whether to transform the value before returning it. Supported values: `json`, `binary` + * * `sdkOptions` - Extra options to pass to the AWS SDK v3 for JavaScript client + * * `throwOnTransformError` - Whether to throw an error if the transform fails (default: `true`) + * * `decrypt` - Whether to decrypt the value before returning it. + * * `recursive` - Whether to recursively retrieve all parameters under the given path (default: `false`) + * + * For usage examples check {@link SSMProvider}. + * + * @param {string} path - The path of the parameters to retrieve + * @param {SSMGetMultipleOptionsInterface} options - Options to configure the retrieval + * @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/ + */ public async getMultiple( path: string, options?: SSMGetMultipleOptionsInterface | undefined @@ -59,9 +360,31 @@ class SSMProvider extends BaseProvider { } /** - * Retrieve multiple parameter values by name from SSM or cache. + * Retrieve multiple parameters by name from AWS Systems Manager. + * + * @example + * ```typescript + * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; + * + * const parametersProvider = new SSMProvider(); + * + * export const handler = async (): Promise => { + * // Retrieve multiple parameters by name from SSM + * const parameters = await parametersProvider.getParametersByName({ + * '/my-parameter-1': {}, // Use default options + * '/my-parameter-2': { transform: 'json' }, // Parse the value as JSON + * }); + * }; + * ``` + * You can customize the retrieval of the values by passing options to **both the function and the parameter**: + * * `maxAge` - The maximum age of the value in cache before fetching a new one (in seconds) (default: 5) + * * `forceFetch` - Whether to always fetch a new value from the store regardless if already available in cache + * * `transform` - Whether to transform the value before returning it. Supported values: `json`, `binary` + * * `sdkOptions` - Extra options to pass to the AWS SDK v3 for JavaScript client + * * `throwOnTransformError` - Whether to throw an error if the transform fails (default: `true`) + * * `decrypt` - Whether to decrypt the value before returning it * - * `ThrowOnError` decides whether to throw an error if a parameter is not found: + * `throwOnError` decides whether to throw an error if a parameter is not found: * - A) Default fail-fast behavior: Throws a `GetParameterError` error upon any failure. * - B) Gracefully aggregate all parameters that failed under "_errors" key. * @@ -82,8 +405,9 @@ class SSMProvider extends BaseProvider { * └────────────────────┘ * ``` * - * @param {Record[]} parameters - List of parameter names, and any optional overrides - * + * @param {Record} parameters - Object containing parameter names and any optional overrides + * @param {SSMGetParametersByNameOptionsInterface} options - Options to configure the retrieval + * @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/ */ public async getParametersByName( parameters: Record, @@ -139,6 +463,12 @@ class SSMProvider extends BaseProvider { return response; } + /** + * Retrieve a parameter from AWS Systems Manager. + * + * @param {string} name - Name of the parameter to retrieve + * @param {SSMGetOptionsInterface} options - Options to customize the retrieval + */ protected async _get( name: string, options?: SSMGetOptionsInterface @@ -154,6 +484,12 @@ class SSMProvider extends BaseProvider { return result.Parameter?.Value; } + /** + * Retrieve multiple items from AWS Systems Manager. + * + * @param {string} path - The path of the parameters to retrieve + * @param {SSMGetMultipleOptionsInterface} options - Options to configure the provider + */ protected async _getMultiple( path: string, options?: SSMGetMultipleOptionsInterface @@ -196,6 +532,13 @@ class SSMProvider extends BaseProvider { return parameters; } + /** + * Retrieve multiple items by name from AWS Systems Manager. + * + * @param {Record} parameters - An object of parameter names and their options + * @param {throwOnError} throwOnError - Whether to throw an error if any of the parameters' retrieval throws an error or handle them gracefully + * @param {boolean} decrypt - Whether to decrypt the parameters or not + */ protected async _getParametersByName( parameters: Record, throwOnError: boolean, @@ -224,6 +567,10 @@ class SSMProvider extends BaseProvider { /** * Slice batch and fetch parameters using GetPrameters API by max permissible batch size + * + * @param {Record} parameters - An object of parameter names and their options + * @param {throwOnError} throwOnError - Whether to throw an error if any of the parameters' retrieval throws an error or handle them gracefully + * @param {boolean} decrypt - Whether to decrypt the parameters or not */ protected async getParametersBatchByName( parameters: Record, @@ -260,6 +607,8 @@ class SSMProvider extends BaseProvider { /** * Fetch each parameter from batch that hasn't expired from cache + * + * @param {Record} parameters - An object of parameter names and their options */ protected async getParametersByNameFromCache( parameters: Record @@ -284,6 +633,13 @@ class SSMProvider extends BaseProvider { }; } + /** + * Slice object into chunks of max permissible batch size and fetch parameters + * + * @param {Record} parameters - An object of parameter names and their options + * @param {boolean} throwOnError - Whether to throw an error if any of the parameters' retrieval throws an error or handle them gracefully + * @param {boolean} decrypt - Whether to decrypt the parameters or not + */ protected async getParametersByNameInChunks( parameters: Record, throwOnError: boolean, @@ -324,6 +680,12 @@ class SSMProvider extends BaseProvider { }; } + /** + * Fetch parameters by name while also decrypting them + * + * @param {Record} parameters - An object of parameter names and their options + * @param {boolean} throwOnError - Whether to throw an error if any of the parameters' retrieval throws an error or handle them gracefully + */ protected async getParametersByNameWithDecryptOption( parameters: Record, throwOnError: boolean @@ -351,6 +713,9 @@ class SSMProvider extends BaseProvider { /** * Handle any invalid parameters returned by GetParameters API * GetParameters is non-atomic. Failures don't always reflect in exceptions so we need to collect. + * + * @param {GetParametersCommandOutput} result - The result of the GetParameters API call + * @param {boolean} throwOnError - Whether to throw an error if any of the parameters' retrieval throws an error or handle them gracefully */ protected static handleAnyInvalidGetParameterErrors( result: GetParametersCommandOutput, @@ -371,6 +736,9 @@ class SSMProvider extends BaseProvider { /** * Split parameters that can be fetched by GetParameters vs GetParameter. + * + * @param {Record} parameters - An object of parameter names and their options + * @param {SSMGetParametersByNameOptionsInterface} configs - The configs passed down */ protected static splitBatchAndDecryptParameters( parameters: Record, @@ -420,6 +788,13 @@ class SSMProvider extends BaseProvider { } } + /** + * Transform and cache the response from GetParameters API call + * + * @param {GetParametersCommandOutput} response - The response from the GetParameters API call + * @param {Record} parameters - An object of parameter names and their options + * @param {boolean} throwOnError - Whether to throw an error if any of the parameters' retrieval throws an error or handle them gracefully + */ protected transformAndCacheGetParametersResponse( response: GetParametersCommandOutput, parameters: Record, diff --git a/packages/parameters/src/ssm/getParameter.ts b/packages/parameters/src/ssm/getParameter.ts index fd4d8e8e0e..6631236942 100644 --- a/packages/parameters/src/ssm/getParameter.ts +++ b/packages/parameters/src/ssm/getParameter.ts @@ -1,6 +1,141 @@ import { SSMProvider, DEFAULT_PROVIDERS } from './SSMProvider'; import type { SSMGetOptionsInterface } from '../types/SSMProvider'; +/** + * ## Intro + * The Parameters utility provides an SSMProvider that allows to retrieve parameters from AWS Systems Manager. + * + * ## Getting started + * + * This utility supports AWS SDK v3 for JavaScript only. This allows the utility to be modular, and you to install only + * the SDK packages you need and keep your bundle size small. + * + * To use the provider, you must install the Parameters utility and the AWS SDK v3 for JavaScript for AppConfig: + * + * ```sh + * npm install @aws-lambda-powertools/parameters @aws-sdk/client-ssm + * ``` + * + * ## Basic usage + * + * @example + * ```typescript + * import { getParameter } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve a parameter + * const parameter = await getParameter('/my-parameter'); + * }; + * ``` + * + * ## Advanced usage + * + * ### Decryption + * + * If you have encrypted parameters, you can use the `decrypt` option to automatically decrypt them. + * + * @example + * ```typescript + * import { getParameter } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve a parameter and decrypt it + * const parameter = await getParameter('/my-parameter', { decrypt: true }); + * }; + * ``` + * + * ### Caching + * + * By default, the provider will cache parameters retrieved in-memory for 5 seconds. + * You can adjust how long values should be kept in cache by using the `maxAge` parameter. + * + * @example + * ```typescript + * import { getParameter } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve a parameter and cache it for 10 seconds + * const parameter = await getParameter('/my-parameter'); + * }; + * ``` + * + * If instead you'd like to always ensure you fetch the latest parameter from the store regardless if already available in cache, use the `forceFetch` parameter. + * + * @example + * ```typescript + * import { getParameter } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve a parameter and always fetch the latest value + * const parameter = await getParameter('/my-parameter', { forceFetch: true }); + * }; + * ``` + * + * ### Transformations + * + * For parameters stored as JSON you can use the transform argument for deserialization. This will return a JavaScript object instead of a string. + * + * @example + * ```typescript + * import { getParameter } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve a parameter and parse it as JSON + * const parameter = await getParameter('/my-parameter', { transform: 'json' }); + * }; + * ``` + * + * For parameters that are instead stored as base64-encoded binary data, you can use the transform argument set to `binary` for decoding. This will return a decoded string. + * + * @example + * ```typescript + * import { getParameter } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve a base64-encoded string and decode it + * const parameter = await getParameter('/my-parameter', { transform: 'binary' }); + * }; + * ``` + * + * ### Extra SDK options + * + * When retrieving a parameter, you can pass extra options to the AWS SDK v3 for JavaScript client by using the `sdkOptions` parameter. + * + * @example + * ```typescript + * import { getParameter } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve a parameter and pass extra options to the AWS SDK v3 for JavaScript client + * const parameter = await getParameter('/my-parameter', { + * sdkOptions: { + * WithDecryption: true, + * }, + * }); + * }; + * ``` + * + * This object accepts the same options as the [AWS SDK v3 for JavaScript SSM GetParameter command](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-ssm/interfaces/getparametercommandinput.html). + * + * ### Built-in provider class + * + * For greater flexibility such as configuring the underlying SDK client used by built-in providers, you can use the {@link SSMProvider} class. + * + * ### Options + * + * * You can customize the retrieval of the value by passing options to the function: + * * `maxAge` - The maximum age of the value in cache before fetching a new one (in seconds) (default: 5) + * * `forceFetch` - Whether to always fetch a new value from the store regardless if already available in cache + * * `transform` - Whether to transform the value before returning it. Supported values: `json`, `binary` + * * `sdkOptions` - Extra options to pass to the AWS SDK v3 for JavaScript client + * * `decrypt` - Whether to decrypt the value before returning it. + * + * For more usage examples, see [our documentation](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/). + * + * @param {string} name - The name of the parameter to retrieve + * @param {SSMGetOptionsInterface} options - Options to configure the provider + * @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/ + */ const getParameter = ( name: string, options?: SSMGetOptionsInterface diff --git a/packages/parameters/src/ssm/getParameters.ts b/packages/parameters/src/ssm/getParameters.ts index 0283bc0b5e..b12097dd10 100644 --- a/packages/parameters/src/ssm/getParameters.ts +++ b/packages/parameters/src/ssm/getParameters.ts @@ -1,7 +1,143 @@ import { SSMProvider, DEFAULT_PROVIDERS } from './SSMProvider'; import type { SSMGetMultipleOptionsInterface } from '../types/SSMProvider'; -const getParameters = ( +/** + * ## Intro + * The Parameters utility provides an SSMProvider that allows to retrieve parameters from AWS Systems Manager. + * + * ## Getting started + * + * This utility supports AWS SDK v3 for JavaScript only. This allows the utility to be modular, and you to install only + * the SDK packages you need and keep your bundle size small. + * + * To use the provider, you must install the Parameters utility and the AWS SDK v3 for JavaScript for AppConfig: + * + * ```sh + * npm install @aws-lambda-powertools/parameters @aws-sdk/client-ssm + * ``` + * + * ## Basic usage + * + * @example + * ```typescript + * import { getParameters } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve parameters by path + * const parameters = await getParameters('/my-parameters-path'); + * }; + * ``` + * + * ## Advanced usage + * + * ### Decryption + * + * If you have encrypted parameters, you can use the `decrypt` option to automatically decrypt them. + * + * @example + * ```typescript + * import { getParameters } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve parameters and decrypt them + * const parameters = await getParameters('/my-parameters-path', { decrypt: true }); + * }; + * ``` + * + * ### Caching + * + * By default, the provider will cache parameters retrieved in-memory for 5 seconds. + * You can adjust how long values should be kept in cache by using the `maxAge` parameter. + * + * @example + * ```typescript + * import { getParameters } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve parameters and cache them for 10 seconds + * const parameters = await getParameters('/my-parameters-path'); + * }; + * ``` + * + * If instead you'd like to always ensure you fetch the latest values from the store regardless if already available in cache, use the `forceFetch` parameter. + * + * @example + * ```typescript + * import { getParameters } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve parameters and always fetch the latest values + * const parameters = await getParameters('/my-parameters-path', { forceFetch: true }); + * }; + * ``` + * + * ### Transformations + * + * For parameters stored as JSON you can use the transform argument for deserialization. This will return a JavaScript objects instead of a strings. + * + * @example + * ```typescript + * import { getParameters } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve parameters and parse them as JSON + * const parameters = await getParameters('/my-parameters-path', { transform: 'json' }); + * }; + * ``` + * + * For parameters that are instead stored as base64-encoded binary data, you can use the transform argument set to `binary` for decoding. This will return decoded strings for each parameter. + * + * @example + * ```typescript + * import { getParameters } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve base64-encoded strings and decode them + * const parameters = await getParameters('/my-parameters-path', { transform: 'binary' }); + * }; + * ``` + * + * ### Extra SDK options + * + * When retrieving a parameter, you can pass extra options to the AWS SDK v3 for JavaScript client by using the `sdkOptions` parameter. + * + * @example + * ```typescript + * import { getParameters } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve parameters and pass extra options to the AWS SDK v3 for JavaScript client + * const parameters = await getParameters('/my-parameters-path', { + * sdkOptions: { + * WithDecryption: true, + * }, + * }); + * }; + * ``` + * + * This object accepts the same options as the [AWS SDK v3 for JavaScript SSM getParameterssByPath command](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-ssm/interfaces/getParameterssbypathcommandinput.html). + * + * ### Built-in provider class + * + * For greater flexibility such as configuring the underlying SDK client used by built-in providers, you can use the {@link SSMProvider} class. + * + * ### Options + * + * * You can customize the retrieval of the value by passing options to the function: + * * `maxAge` - The maximum age of the value in cache before fetching a new one (in seconds) (default: 5) + * * `forceFetch` - Whether to always fetch a new value from the store regardless if already available in cache + * * `transform` - Whether to transform the value before returning it. Supported values: `json`, `binary` + * * `sdkOptions` - Extra options to pass to the AWS SDK v3 for JavaScript client + * * `decrypt` - Whether to decrypt the value before returning it. + * * `recursive` - Whether to recursively retrieve all parameters within the path. + * + * For more usage examples, see [our documentation](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/). + * + * @param {string} path - The path of the parameters to retrieve + * @param {SSMGetMultipleOptionsInterface} options - Options to configure the provider + * @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/ + */ +const getParameterss = ( path: string, options?: SSMGetMultipleOptionsInterface ): Promise> => { @@ -13,5 +149,5 @@ const getParameters = ( }; export { - getParameters, + getParameterss, }; \ No newline at end of file diff --git a/packages/parameters/src/ssm/getParametersByName.ts b/packages/parameters/src/ssm/getParametersByName.ts index 18d50073b8..a8898223ca 100644 --- a/packages/parameters/src/ssm/getParametersByName.ts +++ b/packages/parameters/src/ssm/getParametersByName.ts @@ -3,7 +3,164 @@ import type { SSMGetParametersByNameOptionsInterface } from '../types/SSMProvider'; -const getParametersByName = ( +/** + * ## Intro + * The Parameters utility provides an SSMProvider that allows to retrieve parameters from AWS Systems Manager. + * + * ## Getting started + * + * This utility supports AWS SDK v3 for JavaScript only. This allows the utility to be modular, and you to install only + * the SDK packages you need and keep your bundle size small. + * + * To use the provider, you must install the Parameters utility and the AWS SDK v3 for JavaScript for AppConfig: + * + * ```sh + * npm install @aws-lambda-powertools/parameters @aws-sdk/client-ssm + * ``` + * + * ## Basic usage + * + * @example + * ```typescript + * import { getParametersByName } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve parameters and cache them for 10 seconds + * const parameters = await getParametersByName({ + * '/my-parameter-1': {}, // Use default options + * '/my-parameter-2': { maxAge: 10 }, // Cache for 10 seconds + * }); + * }; + * ``` + * + * ## Advanced usage + * + * ### Decryption + * + * If you have encrypted parameters, you can use the `decrypt` option to automatically decrypt them. + * + * @example + * ```typescript + * import { getParametersByName } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve parameters and decrypt them + * const parameters = await getParametersByName({ + * '/my-parameter-1': {}, // Use default options + * '/my-parameter-2': {}, // Use default options + * }, { decrypt: true }); + * }; + * ``` + * + * ### Caching + * + * By default, the provider will cache parameters retrieved in-memory for 5 seconds. + * You can adjust how long values should be kept in cache by using the `maxAge` parameter. + * + * @example + * ```typescript + * import { getParametersByName } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve parameters and cache them for 10 seconds + * const parameters = await getParametersByName({ + * '/my-parameter-1': {}, // Use default options + * '/my-parameter-2': {}, // Use default options + * }, { maxAge: 10 }); + * }; + * ``` + * + * Alternatively, if you need more granular control over caching each parameter, you can pass it in the options object. + * + * @example + * ```typescript + * import { getParametersByName } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve parameters and cache them individually + * const parameters = await getParametersByName({ + * '/my-parameter-1': { maxAge: 10 }, // Cache for 10 seconds + * '/my-parameter-2': { maxAge: 20 }, // Cache for 20 seconds + * }); + * }; + * ``` + * + * If instead you'd like to always ensure you fetch the latest values from the store regardless if already available in cache, use the `forceFetch` parameter. + * + * @example + * ```typescript + * import { getParametersByName } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve parameters and pass extra options to skip cache + * const parameters = await getParametersByName({ + * '/my-parameter-1': {}, // Use default options + * '/my-parameter-2': {}, // Use default options + * }, { forceFetch: true }); + * }; + * ``` + * + * ### Transformations + * + * For parameters stored as JSON you can use the transform argument for deserialization. This will return a JavaScript objects instead of a strings. + * For parameters that are instead stored as base64-encoded binary data, you can use the transform argument set to `binary` for decoding. This will return decoded strings for each parameter. + * + * @example + * ```typescript + * import { getParametersByName } from '@aws-lambda-powertools/parameters/ssm'; + * + * export const handler = async (): Promise => { + * // Retrieve parameters and pass extra options to transform them + * const parameters = await getParametersByName({ + * '/my-parameter-1': {}, // Use default options (no transformation) + * '/my-parameter-2': { transform: 'json' }, // Parse the value as JSON + * '/my-parameter-3': { transform: 'binary' }, // Parse the value as base64-encoded binary data + * }); + * }; + * ``` + * + * + * ### Built-in provider class + * + * For greater flexibility such as configuring the underlying SDK client used by built-in providers, you can use the {@link SSMProvider} class. + * + * ### Options + * + * * You can customize the retrieval of the value by passing options to **both the function and the parameter**: + * * `maxAge` - The maximum age of the value in cache before fetching a new one (in seconds) (default: 5) + * * `forceFetch` - Whether to always fetch a new value from the store regardless if already available in cache + * * `transform` - Whether to transform the value before returning it. Supported values: `json`, `binary` + * * `sdkOptions` - Extra options to pass to the AWS SDK v3 for JavaScript client + * * `decrypt` - Whether to decrypt the value before returning it + * + * `throwOnError` decides whether to throw an error if a parameter is not found: + * - A) Default fail-fast behavior: Throws a `GetParameterError` error upon any failure. + * - B) Gracefully aggregate all parameters that failed under "_errors" key. + * + * It transparently uses GetParameter and/or getParametersByName depending on decryption requirements. + * + * ```sh + * ┌────────────────────────┐ + * ┌───▶ Decrypt entire batch │─────┐ + * │ └────────────────────────┘ │ ┌────────────────────┐ + * │ ├─────▶ getParametersByName API │ + * ┌──────────────────┐ │ ┌────────────────────────┐ │ └────────────────────┘ + * │ Split batch │─── ┼──▶│ No decryption required │─────┘ + * └──────────────────┘ │ └────────────────────────┘ + * │ ┌────────────────────┐ + * │ ┌────────────────────────┐ │ GetParameter API │ + * └──▶│Decrypt some but not all│───────────▶────────────────────┤ + * └────────────────────────┘ │ getParametersByName API │ + * └────────────────────┘ + * ``` + * + * For more usage examples, see [our documentation](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/). + * + * @param {Record} parameters - The path of the parameters to retrieve + * @param {SSMGetParametersByNameOptionsInterface} options - Options to configure the provider + * @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/ + */ +const getParametersByNameByName = ( parameters: Record, options?: SSMGetParametersByNameOptionsInterface ): Promise & { _errors?: string[] }> => { @@ -15,5 +172,5 @@ const getParametersByName = ( }; export { - getParametersByName, + getParametersByNameByName, }; \ No newline at end of file diff --git a/packages/parameters/src/types/SSMProvider.ts b/packages/parameters/src/types/SSMProvider.ts index 9ce1f66e97..36d5f85cb3 100644 --- a/packages/parameters/src/types/SSMProvider.ts +++ b/packages/parameters/src/types/SSMProvider.ts @@ -10,31 +10,68 @@ import type { TransformOptions } from './BaseProvider'; +/** + * Interface for SSMProvider with clientConfig property. + * + * @interface + * @property {SSMClientConfig} [clientConfig] - Optional configuration to pass during client initialization, e.g. AWS region. + * @property {never} [awsSdkV3Client] - This property should never be passed. + */ interface SSMProviderOptionsWithClientConfig { clientConfig?: SSMClientConfig awsSdkV3Client?: never } +/** + * Interface for SSMProvider with awsSdkV3Client property. + * + * @interface + * @property {SSMClient} [awsSdkV3Client] - Optional AWS SDK v3 client to pass during SSMProvider class instantiation + * @property {never} [clientConfig] - This property should never be passed. + */ interface SSMProviderOptionsWithClientInstance { awsSdkV3Client?: SSMClient clientConfig?: never } +/** + * Options for the SSMProvider class constructor. + * + * @type SSMProviderOptions + * @property {SSMClientConfig} [clientConfig] - Optional configuration to pass during client initialization, e.g. AWS region. Mutually exclusive with awsSdkV3Client. + * @property {SSMClient} [awsSdkV3Client] - Optional AWS SDK v3 client to pass during DynamoDBProvider class instantiation. Mutually exclusive with clientConfig. + */ type SSMProviderOptions = SSMProviderOptionsWithClientConfig | SSMProviderOptionsWithClientInstance; /** - * Options for the SSMProvider get method. - * + * Options for the SSMProvider getMultiple method. + * * @interface SSMGetOptionsInterface * @extends {GetOptionsInterface} + * @property {number} maxAge - Maximum age of the value in the cache, in seconds. + * @property {boolean} forceFetch - Force fetch the value from the parameter store, ignoring the cache. + * @property {GetItemCommandInput} [sdkOptions] - Additional options to pass to the AWS SDK v3 client. + * @property {TransformOptions} transform - Transform to be applied, can be 'json' or 'binary'. * @property {boolean} decrypt - If true, the parameter will be decrypted. - * @property {Partial} sdkOptions - Options for the AWS SDK. */ interface SSMGetOptionsInterface extends GetOptionsInterface { decrypt?: boolean sdkOptions?: Partial } +/** + * Options for the SSMProvider getMultiple method. + * + * @interface SSMGetMultipleOptionsInterface + * @extends {GetMultipleOptionsInterface} + * @property {number} maxAge - Maximum age of the value in the cache, in seconds. + * @property {boolean} forceFetch - Force fetch the value from the parameter store, ignoring the cache. + * @property {GetItemCommandInput} [sdkOptions] - Additional options to pass to the AWS SDK v3 client. + * @property {TransformOptions} transform - Transform to be applied, can be 'json' or 'binary'. + * @property {boolean} decrypt - If true, the parameter will be decrypted. + * @property {boolean} recursive - If true, the parameter will be fetched recursively. + * @property {boolean} throwOnTransformError - If true, the method will throw an error if the transform fails. + */ interface SSMGetMultipleOptionsInterface extends GetMultipleOptionsInterface { sdkOptions?: Partial decrypt?: boolean @@ -42,6 +79,15 @@ interface SSMGetMultipleOptionsInterface extends GetMultipleOptionsInterface { throwOnTransformError?: boolean } +/** + * Options for the SSMProvider getParametersByName method. + * + * @interface SSMGetParametersByNameOptionsInterface + * @property {number} maxAge - Maximum age of the value in the cache, in seconds. + * @property {TransformOptions} transform - Transform to be applied, can be 'json' or 'binary'. + * @property {boolean} decrypt - If true, the parameter will be decrypted. + * @property {boolean} throwOnError - If true, the method will throw an error if one of the parameters cannot be fetched. Otherwise it will aggregate the errors under an _errors key in the response. + */ interface SSMGetParametersByNameOptionsInterface { maxAge?: number throwOnError?: boolean @@ -49,16 +95,25 @@ interface SSMGetParametersByNameOptionsInterface { transform?: TransformOptions } +/** + * Output type for the SSMProvider splitBatchAndDecryptParameters method. + */ type SSMSplitBatchAndDecryptParametersOutputType = { parametersToFetchInBatch: Record parametersToDecrypt: Record }; +/** + * Output type for the SSMProvider getParametersByName method. + */ interface SSMGetParametersByNameOutputInterface { response: Record errors: string[] } +/** + * Output type for the SSMProvider getParametersByNameFromCache method. + */ type SSMGetParametersByNameFromCacheOutputType = { cached: Record> toFetch: Record From 13a7bf85de8bbc8336d1294990d0219fb381483b Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Thu, 23 Feb 2023 20:04:50 +0100 Subject: [PATCH 14/17] chore: typo --- packages/parameters/src/ssm/getParametersByName.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/parameters/src/ssm/getParametersByName.ts b/packages/parameters/src/ssm/getParametersByName.ts index a8898223ca..5efd333f5f 100644 --- a/packages/parameters/src/ssm/getParametersByName.ts +++ b/packages/parameters/src/ssm/getParametersByName.ts @@ -160,7 +160,7 @@ import type { * @param {SSMGetParametersByNameOptionsInterface} options - Options to configure the provider * @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/ */ -const getParametersByNameByName = ( +const getParametersByName = ( parameters: Record, options?: SSMGetParametersByNameOptionsInterface ): Promise & { _errors?: string[] }> => { @@ -172,5 +172,5 @@ const getParametersByNameByName = ( }; export { - getParametersByNameByName, + getParametersByName, }; \ No newline at end of file From ab6d132c02a3ee0a44f5953445ae0d0f585c485a Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Thu, 23 Feb 2023 20:05:20 +0100 Subject: [PATCH 15/17] chore: typo --- packages/parameters/src/ssm/getParameters.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/parameters/src/ssm/getParameters.ts b/packages/parameters/src/ssm/getParameters.ts index b12097dd10..74cf9f80b7 100644 --- a/packages/parameters/src/ssm/getParameters.ts +++ b/packages/parameters/src/ssm/getParameters.ts @@ -137,7 +137,7 @@ import type { SSMGetMultipleOptionsInterface } from '../types/SSMProvider'; * @param {SSMGetMultipleOptionsInterface} options - Options to configure the provider * @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/ */ -const getParameterss = ( +const getParameters = ( path: string, options?: SSMGetMultipleOptionsInterface ): Promise> => { @@ -149,5 +149,5 @@ const getParameterss = ( }; export { - getParameterss, + getParameters, }; \ No newline at end of file From fc92d56da999572d2c27bd62a919319179522122 Mon Sep 17 00:00:00 2001 From: Alexander Melnyk Date: Thu, 16 Mar 2023 13:02:07 +0100 Subject: [PATCH 16/17] chore(docs): fix minor issues in api docs examples --- packages/parameters/src/ssm/SSMProvider.ts | 216 +++++++++---------- packages/parameters/src/ssm/getParameter.ts | 70 +++--- packages/parameters/src/ssm/getParameters.ts | 72 +++---- 3 files changed, 179 insertions(+), 179 deletions(-) diff --git a/packages/parameters/src/ssm/SSMProvider.ts b/packages/parameters/src/ssm/SSMProvider.ts index 822e94c1b5..28818a8aaa 100644 --- a/packages/parameters/src/ssm/SSMProvider.ts +++ b/packages/parameters/src/ssm/SSMProvider.ts @@ -27,14 +27,14 @@ import type { PaginationConfiguration } from '@aws-sdk/types'; /** * ## Intro * The Parameters utility provides a SSMProvider that allows to retrieve parameters from AWS Systems Manager. - * + * * ## Getting started - * + * * This utility supports AWS SDK v3 for JavaScript only. This allows the utility to be modular, and you to install only * the SDK packages you need and keep your bundle size small. - * + * * To use the provider, you must install the Parameters utility and the AWS SDK v3 for JavaScript for AppConfig: - * + * * ```sh * npm install @aws-lambda-powertools/parameters @aws-sdk/client-ssm * ``` @@ -42,13 +42,13 @@ import type { PaginationConfiguration } from '@aws-sdk/types'; * ## Basic usage * * Retrieve a parameter from SSM: - * + * * @example * ```typescript * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; - * + * * const parametersProvider = new SSMProvider(); - * + * * export const handler = async (): Promise => { * // Retrieve a parameter from SSM * const parameter = await parametersProvider.get('/my-parameter'); @@ -56,54 +56,54 @@ import type { PaginationConfiguration } from '@aws-sdk/types'; * ``` * * If you want to retrieve a parameter without customizing the provider, you can use the {@link getParameter} function instead. - * + * * You can also retrieve parameters at once. If you want to get multiple parameters under the same path, you can use the `getMultiple` method. - * + * * @example * ```typescript * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; - * + * * const parametersProvider = new SSMProvider(); - * + * * export const handler = async (): Promise => { * // Retrieve multiple parameters by path from SSM * const parameters = await parametersProvider.getMultiple('/my-parameters-path'); * }; - * + * * If you don't need to customize the provider, you can also use the {@link getParameters} function instead. - * + * * If instead you want to retrieve multiple parameters by name, you can use the `getParametersByName` method. - * + * * @example * ```typescript * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; - * + * * const parametersProvider = new SSMProvider(); - * + * * export const handler = async (): Promise => { * // Retrieve multiple parameters by name from SSM * const parameters = await parametersProvider.getParametersByName({ * '/my-parameter-1': {}, // Use default options - * '/my-parameter-2': { transform: 'json' }, // Parse the value as JSON + * '/my-parameter-2': { transform: 'json' }, // Parse the value as JSON * }); * }; * ``` - * + * * If you don't need to customize the provider, you can also use the {@link getParametersByName} function instead. - * + * * ## Advanced usage - * + * * ### Caching - * + * * By default, the provider will cache parameters retrieved in-memory for 5 seconds. * You can adjust how long values should be kept in cache by using the `maxAge` parameter. - * + * * @example * ```typescript * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; - * + * * const parametersProvider = new SSMProvider(); - * + * * export const handler = async (): Promise => { * // Retrieve a parameter and cache it for 10 seconds * const parameter = await parametersProvider.get('/my-parameter', { maxAge: 10 }); @@ -111,20 +111,20 @@ import type { PaginationConfiguration } from '@aws-sdk/types'; * const parameters = await parametersProvider.getMultiple('/my-parameters-path', { maxAge: 20 }); * }; * ``` - * + * * When using the `getParametersByName` method, you can set a different `maxAge` for each parameter or set a default `maxAge` for all parameters. - * + * * @example * ```typescript * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; - * + * * const parametersProvider = new SSMProvider(); - * + * * export const handler = async (): Promise => { * // Retrieve multiple parameters by name and cache them individually * const parameters = await parametersProvider.getParametersByName({ * '/my-parameter-1': { maxAge: 10 }, // Cache for 10 seconds - * '/my-parameter-2': { maxAge: 10 }, // Cache for 20 seconds + * '/my-parameter-2': { maxAge: 20 }, // Cache for 20 seconds * }); * // Retrieve multiple parameters by name and cache them all for 20 seconds * const parameters = await parametersProvider.getParametersByName({ @@ -133,15 +133,15 @@ import type { PaginationConfiguration } from '@aws-sdk/types'; * }, { maxAge: 20 }); * }; * ``` - * + * * If instead you'd like to always ensure you fetch the latest parameter from the store regardless if already available in cache, use the `forceFetch` parameter. - * + * * @example * ```typescript * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; - * + * * const parametersProvider = new SSMProvider(); - * + * * export const handler = async (): Promise => { * // Retrieve a parameter and skip cache * const parameter = await parametersProvider.get('/my-parameter', { forceFetch: true }); @@ -149,19 +149,19 @@ import type { PaginationConfiguration } from '@aws-sdk/types'; * const parameters = await parametersProvider.getMultiple('/my-parameters-path', { forceFetch: true }); * }; * ``` - * + * * Likewise, you can use the `forceFetch` parameter with the `getParametersByName` method both for individual parameters and for all parameters. - * + * * ### Decryption - * + * * If you want to retrieve a parameter that is encrypted, you can use the `decrypt` parameter. This parameter is compatible with `get`, `getMultiple` and `getParametersByName`. - * + * * @example * ```typescript * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; - * + * * const parametersProvider = new SSMProvider(); - * + * * export const handler = async (): Promise => { * // Retrieve a parameter and decrypt it * const parameter = await parametersProvider.get('/my-parameter', { decrypt: true }); @@ -169,17 +169,17 @@ import type { PaginationConfiguration } from '@aws-sdk/types'; * const parameters = await parametersProvider.getMultiple('/my-parameters-path', { decrypt: true }); * }; * ``` - * + * * ### Transformations - * + * * For parameters stored as JSON you can use the transform argument for deserialization. This will return a JavaScript object instead of a string. - * + * * @example * ```typescript * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; - * + * * const parametersProvider = new SSMProvider(); - * + * * export const handler = async (): Promise => { * // Retrieve a parameter and parse it as JSON * const parameter = await parametersProvider.get('/my-parameter', { transform: 'json' }); @@ -187,15 +187,15 @@ import type { PaginationConfiguration } from '@aws-sdk/types'; * const parameters = await parametersProvider.getMultiple('/my-parameters-path', { transform: 'json' }); * }; * ``` - * + * * For parameters that are instead stored as base64-encoded binary data, you can use the transform argument set to `binary` for decoding. This will return a decoded string. - * + * * @example * ```typescript * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; - * + * * const parametersProvider = new SSMProvider(); - * + * * export const handler = async (): Promise => { * // Retrieve a base64-encoded string and decode it * const parameter = await parametersProvider.get('/my-parameter', { transform: 'binary' }); @@ -203,19 +203,19 @@ import type { PaginationConfiguration } from '@aws-sdk/types'; * const parameters = await parametersProvider.getMultiple('/my-parameters-path', { transform: 'binary' }); * }; * ``` - * + * * Both type of transformations are compatible also with the `getParametersByName` method. - * + * * ### Extra SDK options - * + * * When retrieving parameters, you can pass extra options to the AWS SDK v3 for JavaScript client by using the `sdkOptions` parameter. - * + * * @example * ```typescript * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; - * + * * const parametersProvider = new SSMProvider(); - * + * * export const handler = async (): Promise => { * // Retrieve a parameter and pass extra options to the AWS SDK v3 for JavaScript client * const parameter = await parametersProvider.get('/my-parameter', { @@ -225,39 +225,39 @@ import type { PaginationConfiguration } from '@aws-sdk/types'; * }); * }; * ``` - * + * * The objects accept the same options as respectively the [AWS SDK v3 for JavaScript GetParameter command](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-ssm/classes/getparametercommand.html) and the [AWS SDK v3 for JavaScript GetParametersByPath command](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-ssm/classes/getparametersbypathcommand.html). - * + * * ### Customize AWS SDK v3 for JavaScript client - * + * * By default, the provider will create a new SSM client using the default configuration. - * + * * You can customize the client by passing a custom configuration object to the provider. - * + * * @example * ```typescript * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; - * + * * const parametersProvider = new SSMProvider({ * clientConfig: { region: 'eu-west-1' }, * }); * ``` - * + * * This object accepts the same options as the [AWS SDK v3 for JavaScript SSM client constructor](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-ssm/classes/ssmclient.html#constructor). - * + * * Otherwise, if you want to use a custom client altogether, you can pass it to the provider. - * + * * @example * ```typescript * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; * import { SSMClient } from '@aws-sdk/client-ssm'; - * + * * const client = new SSMClient({ region: 'eu-west-1' }); * const parametersProvider = new SSMProvider({ * awsSdkV3Client: client, * }); * ``` - * + * * This object must be an instance of the [AWS SDK v3 for JavaScript SSM client](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-ssm/classes/ssmclient.html). * * For more usage examples, see [our documentation](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/). @@ -289,28 +289,28 @@ class SSMProvider extends BaseProvider { /** * Retrieve a value from AWS Systems Manager. - * + * * @example * ```typescript * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; - * + * * const parametersProvider = new SSMProvider(); - * + * * export const handler = async (): Promise => { * // Retrieve a parameter from SSM * const parameter = await parametersProvider.get('/my-parameter'); * }; * ``` - * + * * You can customize the retrieval of the value by passing options to the function: * * `maxAge` - The maximum age of the value in cache before fetching a new one (in seconds) (default: 5) * * `forceFetch` - Whether to always fetch a new value from the store regardless if already available in cache * * `transform` - Whether to transform the value before returning it. Supported values: `json`, `binary` * * `sdkOptions` - Extra options to pass to the AWS SDK v3 for JavaScript client * * `decrypt` - Whether to decrypt the value before returning it. - * + * * For usage examples check {@link SSMProvider}. - * + * * @param {string} name - The name of the value to retrieve (i.e. the partition key) * @param {SSMGetOptionsInterface} options - Options to configure the provider * @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/ @@ -324,19 +324,19 @@ class SSMProvider extends BaseProvider { /** * Retrieve multiple values from AWS Systems Manager. - * + * * @example * ```typescript * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; - * + * * const parametersProvider = new SSMProvider(); - * + * * export const handler = async (): Promise => { * // Retrieve multiple parameters from SSM * const parameters = await parametersProvider.getMultiple('/my-parameters-path'); * }; * ``` - * + * * You can customize the retrieval of the values by passing options to the function: * * `maxAge` - The maximum age of the value in cache before fetching a new one (in seconds) (default: 5) * * `forceFetch` - Whether to always fetch a new value from the store regardless if already available in cache @@ -345,9 +345,9 @@ class SSMProvider extends BaseProvider { * * `throwOnTransformError` - Whether to throw an error if the transform fails (default: `true`) * * `decrypt` - Whether to decrypt the value before returning it. * * `recursive` - Whether to recursively retrieve all parameters under the given path (default: `false`) - * + * * For usage examples check {@link SSMProvider}. - * + * * @param {string} path - The path of the parameters to retrieve * @param {SSMGetMultipleOptionsInterface} options - Options to configure the retrieval * @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/ @@ -361,18 +361,18 @@ class SSMProvider extends BaseProvider { /** * Retrieve multiple parameters by name from AWS Systems Manager. - * + * * @example * ```typescript * import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm'; - * + * * const parametersProvider = new SSMProvider(); - * + * * export const handler = async (): Promise => { * // Retrieve multiple parameters by name from SSM * const parameters = await parametersProvider.getParametersByName({ * '/my-parameter-1': {}, // Use default options - * '/my-parameter-2': { transform: 'json' }, // Parse the value as JSON + * '/my-parameter-2': { transform: 'json' }, // Parse the value as JSON * }); * }; * ``` @@ -383,13 +383,13 @@ class SSMProvider extends BaseProvider { * * `sdkOptions` - Extra options to pass to the AWS SDK v3 for JavaScript client * * `throwOnTransformError` - Whether to throw an error if the transform fails (default: `true`) * * `decrypt` - Whether to decrypt the value before returning it - * + * * `throwOnError` decides whether to throw an error if a parameter is not found: * - A) Default fail-fast behavior: Throws a `GetParameterError` error upon any failure. * - B) Gracefully aggregate all parameters that failed under "_errors" key. - * + * * It transparently uses GetParameter and/or GetParameters depending on decryption requirements. - * + * * ```sh * ┌────────────────────────┐ * ┌───▶ Decrypt entire batch │─────┐ @@ -404,7 +404,7 @@ class SSMProvider extends BaseProvider { * └────────────────────────┘ │ GetParameters API │ * └────────────────────┘ * ``` - * + * * @param {Record} parameters - Object containing parameter names and any optional overrides * @param {SSMGetParametersByNameOptionsInterface} options - Options to configure the retrieval * @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/ @@ -441,7 +441,7 @@ class SSMProvider extends BaseProvider { response: batchResponse, errors: batchErrors } = await this.getParametersBatchByName(parametersToFetchInBatch, configs.throwOnError, false); - + response = { ...decryptResponse, ...batchResponse }; // Fail-fast disabled, let's aggregate errors under "_errors" key so they can handle gracefully if (!configs.throwOnError) { @@ -452,7 +452,7 @@ class SSMProvider extends BaseProvider { response: batchResponse, errors: batchErrors } = await this.getParametersBatchByName(parametersToDecrypt, configs.throwOnError, true); - + response = batchResponse; // Fail-fast disabled, let's aggregate errors under "_errors" key so they can handle gracefully if (!configs.throwOnError) { @@ -486,7 +486,7 @@ class SSMProvider extends BaseProvider { /** * Retrieve multiple items from AWS Systems Manager. - * + * * @param {string} path - The path of the parameters to retrieve * @param {SSMGetMultipleOptionsInterface} options - Options to configure the provider */ @@ -507,7 +507,7 @@ class SSMProvider extends BaseProvider { options.recursive : sdkOptions.Recursive; paginationOptions.pageSize = sdkOptions.MaxResults !== undefined ? sdkOptions.MaxResults : undefined; - + const parameters: Record = {}; for await (const page of paginateGetParametersByPath(paginationOptions, sdkOptions)) { for (const parameter of page.Parameters || []) { @@ -515,9 +515,9 @@ class SSMProvider extends BaseProvider { * Standardize the parameter name * * The parameter name returned by SSM will contain the full path. - * However, for readability, we should return only the part after the path. - **/ - + * However, for readability, we should return only the part after the path. + **/ + // If the parameter is present in the response, then it has a Name // eslint-disable-next-line @typescript-eslint/no-non-null-assertion let name = parameter.Name!; @@ -534,7 +534,7 @@ class SSMProvider extends BaseProvider { /** * Retrieve multiple items by name from AWS Systems Manager. - * + * * @param {Record} parameters - An object of parameter names and their options * @param {throwOnError} throwOnError - Whether to throw an error if any of the parameters' retrieval throws an error or handle them gracefully * @param {boolean} decrypt - Whether to decrypt the parameters or not @@ -550,7 +550,7 @@ class SSMProvider extends BaseProvider { if (decrypt) { sdkOptions.WithDecryption = true; } - + const result = await this.client.send(new GetParametersCommand(sdkOptions)); const errors = SSMProvider.handleAnyInvalidGetParameterErrors(result, throwOnError); const response = this.transformAndCacheGetParametersResponse( @@ -567,7 +567,7 @@ class SSMProvider extends BaseProvider { /** * Slice batch and fetch parameters using GetPrameters API by max permissible batch size - * + * * @param {Record} parameters - An object of parameter names and their options * @param {throwOnError} throwOnError - Whether to throw an error if any of the parameters' retrieval throws an error or handle them gracefully * @param {boolean} decrypt - Whether to decrypt the parameters or not @@ -607,7 +607,7 @@ class SSMProvider extends BaseProvider { /** * Fetch each parameter from batch that hasn't expired from cache - * + * * @param {Record} parameters - An object of parameter names and their options */ protected async getParametersByNameFromCache( @@ -635,7 +635,7 @@ class SSMProvider extends BaseProvider { /** * Slice object into chunks of max permissible batch size and fetch parameters - * + * * @param {Record} parameters - An object of parameter names and their options * @param {boolean} throwOnError - Whether to throw an error if any of the parameters' retrieval throws an error or handle them gracefully * @param {boolean} decrypt - Whether to decrypt the parameters or not @@ -647,7 +647,7 @@ class SSMProvider extends BaseProvider { ): Promise { let response: Record = {}; let errors: string[] = []; - + // Slice object into chunks of max permissible batch size const chunks = Object.entries(parameters).reduce(( acc, @@ -669,7 +669,7 @@ class SSMProvider extends BaseProvider { response: chunkResponse, errors: chunkErrors } = await this._getParametersByName(chunk, throwOnError, decrypt); - + response = { ...response, ...chunkResponse }; errors = [ ...errors, ...chunkErrors ]; } @@ -682,7 +682,7 @@ class SSMProvider extends BaseProvider { /** * Fetch parameters by name while also decrypting them - * + * * @param {Record} parameters - An object of parameter names and their options * @param {boolean} throwOnError - Whether to throw an error if any of the parameters' retrieval throws an error or handle them gracefully */ @@ -713,7 +713,7 @@ class SSMProvider extends BaseProvider { /** * Handle any invalid parameters returned by GetParameters API * GetParameters is non-atomic. Failures don't always reflect in exceptions so we need to collect. - * + * * @param {GetParametersCommandOutput} result - The result of the GetParameters API call * @param {boolean} throwOnError - Whether to throw an error if any of the parameters' retrieval throws an error or handle them gracefully */ @@ -736,7 +736,7 @@ class SSMProvider extends BaseProvider { /** * Split parameters that can be fetched by GetParameters vs GetParameter. - * + * * @param {Record} parameters - An object of parameter names and their options * @param {SSMGetParametersByNameOptionsInterface} configs - The configs passed down */ @@ -755,7 +755,7 @@ class SSMProvider extends BaseProvider { overrides.decrypt : configs.decrypt; overrides.maxAge = overrides.maxAge !== undefined ? overrides.maxAge : configs.maxAge; - + if (overrides.decrypt) { parametersToDecrypt[parameterName] = overrides; } else { @@ -771,10 +771,10 @@ class SSMProvider extends BaseProvider { /** * Throw a GetParameterError if fail-fast is disabled and `_errors` key is in parameters list. - * - * @param {Record} parameters - * @param {string} reservedParameter - * @param {boolean} throwOnError + * + * @param {Record} parameters + * @param {string} reservedParameter + * @param {boolean} throwOnError */ protected static throwIfErrorsKeyIsPresent( parameters: Record, @@ -790,7 +790,7 @@ class SSMProvider extends BaseProvider { /** * Transform and cache the response from GetParameters API call - * + * * @param {GetParametersCommandOutput} response - The response from the GetParameters API call * @param {Record} parameters - An object of parameter names and their options * @param {boolean} throwOnError - Whether to throw an error if any of the parameters' retrieval throws an error or handle them gracefully diff --git a/packages/parameters/src/ssm/getParameter.ts b/packages/parameters/src/ssm/getParameter.ts index 6631236942..12b09e0c08 100644 --- a/packages/parameters/src/ssm/getParameter.ts +++ b/packages/parameters/src/ssm/getParameter.ts @@ -4,14 +4,14 @@ import type { SSMGetOptionsInterface } from '../types/SSMProvider'; /** * ## Intro * The Parameters utility provides an SSMProvider that allows to retrieve parameters from AWS Systems Manager. - * + * * ## Getting started - * + * * This utility supports AWS SDK v3 for JavaScript only. This allows the utility to be modular, and you to install only * the SDK packages you need and keep your bundle size small. - * + * * To use the provider, you must install the Parameters utility and the AWS SDK v3 for JavaScript for AppConfig: - * + * * ```sh * npm install @aws-lambda-powertools/parameters @aws-sdk/client-ssm * ``` @@ -21,90 +21,90 @@ import type { SSMGetOptionsInterface } from '../types/SSMProvider'; * @example * ```typescript * import { getParameter } from '@aws-lambda-powertools/parameters/ssm'; - * + * * export const handler = async (): Promise => { * // Retrieve a parameter * const parameter = await getParameter('/my-parameter'); * }; * ``` - * + * * ## Advanced usage - * + * * ### Decryption - * + * * If you have encrypted parameters, you can use the `decrypt` option to automatically decrypt them. - * + * * @example * ```typescript * import { getParameter } from '@aws-lambda-powertools/parameters/ssm'; - * + * * export const handler = async (): Promise => { * // Retrieve a parameter and decrypt it * const parameter = await getParameter('/my-parameter', { decrypt: true }); * }; * ``` - * + * * ### Caching - * + * * By default, the provider will cache parameters retrieved in-memory for 5 seconds. * You can adjust how long values should be kept in cache by using the `maxAge` parameter. - * + * * @example * ```typescript * import { getParameter } from '@aws-lambda-powertools/parameters/ssm'; - * + * * export const handler = async (): Promise => { * // Retrieve a parameter and cache it for 10 seconds - * const parameter = await getParameter('/my-parameter'); + * const parameter = await getParameter('/my-parameter', { maxAge: 10 }); * }; * ``` - * + * * If instead you'd like to always ensure you fetch the latest parameter from the store regardless if already available in cache, use the `forceFetch` parameter. - * + * * @example * ```typescript * import { getParameter } from '@aws-lambda-powertools/parameters/ssm'; - * + * * export const handler = async (): Promise => { * // Retrieve a parameter and always fetch the latest value * const parameter = await getParameter('/my-parameter', { forceFetch: true }); * }; * ``` - * + * * ### Transformations - * + * * For parameters stored as JSON you can use the transform argument for deserialization. This will return a JavaScript object instead of a string. - * + * * @example * ```typescript * import { getParameter } from '@aws-lambda-powertools/parameters/ssm'; - * + * * export const handler = async (): Promise => { * // Retrieve a parameter and parse it as JSON * const parameter = await getParameter('/my-parameter', { transform: 'json' }); * }; * ``` - * + * * For parameters that are instead stored as base64-encoded binary data, you can use the transform argument set to `binary` for decoding. This will return a decoded string. - * + * * @example * ```typescript * import { getParameter } from '@aws-lambda-powertools/parameters/ssm'; - * + * * export const handler = async (): Promise => { * // Retrieve a base64-encoded string and decode it * const parameter = await getParameter('/my-parameter', { transform: 'binary' }); * }; * ``` - * + * * ### Extra SDK options - * + * * When retrieving a parameter, you can pass extra options to the AWS SDK v3 for JavaScript client by using the `sdkOptions` parameter. - * + * * @example * ```typescript * import { getParameter } from '@aws-lambda-powertools/parameters/ssm'; - * + * * export const handler = async (): Promise => { * // Retrieve a parameter and pass extra options to the AWS SDK v3 for JavaScript client * const parameter = await getParameter('/my-parameter', { @@ -114,24 +114,24 @@ import type { SSMGetOptionsInterface } from '../types/SSMProvider'; * }); * }; * ``` - * + * * This object accepts the same options as the [AWS SDK v3 for JavaScript SSM GetParameter command](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-ssm/interfaces/getparametercommandinput.html). - * + * * ### Built-in provider class * * For greater flexibility such as configuring the underlying SDK client used by built-in providers, you can use the {@link SSMProvider} class. - * + * * ### Options - * + * * * You can customize the retrieval of the value by passing options to the function: * * `maxAge` - The maximum age of the value in cache before fetching a new one (in seconds) (default: 5) * * `forceFetch` - Whether to always fetch a new value from the store regardless if already available in cache * * `transform` - Whether to transform the value before returning it. Supported values: `json`, `binary` * * `sdkOptions` - Extra options to pass to the AWS SDK v3 for JavaScript client * * `decrypt` - Whether to decrypt the value before returning it. - * + * * For more usage examples, see [our documentation](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/). - * + * * @param {string} name - The name of the parameter to retrieve * @param {SSMGetOptionsInterface} options - Options to configure the provider * @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/ diff --git a/packages/parameters/src/ssm/getParameters.ts b/packages/parameters/src/ssm/getParameters.ts index 74cf9f80b7..e93daf1ea8 100644 --- a/packages/parameters/src/ssm/getParameters.ts +++ b/packages/parameters/src/ssm/getParameters.ts @@ -4,14 +4,14 @@ import type { SSMGetMultipleOptionsInterface } from '../types/SSMProvider'; /** * ## Intro * The Parameters utility provides an SSMProvider that allows to retrieve parameters from AWS Systems Manager. - * + * * ## Getting started - * + * * This utility supports AWS SDK v3 for JavaScript only. This allows the utility to be modular, and you to install only * the SDK packages you need and keep your bundle size small. - * + * * To use the provider, you must install the Parameters utility and the AWS SDK v3 for JavaScript for AppConfig: - * + * * ```sh * npm install @aws-lambda-powertools/parameters @aws-sdk/client-ssm * ``` @@ -21,90 +21,90 @@ import type { SSMGetMultipleOptionsInterface } from '../types/SSMProvider'; * @example * ```typescript * import { getParameters } from '@aws-lambda-powertools/parameters/ssm'; - * + * * export const handler = async (): Promise => { * // Retrieve parameters by path * const parameters = await getParameters('/my-parameters-path'); * }; * ``` - * + * * ## Advanced usage - * + * * ### Decryption - * + * * If you have encrypted parameters, you can use the `decrypt` option to automatically decrypt them. - * + * * @example * ```typescript * import { getParameters } from '@aws-lambda-powertools/parameters/ssm'; - * + * * export const handler = async (): Promise => { * // Retrieve parameters and decrypt them * const parameters = await getParameters('/my-parameters-path', { decrypt: true }); * }; * ``` - * + * * ### Caching - * + * * By default, the provider will cache parameters retrieved in-memory for 5 seconds. * You can adjust how long values should be kept in cache by using the `maxAge` parameter. - * + * * @example * ```typescript * import { getParameters } from '@aws-lambda-powertools/parameters/ssm'; - * + * * export const handler = async (): Promise => { * // Retrieve parameters and cache them for 10 seconds - * const parameters = await getParameters('/my-parameters-path'); + * const parameters = await getParameters('/my-parameters-path', { maxAge: 10 }); * }; * ``` - * + * * If instead you'd like to always ensure you fetch the latest values from the store regardless if already available in cache, use the `forceFetch` parameter. - * + * * @example * ```typescript * import { getParameters } from '@aws-lambda-powertools/parameters/ssm'; - * + * * export const handler = async (): Promise => { * // Retrieve parameters and always fetch the latest values * const parameters = await getParameters('/my-parameters-path', { forceFetch: true }); * }; * ``` - * + * * ### Transformations - * + * * For parameters stored as JSON you can use the transform argument for deserialization. This will return a JavaScript objects instead of a strings. - * + * * @example * ```typescript * import { getParameters } from '@aws-lambda-powertools/parameters/ssm'; - * + * * export const handler = async (): Promise => { * // Retrieve parameters and parse them as JSON * const parameters = await getParameters('/my-parameters-path', { transform: 'json' }); * }; * ``` - * + * * For parameters that are instead stored as base64-encoded binary data, you can use the transform argument set to `binary` for decoding. This will return decoded strings for each parameter. - * + * * @example * ```typescript * import { getParameters } from '@aws-lambda-powertools/parameters/ssm'; - * + * * export const handler = async (): Promise => { * // Retrieve base64-encoded strings and decode them * const parameters = await getParameters('/my-parameters-path', { transform: 'binary' }); * }; * ``` - * + * * ### Extra SDK options - * + * * When retrieving a parameter, you can pass extra options to the AWS SDK v3 for JavaScript client by using the `sdkOptions` parameter. - * + * * @example * ```typescript * import { getParameters } from '@aws-lambda-powertools/parameters/ssm'; - * + * * export const handler = async (): Promise => { * // Retrieve parameters and pass extra options to the AWS SDK v3 for JavaScript client * const parameters = await getParameters('/my-parameters-path', { @@ -114,15 +114,15 @@ import type { SSMGetMultipleOptionsInterface } from '../types/SSMProvider'; * }); * }; * ``` - * - * This object accepts the same options as the [AWS SDK v3 for JavaScript SSM getParameterssByPath command](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-ssm/interfaces/getParameterssbypathcommandinput.html). - * + * + * This object accepts the same options as the [AWS SDK v3 for JavaScript SSM getParametersByPath command](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-ssm/interfaces/getParameterssbypathcommandinput.html). + * * ### Built-in provider class * * For greater flexibility such as configuring the underlying SDK client used by built-in providers, you can use the {@link SSMProvider} class. - * + * * ### Options - * + * * * You can customize the retrieval of the value by passing options to the function: * * `maxAge` - The maximum age of the value in cache before fetching a new one (in seconds) (default: 5) * * `forceFetch` - Whether to always fetch a new value from the store regardless if already available in cache @@ -130,9 +130,9 @@ import type { SSMGetMultipleOptionsInterface } from '../types/SSMProvider'; * * `sdkOptions` - Extra options to pass to the AWS SDK v3 for JavaScript client * * `decrypt` - Whether to decrypt the value before returning it. * * `recursive` - Whether to recursively retrieve all parameters within the path. - * + * * For more usage examples, see [our documentation](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/). - * + * * @param {string} path - The path of the parameters to retrieve * @param {SSMGetMultipleOptionsInterface} options - Options to configure the provider * @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/ From 63f3d6d4357768147dcf363d78b0707d14c858fc Mon Sep 17 00:00:00 2001 From: Alexander Melnyk Date: Thu, 16 Mar 2023 13:36:56 +0100 Subject: [PATCH 17/17] chore(docs): add note for maxAge start caching after the first api call --- packages/parameters/src/types/BaseProvider.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/parameters/src/types/BaseProvider.ts b/packages/parameters/src/types/BaseProvider.ts index 63c72e8734..c0e5a08c3d 100644 --- a/packages/parameters/src/types/BaseProvider.ts +++ b/packages/parameters/src/types/BaseProvider.ts @@ -5,8 +5,8 @@ type TransformOptions = 'auto' | 'binary' | 'json'; /** * Options for the `get` method. - * - * @property {number} maxAge - Maximum age of the value in the cache, in seconds. + * + * @property {number} maxAge - Maximum age of the value in the cache, in seconds. Will be applied after the first API call. * @property {boolean} forceFetch - Force fetch the value from the parameter store, ignoring the cache. * @property {unknown} sdkOptions - Options to pass to the underlying SDK. * @property {TransformOptions} transform - Transform to be applied, can be 'json', 'binary', or 'auto'. @@ -32,8 +32,8 @@ interface GetOptionsInterface { /** * Options for the `getMultiple` method. - * - * @property {number} maxAge - Maximum age of the value in the cache, in seconds. + * + * @property {number} maxAge - Maximum age of the value in the cache, in seconds. Will be applied after the first API call. * @property {boolean} forceFetch - Force fetch the value from the parameter store, ignoring the cache. * @property {unknown} sdkOptions - Options to pass to the underlying SDK. * @property {TransformOptions} transform - Transform to be applied, can be 'json', 'binary', or 'auto'.