UNPKG

@aws-lambda-powertools/parameters

Version:
365 lines (364 loc) 14.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DynamoDBProvider = void 0; const client_dynamodb_1 = require("@aws-sdk/client-dynamodb"); const util_dynamodb_1 = require("@aws-sdk/util-dynamodb"); const BaseProvider_js_1 = require("../base/BaseProvider.js"); /** * ## 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 (`@aws-sdk/client-dynamodb` and `@aws-sdk/util-dynamodb`). This allows the utility to be modular, and you to install only * the SDK packages you need and keep your bundle size small. * * ## 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<void> => { * // 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<void> => { * // 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<void> => { * // 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<void> => { * // 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 values stored as JSON 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<void> => { * // 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<void> => { * // 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<void> => { * // 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<void> => { * // 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://docs.powertools.aws.dev/lambda/typescript/latest/utilities/parameters/). */ class DynamoDBProvider extends BaseProvider_js_1.BaseProvider { keyAttr = 'id'; sortAttr = 'sk'; tableName; valueAttr = 'value'; /** * It initializes the DynamoDBProvider class. * * @param {DynamoDBProviderOptions} config - The configuration object. */ constructor(config) { super({ awsSdkV3ClientPrototype: client_dynamodb_1.DynamoDBClient, ...config, }); const { tableName, keyAttr, sortAttr, valueAttr } = config; this.tableName = tableName; if (keyAttr) this.keyAttr = keyAttr; if (sortAttr) this.sortAttr = sortAttr; if (valueAttr) this.valueAttr = 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<void> => { * // 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://docs.powertools.aws.dev/lambda/typescript/latest/utilities/parameters/ */ async get(name, options) { return super.get(name, options); } /** * 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<void> => { * // 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 {DynamoDBGetMultipleOptions} options - Options to configure the provider * @see https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/parameters/ */ async getMultiple(path, options) { 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 {DynamoDBGetOptions} options - Options to customize the retrieval */ async _get(name, options) { const sdkOptions = { ...(options?.sdkOptions || {}), TableName: this.tableName, Key: (0, util_dynamodb_1.marshall)({ [this.keyAttr]: name }), ProjectionExpression: '#value', ExpressionAttributeNames: { '#value': this.valueAttr, }, }; const result = await this.client.send(new client_dynamodb_1.GetItemCommand(sdkOptions)); return result.Item ? (0, util_dynamodb_1.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 {DynamoDBGetMultipleOptions} options - Options to customize the retrieval */ async _getMultiple(path, options) { const sdkOptions = { ...(options?.sdkOptions || {}), TableName: this.tableName, KeyConditionExpression: '#key = :key', ExpressionAttributeValues: (0, util_dynamodb_1.marshall)({ ':key': path }), ExpressionAttributeNames: { '#key': this.keyAttr, '#sk': this.sortAttr, '#value': this.valueAttr, }, ProjectionExpression: '#sk, #value', }; const paginationOptions = { client: this.client, pageSize: options?.sdkOptions?.Limit, }; const parameters = {}; for await (const page of (0, client_dynamodb_1.paginateQuery)(paginationOptions, sdkOptions)) { for (const item of page.Items || []) { const unmarshalledItem = (0, util_dynamodb_1.unmarshall)(item); parameters[unmarshalledItem[this.sortAttr]] = unmarshalledItem[this.valueAttr]; } } return parameters; } } exports.DynamoDBProvider = DynamoDBProvider;