+++ title = "Define resources" weight = 300 +++ ## Add resources to the hit counter construct Now, let's define the AWS Lambda function and the DynamoDB table in our `HitCounter` construct. Now, go back to `~/HitCounter.java` and add the following highlighted code: {{<highlight java "hl_lines=3-4 8-13 16-17 22-38 41-53">}} package com.myorg; import java.util.HashMap; import java.util.Map; import software.constructs.Construct; import software.amazon.awscdk.services.dynamodb.Attribute; import software.amazon.awscdk.services.dynamodb.AttributeType; import software.amazon.awscdk.services.dynamodb.Table; import software.amazon.awscdk.services.lambda.Code; import software.amazon.awscdk.services.lambda.Function; import software.amazon.awscdk.services.lambda.Runtime; public class HitCounter extends Construct { private final Function handler; private final Table table; public HitCounter(final Construct scope, final String id, final HitCounterProps props) { super(scope, id); this.table = Table.Builder.create(this, "Hits") .partitionKey(Attribute.builder() .name("path") .type(AttributeType.STRING) .build()) .build(); final Map<String, String> environment = new HashMap<>(); environment.put("DOWNSTREAM_FUNCTION_NAME", props.getDownstream().getFunctionName()); environment.put("HITS_TABLE_NAME", this.table.getTableName()); this.handler = Function.Builder.create(this, "HitCounterHandler") .runtime(Runtime.NODEJS_14_X) .handler("hitcounter.handler") .code(Code.fromAsset("lambda")) .environment(environment) .build(); } /** * @return the counter definition */ public Function getHandler() { return this.handler; } /** * @return the counter table */ public Table getTable() { return this.table; } } {{</highlight>}} ## What did we do here? This code is hopefully easy to understand: * We defined a DynamoDB table, `table`, with `path` as the partition key (every DynamoDB table must have a single partition key). * We defined a Lambda function which is bound to the `lambda/hitcounter.handler` code. * We __wired__ the Lambda's environment variables to the `Function.name` and `Table.name` of our resources via `environment.put(...)`. ## Late-bound values The `FunctionName` and `TableName` properties are values that only resolve when we deploy our stack (notice that we haven't configured these physical names when we defined the table/function, only logical IDs). This means that if you print their values during synthesis, you will get a "TOKEN", which is how the CDK represents these late-bound values. You should treat tokens as *opaque strings*. This means you can concatenate them together for example, but don't be tempted to parse them in your code.