Bjorn Theart
05/18/2022, 2:44 PMAdriƔn Mouly
05/18/2022, 2:53 PMAdriƔn Mouly
05/18/2022, 2:53 PMthdxr
05/18/2022, 2:54 PMthdxr
05/18/2022, 2:54 PMAdriƔn Mouly
05/18/2022, 2:54 PMthdxr
05/18/2022, 2:54 PMsst.Parameter
thdxr
05/18/2022, 2:54 PMAdriƔn Mouly
05/18/2022, 2:54 PMAdriƔn Mouly
05/18/2022, 2:54 PMAdriƔn Mouly
05/18/2022, 2:55 PMBjorn Theart
05/18/2022, 2:55 PMthdxr
05/18/2022, 2:56 PM/<your-app>/<your-stage>/MY_CONFIG_VALUE
if it's not found there it'll go to /<your-app>/fallback/MY_CONFIG_VALUE
This is useful if you have multiple environments in the same AWS account and you don't want to set STRIPE_API_KEY 10 timesAdriƔn Mouly
05/18/2022, 2:57 PMthdxr
05/18/2022, 2:57 PMBjorn Theart
05/18/2022, 2:57 PMAdriƔn Mouly
05/18/2022, 2:57 PMthdxr
05/18/2022, 2:57 PMBjorn Theart
05/18/2022, 2:58 PMAdriƔn Mouly
05/18/2022, 2:58 PMthdxr
05/18/2022, 2:58 PMthdxr
05/18/2022, 2:58 PMAdriƔn Mouly
05/18/2022, 2:58 PMBjorn Theart
05/18/2022, 2:58 PMAdriƔn Mouly
05/18/2022, 2:58 PMBjorn Theart
05/18/2022, 2:58 PMBjorn Theart
05/18/2022, 3:05 PMstacks/Parameter.ts
import { App, Function as Fn } from "@serverless-stack/resources";
import { Effect, PolicyStatement } from "aws-cdk-lib/aws-iam";
import { StringParameter } from "aws-cdk-lib/aws-ssm";
import { Construct } from "constructs";
import fs from "fs";
export class Parameter extends Construct {
public readonly name: string;
private static readonly all = new Set<string>();
constructor(scope: Construct, name: string, value?: string) {
super(scope, name);
const app = App.of(scope) as App;
Parameter.all.add(name);
this.name = name;
if (value) {
new StringParameter(this, name, {
parameterName: `/${app.name}/${app.stage}/${name}`,
stringValue: value,
});
}
}
public static Secret = Symbol();
public static create<T extends Record<string, string | typeof Parameter.Secret>>(
scope: Construct,
params: T
) {
const result: Record<string, Parameter> = {};
for (const [key, value] of Object.entries(params)) {
result[key] = new Parameter(scope, key, typeof value === "string" ? value : undefined);
}
return result as Record<keyof T, Parameter>;
}
public static use(func: Fn, ...params: Parameter[]) {
const values = params.map((p) => p.name).join(",");
const app = App.of(params[0]) as App;
const policy = new PolicyStatement({
resources: params.flatMap((p) => [
`arn:aws:ssm:${app.region}:${app.account}:parameter/${app.name}/${app.stage}/${p.name}`,
`arn:aws:ssm:${app.region}:${app.account}:parameter/${app.name}/fallback/${p.name}`,
]),
actions: ["*"],
effect: Effect.ALLOW,
});
func.addToRolePolicy(policy);
func.addEnvironment("SSM_VALUES", values);
func.addEnvironment("SSM_PREFIX", `/${app.name}/${app.stage}/`);
}
public static codegen() {
fs.mkdirSync("node_modules/@types/sst-parameters", {
recursive: true,
});
fs.writeFileSync(
"node_modules/@types/sst-parameters/package.json",
JSON.stringify({
types: "index.d.ts",
})
);
fs.writeFileSync(
"node_modules/@types/sst-parameters/index.d.ts",
`
import "@serverless-stack/node/config";
declare module "@serverless-stack/node/config" {
export interface ConfigType {
${[...Parameter.all].map((p) => `${p}: string`).join(",\n")}
}
}`
);
}
}
Then, in stacks/Api.ts
I have the following route:
...
"GET /config": {
function: {
handler: "functions/config.handler",
},
},
...
here's how I create a secret parameter:
const parameter = Parameter.create(stack, {
HUBSPOT_APIKEY: Parameter.Secret,
});
note: since this is a secret and you're only setting it to a Symbol, make sure you create the parameter in the Parameter Store on AWS
I then get the function reference call Parameter.use
const createConfigFunc = api.getFunction("GET /config");
Parameter.use(createConfigFunc!, parameter.HUBSPOT_APIKEY);
My Lambda function handler looks as follows:
import { Config } from "@serverless-stack/node/config";
import { APIGatewayProxyHandlerV2 } from "aws-lambda";
export const handler: APIGatewayProxyHandlerV2 = async (event) => {
const body = {
test: true,
hubspotApiKey: Config.HUBSPOT_APIKEY,
};
return {
statusCode: 200,
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body, null, " "),
};
};
AdriƔn Mouly
05/18/2022, 3:06 PMAdriƔn Mouly
05/18/2022, 3:06 PMAdriƔn Mouly
05/18/2022, 3:06 PMthdxr
05/18/2022, 3:07 PMfunctions
would just have a parameters
option just like permissionsthdxr
05/18/2022, 3:07 PMthdxr
05/18/2022, 3:08 PMBjorn Theart
05/18/2022, 3:08 PMBjorn Theart
05/18/2022, 3:09 PMDamjan
05/18/2022, 3:09 PMthdxr
05/18/2022, 3:09 PMAlex Rayo
05/18/2022, 7:32 PMthdxr
05/18/2022, 7:33 PMthdxr
05/18/2022, 7:33 PM