Introducing Lambda Powertools Parameters Utility: Simplifying Retrieval of Parameters from AWS Services

Today, lambda powertools has released version 1.7.0. Although it is a **beta developer preview**, it is already very close to the GA version. This version includes a feature that I have been waiting for a long time, so I can't wait to use it and introduce it to you. This feature is called Parameters utility. This new utility allows you to retrieve one or more parameter values from a range of AWS services, while also helping you reduce the amount of custom code needed to handle caching, transformations, and error handling.

The Parameters utility provides high-level functions to retrieve one or multiple parameter values from [AWS Systems Manager Parameter Store](https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html), [AWS Secrets Manager](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html), [AWS AppConfig](https://docs.aws.amazon.com/appconfig/latest/userguide/what-is-appconfig.html), [Amazon DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Introduction.html), or your own parameter store.

#### Key features

-   Retrieve one or multiple parameters from the underlying provider
-   Cache parameter values for a given amount of time (defaults to 5 seconds)
-   Transform parameter values from JSON or base64 encoded strings
-   Bring Your Own Parameter Store Provider

#### Getting started

To start testing the utility, install it from npm using the `@aws-lambda-powertools/parameters@1.7.0-beta` alias.

In addition, you will need to add the AWS SDK client for the parameter store you are planning to use. The Parameters utility supports [AWS SDK v3 for JavaScript](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/#aws-sdk-for-javascript-v3) only which allows the utility to be modular, and you to install only the SDK packages you need and keep your bundle size small:

-   SSM Parameters Store -> `@aws-sdk/client-ssm`
-   Secrets Manager -> `@aws-sdk/client-secrets-manager`
-   AppConfig -> `@aws-sdk/client-appconfigdata`
-   DynamoDB -> `@aws-sdk/client-dynamodb @aws-sdk/util-dynamodb`

Next, assign appropriate [AWS Identity and Access Management (IAM)](https://aws.amazon.com/iam/) permissions to the [Lambda function execution role](https://docs.aws.amazon.com/lambda/latest/dg/lambda-intro-execution-role.html) of your Lambda function that allow retrieving parameters from the parameter store. You can see which permissions are needed for each action and store in the [IAM Permissions section](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/#iam-permissions) of the utility's docs.

:::note info
In the section below we will use Secrets Manager as store to showcase different features of the Parameters utility. The same features are available for all other providers, as well as some others unique to each store. If you are interested in another store, [skip to the utility docs](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters).
:::
#### Retrieving a single secret

To retrieve an individual parameter, the Parameters utility provides the `getSecret` function:
```typescript
import { getSecret } from '@aws-lambda-powertools/parameters/secrets';  
  
export const handler = async (): Promise<void> => {  
  // Retrieve a single secret  
  const secret = await getSecret('my-secret');  
  console.log(secret);  
}
```

#### Adjusting cache TTL

By default, **the retrieved value will be cached in-memory for 5 seconds**. This cached value is used for subsequent invocations of the Lambda function until it expires. If you want to keep the value around longer, the Parameters utility allows you to adjust the time-to-live (TTL) via the `maxAge` argument:
```typescript
import { getSecret } from '@aws-lambda-powertools/parameters/secrets';  
  
export const handler = async (): Promise<void> => {  
  // Retrieve a single secret with a 60 seconds cache TTL
  const secret = await getSecret('my-secret', { maxAge: 60 });  
  console.log(secret);  
}
```

If instead you want to make sure that the latest value is always retrieved and cache is skipped, you can use the `forceFetch` option:
```typescript
import { getSecret } from '@aws-lambda-powertools/parameters/secrets';  
  
export const handler = async (): Promise<void> => {  
  // Retrieve a single secret skipping cache
  const secret = await getSecret('my-secret', { forceFetch: true });  
  console.log(secret);  
}
```

#### Decoding secrets stored in JSON or base64 format

If some of your secrets are stored in base64 or JSON, you can deserialize them via the Parameters utility’s `transform` argument:
```typescript
import { SecretsProvider } from '@aws-lambda-powertools/parameters/secrets';  
  
const secretsProvider = new SecretsProvider();  
  
export const handler = async (): Promise<void> => {  
  // Retrieve a secret and deserialize it as JSON  
  const json = await secretsProvider.get('my-secret-json', { transform: 'json' });  
  console.log(json);  
  
  // Transform a base64 encoded string  
  const binary = await secretsProvider.getMultiple('my-secret-binary', { transform: 'binary' });  
  console.log(binary);  
}
```

#### Customizing the AWS SDK

In some cases, you might want to use your own custom AWS SDK to retrieve values. This is useful in those instances in which you want to configure specific parameters or if you want to apply tracing. To do so, you can use the provider class directly:
```typescript
import { Tracer } from "@aws-lambda-powertools/tracer";  
import { SecretsProvider } from "@aws-lambda-powertools/parameters/secrets";  
import { SecretsManagerClient } from "@aws-sdk/client-secrets-manager";  
  
// initialize the tracer  
const tracer = new Tracer();  
// construct your client and instrument it to emit tracing data  
const secretsManagerClient = tracer.captureAWSv3Client(new SecretsManagerClient({}));  
// pass the client to the SecretProvider  
const secretProvider = new SecretsProvider({ awsSdkV3Client: secretsManagerClient });  
  
export const handler = async (): Promise<void> => {  
  // this operation will now appear in your X-Ray traces and service map  
  const secret = await secretProvider.get('my-secret');  
  console.log(secret);  
}
```
To learn more about all the features available for each provider, check the [Parameters docs](https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters).

#### Other provider
The examples above are all secrets, and you can use the same approach to access configurations stored in AppConfig, SSM, or DynamoDB.
```typescript
import { AppConfigProvider } from "@aws-lambda-powertools/parameters/appconfig";  
import { SSMProvider } from "@aws-lambda-powertools/parameters/ssm";  
import { DynamoDBProvider } from "@aws-lambda-powertools/parameters/dynamodb";
```

#### SSM Provider
For example, using SSM, you can retrieve multiple parameters at once and apply specific transformations or TTLs.
```typescript
import { getParametersByName } from '@aws-lambda-powertools/parameters/ssm';  
import type { SSMGetParametersByNameOptionsInterface } from "@aws-lambda-powertools/parameters/types";  
  
const props: Record<string, SSMGetParametersByNameOptionsInterface> = {  
  '/develop/service/commons/telemetry/config': { maxAge: 300, transform: 'json' },  
  '/no_cache_param': { maxAge: 0 },  
  '/develop/service/payment/api/capture/url': {}, // When empty or undefined, it uses default values  
  '/this/param/does/not/exist': {}, // <- Example of non-existent parameter 
};  
  
  
export const handler = async (): Promise<void> => {  
  // This returns an object with the parameter name as key  
  const {  
    _errors: errors,  
    ...parameters  
  } = await getParametersByName(props, { maxAge: 60 });  
  
  // Handle gracefully, since `/this/param/does/not/exist` will only be available in `_errors`  
  if (errors && errors.length) {  
    console.error(`Unable to retrieve parameters: ${errors.join(',')}`);  
  }  
  
  for (const [key, value] of Object.entries(parameters)) {  
    console.log(`${key}: ${value}`);  
  }  
};
```