aws-powertools / powertools-lambda-typescript

Powertools is a developer toolkit to implement Serverless best practices and increase developer velocity.
https://docs.powertools.aws.dev/lambda/typescript/latest/
MIT No Attribution
1.56k stars 137 forks source link

Feature request: Helper function for validating required environment variables #3159

Open garysassano opened 1 week ago

garysassano commented 1 week ago

Use case

It would be helpful to have a helper function to validate that required environment variables are present and not empty. This is a common use case when developing Lambda functions, and currently requires developers to write repetitive boilerplate code. This will improve error handling and make code more robust and maintainable.

Solution/User Experience

Create a helper function getRequiredEnvVar that:

  1. Takes the name of an environment variable as a parameter
  2. Checks if the variable exists and is not empty
  3. Returns the value if it exists
  4. Throws a descriptive error if the variable is missing or empty

Example Usage

import { getRequiredEnvVar } from '@aws-lambda-powertools/commons';

// Simple usage
const dbName = getRequiredEnvVar("DB_NAME");

// With type safety
const port = getRequiredEnvVar<number>("PORT", { parser: Number });

// Multiple variables for database configuration
const credentials = {
    username: getRequiredEnvVar("DB_USER"),
    password: getRequiredEnvVar("DB_PASS"),
    host: getRequiredEnvVar("DB_HOST"),
    port: getRequiredEnvVar<number>("DB_PORT", { parser: Number })
};

// Using with custom error message
const apiKey = getRequiredEnvVar("API_KEY", {
    errorMessage: "API_KEY is required for external service integration"
});

Benefits

Implementation Notes

function getRequiredEnvVar<T = string>( name: string, options?: GetEnvVarOptions ): T;


- Should throw a custom error type (e.g., `MissingEnvironmentVariableError`) for better error handling
- Should trim whitespace from values before validation
- Empty strings should be considered invalid by default
- Consider adding validation for common types:
  - Numbers (integers, floats)
  - Booleans (true/false, yes/no, 1/0)
  - JSON strings that need parsing
- Error messages should be clear and actionable, including:
  - The name of the missing/invalid variable
  - The expected format (if a parser was provided)
  - Any custom error message provided in options

### Alternative solutions

_No response_

### Acknowledgment

- [x] This feature request meets [Powertools for AWS Lambda (TypeScript) Tenets](https://docs.powertools.aws.dev/lambda/typescript/latest/#tenets)
- [x] Should this be considered in other Powertools for AWS Lambda languages? i.e. [Python](https://github.com/aws-powertools/powertools-lambda-python/), [Java](https://github.com/aws-powertools/powertools-lambda-java/), and [.NET](https://github.com/aws-powertools/powertools-lambda-dotnet/)

### Future readers

Please react with 👍 and your use case to help us understand customer demand.
am29d commented 1 week ago

Hey @garysassano , thanks for raising the issue. This is a common use case where you'd spend few lines of code to fetch and validate the environment variables that we could simplify and provide better error handling, especially for higher number of variables (10+).

The requirements and the solution remind me of https://github.com/ran-isenberg/aws-lambda-env-modeler from @ran-isenberg. Instead of calling getRequiredEnvVar multiple times, I see a better solution in having an environment object defined as a model. We could use zod parser to validate the model and also get a full error report for all environment variables.

const envSchema = z.object({
  DB_NAME: z.string(),
  DB_PORT: z.number(),
})

type MyEnvs = z.infer<typeof envSchema>;

const myEnvs: Myenvs = validateEnvs(envSchema)

const handler = async (event: unknown, context: Context) => {
  // myEnvs is available, valid and typed here
}

The main benefit we could provide is 1/ fetch a list of variables from process.env, 2/ validate against pre-defined schema 3/ output full report on all variables.

I'd like to hear more feedback from the community and customers how they approach this problem and if it's worth implementing.