Using AppConfig Layer in your nodejs lambda with AWS CDK
Tags: todayilearned, aws, typescript
Published: 2023-01-24 04:41:22

The biggest problem with conventional configuration management is that the client depends on the server for config updates. This puts you at the mercy of your network stack and having to coordinate with an ops team to update configurations. AWS App Config is a managed service that attempts to solve this and other problems.

## What is AWS App Config?

> Use AWS AppConfig, a capability of AWS Systems Manager, to create, manage, and quickly deploy application configurations. A configuration is a collection of settings that influence the behavior of your application. You can use AWS AppConfig with applications hosted on Amazon Elastic Compute Cloud (Amazon EC2) instances, AWS Lambda, containers, mobile applications, or IoT devices.

## AWS AppConfig use cases

> AWS AppConfig can help you in the following use cases:

> Application tuning – Introduce changes carefully to your application that can be tested with production traffic.
> Feature toggle – Turn on new features that require a timely deployment, such as a product launch or announcement.
> Allow list – Allow premium subscribers to access paid content.
> Operational issues – Reduce stress on your application when a dependency or other external factor impacts the system.

If you want to deep dive into AppConfig you can read more about this [here](https://docs.aws.amazon.com/appconfig/latest/userguide/what-is-appconfig.html).

## What is a [lambda layer](https://docs.aws.amazon.com/lambda/latest/dg/invocation-layers.html)?

> A Lambda layer is a .zip file archive that can contain additional code or other content. A layer can contain libraries, a custom runtime, data, or configuration files. Use layers to reduce deployment package size and to promote code sharing and separation of responsibilities so that you can iterate faster on writing business logic.

You can use some of [lambda extensions](https://docs.aws.amazon.com/lambda/latest/dg/lambda-extensions.html) to power up your lambda, an extension can be a layer as the app config layer for example, lambda supports external and internal extensions. 
An external extension runs as an independent process in the execution environment and continues to run after the function invocation is fully processed. Because extensions run as separate processes, you can write them in a different language than the function. All Lambda runtimes support extensions.

after this brief introduction and recap, we can Bust one's buns xD

## Let's Code
![a woman dancing in front of her computer](https://media0.giphy.com/media/umYMU8G2ixG5mJBDo5/giphy.gif?cid=ecf05e47jtdg65e1q9omtv3gtl1xzfy9iylj9yktjics5s6q&rid=giphy.gif&ct=g)
In this example I'm going to use nodejs with typescript, but you can use another runtime if you want.

So we gonna create our node function class to export and abstract the configuration

### The NodeFunction Class
```typescript
import { Alias, Architecture, ILayerVersion, Runtime, Tracing } from 'aws-cdk-lib/aws-lambda'

export interface INodeFunctionProps extends NodejsFunctionProps {
  layers: ILayerVersion[]
  environment: Record<string, string>
} 
export class NodeFunction extends NodejsFunction {
  readonly alias: Alias

  constructor(scope: Construct, id: string, props: INodeFunctionProps) {
    const defaultProps: NodejsFunctionProps = {
      timeout: Duration.seconds(300),
      runtime: Runtime.NODEJS_16_X,
      environment: {
        NODE_OPTIONS: '--enable-source-maps',
        AWS_NODEJS_CONNECTION_REUSE_ENABLED: '1',
        ...props.environment
      },
      bundling: {
        externalModules: [
          // Use the 'aws-sdk' available in the Lambda runtime
          'aws-sdk',
        ],
        target: 'es2021',
        logLevel: LogLevel.ERROR,
        minify: true,
        keepNames: true,
        sourceMap: false,
      },
      architecture: Architecture.ARM_64,
      logRetention: isProduction ? RetentionDays.ONE_YEAR : RetentionDays.ONE_WEEK,
      tracing: Tracing.ACTIVE,
      layers: [...props.layers]
    }

    super(scope, id, defaultProps)

    this.alias = new Alias(this, id.concat('alias'), {
      version: this.currentVersion,
      aliasName: 'current',
    })
  }
}
```
First of all we need to specify your lambda layer, AWS has some versions of the [AWS AppConfig Lambda extension](https://docs.aws.amazon.com/appconfig/latest/userguide/appconfig-integration-lambda-extensions-versions.html), in this case I'll use the ARM-64 layer because in the following code I'm using [Graviton2](https://www.justaftermidnight247.com/insights/everything-you-need-to-know-about-aws-graviton2/#:~:text=Graviton2%20processors%20are%20a%20type,across%20EC2%20instances%20vs%20competitors.) to improve the performance of my nodejs lambda.

```typescript
//
const appConfig = LayerVersion.fromLayerVersionArn(
      this,
      `my-first-app-config-layer`,
      'arn:aws:lambda:us-east-1:027255383542:layer:AWS-AppConfig-Extension-Arm64:15', // app config extension arn
    )
new NodeFunction(this, 'my-lambda-with-appconfig', {
  layers: [appConfig],
  environment: {
   AWS_APPCONFIG_EXTENSION_PREFETCH_LIST: '/applications/MyApp/environments/Default/configurations/v1' //here you need to specify your app config created on console
  }
})
```

When you deploy your lambda you will see something like that on cloudwatch:

![cloudwatch with logs of app config loaded](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5u88ymty9ly4jkmn26ik.png)

That's all folks, enjoy your app config!

![](https://media3.giphy.com/media/cXblnKXr2BQOaYnTni/giphy.gif?cid=ecf05e47dz0ezul0jq3v2ypfd8n5tv834yql6uey5sg19kpt&rid=giphy.gif&ct=g)