Skip to content

Commit

Permalink
feat(parameters): stronger types for SSM getParameter (#1387)
Browse files Browse the repository at this point in the history
* feat: stronger types for SSM getParameter

* feat: improved types for getParameters

* feat: added explicit type override

* chore: rebase

* chore: added type annotation to tests to use as canary
  • Loading branch information
dreamorosi authored Apr 5, 2023
1 parent 7a9d499 commit 9d53942
Show file tree
Hide file tree
Showing 8 changed files with 272 additions and 51 deletions.
44 changes: 24 additions & 20 deletions packages/parameters/src/ssm/SSMProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@ import type {
} from '@aws-sdk/client-ssm';
import type {
SSMProviderOptions,
SSMGetMultipleOptionsInterface,
SSMGetOptionsInterface,
SSMGetOptions,
SSMGetOutput,
SSMGetMultipleOptions,
SSMGetMultipleOptionsUnion,
SSMGetMultipleOutput,
SSMGetParametersByNameOutput,
SSMGetParametersByNameOutputInterface,
SSMGetParametersByNameOptionsInterface,
SSMSplitBatchAndDecryptParametersOutputType,
Expand Down Expand Up @@ -312,14 +316,14 @@ class SSMProvider extends BaseProvider {
* 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
* @param {SSMGetOptions} options - Options to configure the provider
* @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/
*/
public async get(
public async get<T = undefined, O extends SSMGetOptions | undefined = SSMGetOptions>(
name: string,
options?: SSMGetOptionsInterface | undefined
): Promise<string | Record<string, unknown> | undefined> {
return super.get(name, options) as Promise<string | Record<string, unknown> | undefined>;
options?: O & SSMGetOptions
): Promise<SSMGetOutput<T, O> | undefined> {
return super.get(name, options) as Promise<SSMGetOutput<T, O> | undefined>;
}

/**
Expand Down Expand Up @@ -349,14 +353,14 @@ class SSMProvider extends BaseProvider {
* For usage examples check {@link SSMProvider}.
*
* @param {string} path - The path of the parameters to retrieve
* @param {SSMGetMultipleOptionsInterface} options - Options to configure the retrieval
* @param {SSMGetMultipleOptions} options - Options to configure the retrieval
* @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/
*/
public async getMultiple(
public async getMultiple<T = undefined, O extends SSMGetMultipleOptionsUnion | undefined = undefined>(
path: string,
options?: SSMGetMultipleOptionsInterface | undefined
): Promise<undefined | Record<string, unknown>> {
return super.getMultiple(path, options);
options?: O & SSMGetMultipleOptions
): Promise<SSMGetMultipleOutput<T, O> | undefined> {
return super.getMultiple(path, options) as Promise<SSMGetMultipleOutput<T, O> | undefined>;
}

/**
Expand Down Expand Up @@ -409,10 +413,10 @@ class SSMProvider extends BaseProvider {
* @param {SSMGetParametersByNameOptionsInterface} options - Options to configure the retrieval
* @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/
*/
public async getParametersByName(
public async getParametersByName<T = undefined>(
parameters: Record<string, SSMGetParametersByNameOptionsInterface>,
options?: SSMGetParametersByNameOptionsInterface
): Promise<Record<string, unknown>> {
): Promise<SSMGetParametersByNameOutput<T>> {
const configs = { ...{
decrypt: this.resolveDecryptionConfigValue({}) || false,
maxAge: DEFAULT_MAX_AGE_SECS,
Expand Down Expand Up @@ -460,18 +464,18 @@ class SSMProvider extends BaseProvider {
}
}

return response;
return response as unknown as Promise<SSMGetParametersByNameOutput<T>>;
}

/**
* Retrieve a parameter from AWS Systems Manager.
*
* @param {string} name - Name of the parameter to retrieve
* @param {SSMGetOptionsInterface} options - Options to customize the retrieval
* @param {SSMGetOptions} options - Options to customize the retrieval
*/
protected async _get(
name: string,
options?: SSMGetOptionsInterface
options?: SSMGetOptions
): Promise<string | undefined> {
const sdkOptions: GetParameterCommandInput = {
...(options?.sdkOptions || {}),
Expand All @@ -487,11 +491,11 @@ 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
* @param {SSMGetMultipleOptions} options - Options to configure the provider
*/
protected async _getMultiple(
path: string,
options?: SSMGetMultipleOptionsInterface
options?: SSMGetMultipleOptions
): Promise<Record<string, string | undefined>> {
const sdkOptions: GetParametersByPathCommandInput = {
...(options?.sdkOptions || {}),
Expand Down Expand Up @@ -733,7 +737,7 @@ class SSMProvider extends BaseProvider {
}

protected resolveDecryptionConfigValue(
options: SSMGetOptionsInterface | SSMGetMultipleOptionsInterface = {},
options: SSMGetOptions | SSMGetMultipleOptions = {},
sdkOptions?: GetParameterCommandInput | GetParametersByPathCommandInput
): boolean | undefined {
if (options?.decrypt !== undefined) return options.decrypt;
Expand Down
17 changes: 11 additions & 6 deletions packages/parameters/src/ssm/getParameter.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { SSMProvider, DEFAULT_PROVIDERS } from './SSMProvider';
import type { SSMGetOptionsInterface } from '../types/SSMProvider';
import type {
SSMGetOptions,
SSMGetOutput,
} from '../types/SSMProvider';

/**
* ## Intro
Expand Down Expand Up @@ -133,18 +136,20 @@ import type { SSMGetOptionsInterface } from '../types/SSMProvider';
* 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
* @param {SSMGetOptions} options - Options to configure the provider
* @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/
*/
const getParameter = (
const getParameter = <T = undefined, O extends SSMGetOptions | undefined = SSMGetOptions>(
name: string,
options?: SSMGetOptionsInterface
): Promise<undefined | string | Record<string, unknown>> => {
options?: O & SSMGetOptions
): Promise<SSMGetOutput<T, O> | undefined> => {
if (!DEFAULT_PROVIDERS.hasOwnProperty('ssm')) {
DEFAULT_PROVIDERS.ssm = new SSMProvider();
}

return (DEFAULT_PROVIDERS.ssm as SSMProvider).get(name, options);
return (
DEFAULT_PROVIDERS.ssm as SSMProvider
).get(name, options) as Promise<SSMGetOutput<T, O> | undefined>;
};

export {
Expand Down
18 changes: 12 additions & 6 deletions packages/parameters/src/ssm/getParameters.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { SSMProvider, DEFAULT_PROVIDERS } from './SSMProvider';
import type { SSMGetMultipleOptionsInterface } from '../types/SSMProvider';
import type {
SSMGetMultipleOptions,
SSMGetMultipleOptionsUnion,
SSMGetMultipleOutput,
} from '../types/SSMProvider';

/**
* ## Intro
Expand Down Expand Up @@ -134,18 +138,20 @@ import type { SSMGetMultipleOptionsInterface } from '../types/SSMProvider';
* 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
* @param {SSMGetMultipleOptions} options - Options to configure the provider
* @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/
*/
const getParameters = (
const getParameters = <T = undefined, O extends SSMGetMultipleOptionsUnion | undefined = SSMGetMultipleOptionsUnion>(
path: string,
options?: SSMGetMultipleOptionsInterface
): Promise<undefined | Record<string, unknown>> => {
options?: O & SSMGetMultipleOptions
): Promise<SSMGetMultipleOutput<T, O> | undefined> => {
if (!DEFAULT_PROVIDERS.hasOwnProperty('ssm')) {
DEFAULT_PROVIDERS.ssm = new SSMProvider();
}

return (DEFAULT_PROVIDERS.ssm as SSMProvider).getMultiple(path, options);
return (
DEFAULT_PROVIDERS.ssm as SSMProvider
).getMultiple(path, options) as Promise<SSMGetMultipleOutput<T, O> | undefined>;
};

export {
Expand Down
11 changes: 7 additions & 4 deletions packages/parameters/src/ssm/getParametersByName.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { SSMProvider, DEFAULT_PROVIDERS } from './SSMProvider';
import type {
SSMGetParametersByNameOptionsInterface
SSMGetParametersByNameOptionsInterface,
SSMGetParametersByNameOutput,
} from '../types/SSMProvider';

/**
Expand Down Expand Up @@ -160,15 +161,17 @@ import type {
* @param {SSMGetParametersByNameOptionsInterface} options - Options to configure the provider
* @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/utilities/parameters/
*/
const getParametersByName = (
const getParametersByName = <T = undefined>(
parameters: Record<string, SSMGetParametersByNameOptionsInterface>,
options?: SSMGetParametersByNameOptionsInterface
): Promise<Record<string, unknown> & { _errors?: string[] }> => {
): Promise<SSMGetParametersByNameOutput<T>> => {
if (!DEFAULT_PROVIDERS.hasOwnProperty('ssm')) {
DEFAULT_PROVIDERS.ssm = new SSMProvider();
}

return (DEFAULT_PROVIDERS.ssm as SSMProvider).getParametersByName(parameters, options);
return (
DEFAULT_PROVIDERS.ssm as SSMProvider
).getParametersByName(parameters, options) as Promise<SSMGetParametersByNameOutput<T>>;
};

export {
Expand Down
8 changes: 6 additions & 2 deletions packages/parameters/src/types/BaseProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ interface GetOptionsInterface {
*/
sdkOptions?: unknown
/**
* Transform to be applied, can be 'json', 'binary', or 'auto'.
* Transform to be applied, can be `json` or `binary`.
*/
transform?: TransformOptions
transform?: Omit<TransformOptions, 'auto'>
}

/**
Expand All @@ -40,6 +40,10 @@ interface GetOptionsInterface {
* @property {boolean} throwOnTransformError - Whether to throw an error if a value cannot be transformed.
*/
interface GetMultipleOptionsInterface extends GetOptionsInterface {
/**
* Transform to be applied, can be `json`, `binary`, or `auto`.
*/
transform?: TransformOptions
/**
* Whether to throw an error if a value cannot be transformed.
*/
Expand Down
101 changes: 94 additions & 7 deletions packages/parameters/src/types/SSMProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,46 @@ type SSMProviderOptions = SSMProviderOptionsWithClientConfig | SSMProviderOption
* @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 {GetItemCommandInput} [sdkOptions] - Additional options to pass to the AWS SDK v3 client. Supports all options from `GetParameterCommandInput`.
* @property {TransformOptions} transform - Transform to be applied, can be 'json' or 'binary'.
* @property {boolean} decrypt - If true, the parameter will be decrypted.
* @property {boolean} decrypt - If true, the parameter will be decrypted. Defaults to `false`.
*/
interface SSMGetOptionsInterface extends GetOptionsInterface {
interface SSMGetOptions extends GetOptionsInterface {
/**
* If true, the parameter will be decrypted. Defaults to `false`.
*/
decrypt?: boolean
/**
* Additional options to pass to the AWS SDK v3 client. Supports all options from `GetParameterCommandInput`.
*/
sdkOptions?: Partial<GetParameterCommandInput>

transform?: Exclude<TransformOptions, 'auto'>
}

interface SSMGetOptionsTransformJson extends SSMGetOptions {
transform: 'json'
}

interface SSMGetOptionsTransformBinary extends SSMGetOptions {
transform: 'binary'
}

interface SSMGetOptionsTransformNone extends SSMGetOptions {
transform?: never
}

/**
* Generic output type for the SSMProvider get method.
*/
type SSMGetOutput<T = undefined, O = undefined> =
undefined extends T ?
undefined extends O ? string :
O extends SSMGetOptionsTransformNone | SSMGetOptionsTransformBinary ? string :
O extends SSMGetOptionsTransformJson ? Record<string, unknown> :
never
: T;

/**
* Options for the SSMProvider getMultiple method.
*
Expand All @@ -72,13 +103,60 @@ interface SSMGetOptionsInterface extends GetOptionsInterface {
* @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 {
interface SSMGetMultipleOptions extends GetMultipleOptionsInterface {
/**
* Additional options to pass to the AWS SDK v3 client. Supports all options from `GetParametersByPathCommandInput`.
*/
sdkOptions?: Partial<GetParametersByPathCommandInput>
/**
* If true, the parameters will be decrypted. Defaults to `false`.
*/
decrypt?: boolean
/**
* If true, the parameters will be fetched recursively. Defaults to `false`.
*/
recursive?: boolean
/**
* If true, the method will throw an error if the transform fails.
*/
throwOnTransformError?: boolean
}

interface SSMGetMultipleOptionsTransformJson extends SSMGetMultipleOptions {
transform: 'json'
}

interface SSMGetMultipleOptionsTransformBinary extends SSMGetMultipleOptions {
transform: 'binary'
}

interface SSMGetMultipleOptionsTransformAuto extends SSMGetMultipleOptions {
transform: 'auto'
}

interface SSMGetMultipleOptionsTransformNone extends SSMGetMultipleOptions {
transform?: never
}

type SSMGetMultipleOptionsUnion =
SSMGetMultipleOptionsTransformJson |
SSMGetMultipleOptionsTransformBinary |
SSMGetMultipleOptionsTransformAuto |
SSMGetMultipleOptionsTransformNone |
undefined;

/**
* Generic output type for the SSMProvider getMultiple method.
*/
type SSMGetMultipleOutput<T = undefined, O = undefined> =
undefined extends T ?
undefined extends O ? Record<string, string> :
O extends SSMGetMultipleOptionsTransformNone | SSMGetMultipleOptionsTransformBinary ? Record<string, string> :
O extends SSMGetMultipleOptionsTransformAuto ? Record<string, unknown> :
O extends SSMGetMultipleOptionsTransformJson ? Record<string, Record<string, unknown>> :
never
: Record<string, T>;

/**
* Options for the SSMProvider getParametersByName method.
*
Expand All @@ -92,7 +170,7 @@ interface SSMGetParametersByNameOptionsInterface {
maxAge?: number
throwOnError?: boolean
decrypt?: boolean
transform?: TransformOptions
transform?: Exclude<TransformOptions, 'auto'>
}

/**
Expand All @@ -119,12 +197,21 @@ type SSMGetParametersByNameFromCacheOutputType = {
toFetch: Record<string, SSMGetParametersByNameOptionsInterface>
};

type SSMGetParametersByNameOutput<T = undefined> =
undefined extends T ?
Record<string, unknown> & { _errors?: string[] } :
Record<string, T> & { _errors?: string[] };

export type {
SSMProviderOptions,
SSMGetOptionsInterface,
SSMGetMultipleOptionsInterface,
SSMGetOptions,
SSMGetOutput,
SSMGetMultipleOptions,
SSMGetMultipleOptionsUnion,
SSMGetMultipleOutput,
SSMGetParametersByNameOptionsInterface,
SSMSplitBatchAndDecryptParametersOutputType,
SSMGetParametersByNameOutputInterface,
SSMGetParametersByNameFromCacheOutputType,
SSMGetParametersByNameOutput,
};
Loading

0 comments on commit 9d53942

Please sign in to comment.