From 9e70e4af1a78ddec0b222939a6162380d1e05422 Mon Sep 17 00:00:00 2001 From: thomasabishop Date: Mon, 12 Jun 2023 07:26:32 +0100 Subject: [PATCH] aws: more notes on SAM --- .../AWS/SAM/Local_AWS_development_with_SAM.md | 90 ++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) diff --git a/DevOps/AWS/SAM/Local_AWS_development_with_SAM.md b/DevOps/AWS/SAM/Local_AWS_development_with_SAM.md index 18697a8..4bfc77d 100644 --- a/DevOps/AWS/SAM/Local_AWS_development_with_SAM.md +++ b/DevOps/AWS/SAM/Local_AWS_development_with_SAM.md @@ -27,6 +27,94 @@ We then run: sam local start-api ``` -You should see the following: +If you have an API Gateway endpoint that you want to call over the local server. You will be able to call it after executing the above. + +This will be indicated by: ![](/_img/local-sam-docker.png) + +If we want to invoke the function directly we use: + +```sh + sam local invoke [FunctionName] +``` + +## Using environment variables + +If you have an API key or database credentials, you are going to typically want to use different values dependent on environment. + +Even if the values are the same accross environments, it's a good idea to not call a secret when working locally since this request is billable. + +In the example below I show how to set up environment variables for an API key locally and in production. + +## Create secret + +Go to AWS SecretsManager and add the API key as a secret. This will be sourced in production. + +## Create local ENV file + +> These must be in JSON to work with SAM: + +### Local env + +```json +// local-env.json +{ + "FunctionName": { + "API_KEY": "xxx-yyy-xxx", + "NODE_ENV": "development" + } +} +``` + +We save these to the root of the given function's directory not at the global repo level. + +> Be sure to add this to `.gitignore` so that it does not become public + +### Update `template.yaml` + +Every environment variable you intend to use, must exist in the `template.yaml`, otherwise it will not be sourced at runtime: + +```yaml +... +Resources: + Properties: + Environment: + Variables: + SECRET_ARN: "arn:aws:secretsmanager:eu-west-2:885135949562:secret:wakatime-api-key-X9oF3v", + NODE_ENV: production + API_KEY: +... +``` + +> We go ahead and populate the values for production. But we leave the variable we use in development blank, since we don't want it committed and we will source it at the SAM invocation. It still needs to exist though. + +### Pass in the environment variable at invocation: + +```sh +sam local start-api --env-vars /home/thomas/repos/lambdas/wakatime-api/get-coding-stats/local-env.json +``` + +In production, the variables required will be automatically sourced from the `template.yaml` + +### Create handler within the Lambda itself + +You are obviously going to need to distinguish between the different deployments when the Lambda executes. Here is an example helper function: + +```ts +import * as AWS from "aws-sdk"; + +const secretsManager = new AWS.SecretsManager(); + +async function getApiKey(): Promise { + if (process.env.NODE_ENV === "production") { + const response = await secretsManager + .getSecretValue({ SecretId: process.env.SECRET_ARN as string }) + .promise(); + const secretValues = JSON.parse(response.SecretString as string); + return secretValues.API_KEY; + } else { + return process.env.API_KEY as string; + } +} +```