diff --git a/cloudfront-keyvaluestore-apigw-routing-cdk/README.md b/cloudfront-keyvaluestore-apigw-routing-cdk/README.md
new file mode 100644
index 000000000..82d7d23e9
--- /dev/null
+++ b/cloudfront-keyvaluestore-apigw-routing-cdk/README.md
@@ -0,0 +1,126 @@
+# Amazon CloudFront with Amazon API Gateway Routing using Key Value Store
+
+This pattern demonstrates how to use Amazon CloudFront with CloudFront Functions to dynamically route traffic between multiple Amazon API Gateway endpoints. The routing decisions are based on values stored in CloudFront Key Value Store, allowing for flexible, configuration-driven request routing without redeploying your infrastructure.
+This example uses an equal (50:50 distribution) between both API Gateways. For more informations on "cell partitioning" refer to the [AWS Well-Architected Guide - Cell Partition](https://docs.aws.amazon.com/wellarchitected/latest/reducing-scope-of-impact-with-cell-based-architecture/cell-partition.html)
+
+Learn more about this pattern at Serverless Land Patterns: [https://serverlessland.com/patterns/cloudfront-keyvaluestore-apigw-routing-cdk](https://serverlessland.com/patterns/cloudfront-keyvaluestore-apigw-routing-cdk)
+
+Important: this application uses various AWS services and there are costs associated with these services after the Free Tier usage - please see the [AWS Pricing page](https://aws.amazon.com/pricing/) for details. You are responsible for any AWS costs incurred. No warranty is implied in this example.
+
+## Requirements
+
+* [Create an AWS account](https://portal.aws.amazon.com/gp/aws/developer/registration/index.html) if you do not already have one and log in. The IAM user that you use must have sufficient permissions to make necessary AWS service calls and manage AWS resources.
+* [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) installed and configured
+* [Git Installed](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
+* [Node.js and npm](https://nodejs.org/) installed
+* [AWS CDK](https://docs.aws.amazon.com/cdk/latest/guide/getting_started.html) installed
+
+## Deployment Instructions
+
+1. Create a new directory, navigate to that directory in a terminal and clone the GitHub repository:
+
+ ```
+ git clone https://github.com/aws-samples/serverless-patterns
+ ```
+
+1. Change directory to the pattern directory:
+
+ ```
+ cd cloudfront-keyvaluestore-apigw-routing-cdk
+ ```
+
+1. Install dependencies:
+
+ ```
+ npm install
+ ```
+
+1. Deploy the CDK stack to your default AWS account and region:
+
+ ```
+ cdk deploy
+ ```
+ **The deployment will take a couple of minutes**
+
+1. Note the outputs from the CDK deployment process. These contain the resource URLs and ARNs which are used for testing.
+
+
+## How it works
+
+
+
+1. The client makes a request to the CloudFront distribution
+1. The CloudFront Function executes on viewer request events
+1. The function retrieves routing information from CloudFront Key Value Store
+1. Based on the retrieved value, the function redirects the request to one of the two API Gateway endpoints
+1. The selected API Gateway returns its response to the client
+
+In a real-world scenario the available targets would be maintained in the Key Value Store depending on the desired business logic and requirements.
+
+## Testing
+
+1. Get Key Value Store `ETAG` and note it down.
+
+ ```
+ aws cloudfront-keyvaluestore describe-key-value-store \
+ --kvs-arn=[KVSTOREARN]
+ ```
+
+1. Add entries to the Key Value Storereplace. Replace `[KVSTOREARN]`, `[APIGATEWAY1URL]`, and `[APIGATEWAY2URL]` with the noted outputs.
+
+ ```
+ aws cloudfront-keyvaluestore update-keys \
+ --kvs-arn[KVSTOREARN] \
+ --if-match=[ETAG] \
+ --puts '[
+ {
+ "Key": "APIGW1URL",
+ "Value": "[APIGATEWAY1URL] "
+ },
+ {
+ "Key": "APIGW2URL",
+ "Value": "[APIGATEWAY2URL]"
+ }
+ ]'
+ ```
+
+ If you receive something similar to, it worked
+ ```json
+ {
+ "ETag": "KV3UN6WX5RRO2AG",
+ "ItemCount": 2,
+ "TotalSizeInBytes": 145
+ }
+ ```
+
+1. Access the CloudFront URL in a browser or via curl, replace `[CLOUDFRONTDOMAINNAME]`:
+
+ ```
+ curl -i -L [CLOUDFRONTDOMAINNAME]
+ ```
+
+1. The request should be redirected to either API Gateway 1 or API Gateway 2, and you should see a response like:
+
+ ```
+ {"message": "Hello from API 1"}
+ ```
+
+ or
+
+ ```
+ {"message": "Hello from API 2"}
+ ```
+
+1. Make multiple requests to observe the random routing between the two API Gateway endpoints.
+
+
+## Cleanup
+
+1. Delete the stack
+ ```bash
+ cdk destroy
+ ```
+----
+Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+
+SPDX-License-Identifier: MIT-0
diff --git a/cloudfront-keyvaluestore-apigw-routing-cdk/bin/cloudfront-keyvaluestore-apigw-routing-cdk.ts b/cloudfront-keyvaluestore-apigw-routing-cdk/bin/cloudfront-keyvaluestore-apigw-routing-cdk.ts
new file mode 100644
index 000000000..ef7947583
--- /dev/null
+++ b/cloudfront-keyvaluestore-apigw-routing-cdk/bin/cloudfront-keyvaluestore-apigw-routing-cdk.ts
@@ -0,0 +1,12 @@
+#!/usr/bin/env node
+import * as cdk from "aws-cdk-lib";
+import { PatternStack } from "../lib/pattern-stack";
+
+const app = new cdk.App();
+// amazonq-ignore-next-line
+new PatternStack(app, "PatternStack", {
+ env: {
+ account: process.env.CDK_DEFAULT_ACCOUNT,
+ region: process.env.CDK_DEFAULT_REGION,
+ },
+});
diff --git a/cloudfront-keyvaluestore-apigw-routing-cdk/cdk.json b/cloudfront-keyvaluestore-apigw-routing-cdk/cdk.json
new file mode 100644
index 000000000..f8740512e
--- /dev/null
+++ b/cloudfront-keyvaluestore-apigw-routing-cdk/cdk.json
@@ -0,0 +1,83 @@
+{
+ "app": "npx ts-node --prefer-ts-exts bin/cloudfront-keyvaluestore-apigw-routing-cdk.ts",
+ "watch": {
+ "include": ["**"],
+ "exclude": [
+ "README.md",
+ "cdk*.json",
+ "**/*.d.ts",
+ "**/*.js",
+ "tsconfig.json",
+ "package*.json",
+ "yarn.lock",
+ "node_modules",
+ "test"
+ ]
+ },
+ "context": {
+ "@aws-cdk/aws-lambda:recognizeLayerVersion": true,
+ "@aws-cdk/core:checkSecretUsage": true,
+ "@aws-cdk/core:target-partitions": ["aws", "aws-cn"],
+ "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
+ "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
+ "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true,
+ "@aws-cdk/aws-iam:minimizePolicies": true,
+ "@aws-cdk/core:validateSnapshotRemovalPolicy": true,
+ "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true,
+ "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true,
+ "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true,
+ "@aws-cdk/aws-apigateway:disableCloudWatchRole": true,
+ "@aws-cdk/core:enablePartitionLiterals": true,
+ "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true,
+ "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true,
+ "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true,
+ "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true,
+ "@aws-cdk/aws-route53-patters:useCertificate": true,
+ "@aws-cdk/customresources:installLatestAwsSdkDefault": false,
+ "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true,
+ "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true,
+ "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true,
+ "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true,
+ "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true,
+ "@aws-cdk/aws-redshift:columnId": true,
+ "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true,
+ "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true,
+ "@aws-cdk/aws-apigateway:requestValidatorUniqueId": true,
+ "@aws-cdk/aws-kms:aliasNameRef": true,
+ "@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true,
+ "@aws-cdk/core:includePrefixInUniqueNameGeneration": true,
+ "@aws-cdk/aws-efs:denyAnonymousAccess": true,
+ "@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true,
+ "@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true,
+ "@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true,
+ "@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true,
+ "@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true,
+ "@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true,
+ "@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true,
+ "@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": true,
+ "@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": true,
+ "@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": true,
+ "@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": true,
+ "@aws-cdk/aws-eks:nodegroupNameAttribute": true,
+ "@aws-cdk/aws-ec2:ebsDefaultGp3Volume": true,
+ "@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": true,
+ "@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault": false,
+ "@aws-cdk/aws-s3:keepNotificationInImportedBucket": false,
+ "@aws-cdk/aws-ecs:enableImdsBlockingDeprecatedFeature": false,
+ "@aws-cdk/aws-ecs:disableEcsImdsBlocking": true,
+ "@aws-cdk/aws-ecs:reduceEc2FargateCloudWatchPermissions": true,
+ "@aws-cdk/aws-dynamodb:resourcePolicyPerReplica": true,
+ "@aws-cdk/aws-ec2:ec2SumTImeoutEnabled": true,
+ "@aws-cdk/aws-appsync:appSyncGraphQLAPIScopeLambdaPermission": true,
+ "@aws-cdk/aws-rds:setCorrectValueForDatabaseInstanceReadReplicaInstanceResourceId": true,
+ "@aws-cdk/core:cfnIncludeRejectComplexResourceUpdateCreatePolicyIntrinsics": true,
+ "@aws-cdk/aws-lambda-nodejs:sdkV3ExcludeSmithyPackages": true,
+ "@aws-cdk/aws-stepfunctions-tasks:fixRunEcsTaskPolicy": true,
+ "@aws-cdk/aws-ec2:bastionHostUseAmazonLinux2023ByDefault": true,
+ "@aws-cdk/aws-route53-targets:userPoolDomainNameMethodWithoutCustomResource": true,
+ "@aws-cdk/aws-elasticloadbalancingV2:albDualstackWithoutPublicIpv4SecurityGroupRulesDefault": true,
+ "@aws-cdk/aws-iam:oidcRejectUnauthorizedConnections": true,
+ "@aws-cdk/core:enableAdditionalMetadataCollection": true,
+ "@aws-cdk/aws-lambda:createNewPoliciesWithAddToRolePolicy": true
+ }
+}
diff --git a/cloudfront-keyvaluestore-apigw-routing-cdk/cloudfront-keyvaluestore-apigw-routing-cdk.json b/cloudfront-keyvaluestore-apigw-routing-cdk/cloudfront-keyvaluestore-apigw-routing-cdk.json
new file mode 100644
index 000000000..ddf7730f5
--- /dev/null
+++ b/cloudfront-keyvaluestore-apigw-routing-cdk/cloudfront-keyvaluestore-apigw-routing-cdk.json
@@ -0,0 +1,111 @@
+{
+ "title": "Amazon CloudFront with API Gateway Routing using Key Value Store",
+ "description": "Route traffic dynamically between API Gateway endpoints using CloudFront Functions and Key Value Store without redeploying infrastructure.",
+ "language": "TypeScript",
+ "level": "300",
+ "framework": "AWS CDK",
+ "introBox": {
+ "headline": "How it works",
+ "text": [
+ "This pattern demonstrates how to use Amazon CloudFront with CloudFront Functions to dynamically route traffic between multiple Amazon API Gateway endpoints.",
+ "The routing decisions are based on values stored in CloudFront Key Value Store, allowing for flexible, configuration-driven request routing without redeploying your infrastructure.",
+ "This example uses an equal (50:50 distribution) between both API Gateways, showcasing how to implement cell partitioning for your applications.",
+ "The pattern deploys a CloudFront distribution, CloudFront Function, CloudFront Key Value Store, and two API Gateway endpoints."
+ ]
+ },
+ "gitHub": {
+ "template": {
+ "repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/cloudfront-keyvaluestore-apigw-routing-cdk",
+ "templateURL": "serverless-patterns/cloudfront-keyvaluestore-apigw-routing-cdk",
+ "projectFolder": "cloudfront-keyvaluestore-apigw-routing-cdk",
+ "templateFile": "lib/pattern-stack.ts"
+ }
+ },
+ "resources": {
+ "bullets": [
+ {
+ "text": "AWS Well-Architected Guide - Cell Partition",
+ "link": "https://docs.aws.amazon.com/wellarchitected/latest/reducing-scope-of-impact-with-cell-based-architecture/cell-partition.html"
+ },
+ {
+ "text": "CloudFront Key Value Store Documentation",
+ "link": "https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/kvs-with-functions.html"
+ },
+ {
+ "text": "CloudFront Functions Documentation",
+ "link": "https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-functions.html"
+ }
+ ]
+ },
+ "deploy": {
+ "text": [
+ "Clone the repository: git clone https://github.com/aws-samples/serverless-patterns",
+ "Change directory: cd cloudfront-keyvaluestore-apigw-routing-cdk",
+ "Install dependencies: npm install",
+ "Deploy the CDK stack: cdk deploy"
+ ]
+ },
+ "testing": {
+ "text": [
+ "1. Get Key Value Store ETAG: aws cloudfront-keyvaluestore describe-key-value-store --kvs-arn=[KVSTOREARN]",
+ "2. Add entries to the Key Value Store: aws cloudfront-keyvaluestore update-keys --kvs-arn=[KVSTOREARN] --if-match=[ETAG] --puts '[{\"Key\": \"APIGW1URL\", \"Value\": \"[APIGATEWAY1URL]\"},{\"Key\": \"APIGW2URL\", \"Value\": \"[APIGATEWAY2URL]\"}]'",
+ "3. Access CloudFront URL: curl -i -L [CLOUDFRONTDOMAINNAME]",
+ "4. The request should be redirected to either API Gateway 1 or API Gateway 2, showing a response like {\"message\": \"Hello from API 1\"} or {\"message\": \"Hello from API 2\"}",
+ "5. Make multiple requests to observe routing between the two API Gateway endpoints."
+ ]
+ },
+ "cleanup": {
+ "text": [
+ "Delete the stack: cdk destroy"
+ ]
+ },
+ "authors": [
+ {
+ "name": "Marco Jahn",
+ "image": "https://sessionize.com/image/e99b-400o400o2-pqR4BacUSzHrq4fgZ4wwEQ.png",
+ "bio": "Senior Solutions Architect, Amazon Web Services",
+ "linkedin": "marcojahn"
+ }
+ ],
+ "patternArch": {
+ "icon1": {
+ "x": 20,
+ "y": 50,
+ "service": "cloudfront",
+ "label": "Amazon CloudFront"
+ },
+ "icon2": {
+ "x": 50,
+ "y": 50,
+ "service": "cf-functions",
+ "label": "CloudFront function"
+ },
+ "icon3": {
+ "x": 80,
+ "y": 20,
+ "service": "apigw",
+ "label": "Amazon API Gateway 1"
+ },
+ "icon4": {
+ "x": 80,
+ "y": 70,
+ "service": "apigw",
+ "label": "Amazon API Gateway 2"
+ },
+ "line1": {
+ "from": "icon1",
+ "to": "icon2",
+ "label": ""
+ },
+ "line2": {
+ "from": "icon2",
+ "to": "icon3",
+ "label": ""
+ },
+ "line3": {
+ "from": "icon2",
+ "to": "icon4",
+ "label": ""
+ }
+ }
+}
diff --git a/cloudfront-keyvaluestore-apigw-routing-cdk/cloudfront-keyvaluestore-apigw-routing-cdk.png b/cloudfront-keyvaluestore-apigw-routing-cdk/cloudfront-keyvaluestore-apigw-routing-cdk.png
new file mode 100644
index 000000000..e4504860c
Binary files /dev/null and b/cloudfront-keyvaluestore-apigw-routing-cdk/cloudfront-keyvaluestore-apigw-routing-cdk.png differ
diff --git a/cloudfront-keyvaluestore-apigw-routing-cdk/example-pattern.json b/cloudfront-keyvaluestore-apigw-routing-cdk/example-pattern.json
new file mode 100644
index 000000000..4d49ca4ef
--- /dev/null
+++ b/cloudfront-keyvaluestore-apigw-routing-cdk/example-pattern.json
@@ -0,0 +1,68 @@
+{
+ "title": "Amazon CloudFront with API Gateway Routing using Key Value Store",
+ "description": "Route traffic dynamically between API Gateway endpoints using CloudFront Functions and Key Value Store without redeploying infrastructure.",
+ "language": "TypeScript",
+ "level": "300",
+ "framework": "AWS CDK",
+ "introBox": {
+ "headline": "How it works",
+ "text": [
+ "This pattern demonstrates how to use Amazon CloudFront with CloudFront Functions to dynamically route traffic between multiple Amazon API Gateway endpoints.",
+ "The routing decisions are based on values stored in CloudFront Key Value Store, allowing for flexible, configuration-driven request routing without redeploying your infrastructure.",
+ "This example uses an equal (50:50 distribution) between both API Gateways, showcasing how to implement cell partitioning for your applications.",
+ "The pattern deploys a CloudFront distribution, CloudFront Function, CloudFront Key Value Store, and two API Gateway endpoints."
+ ]
+ },
+ "gitHub": {
+ "template": {
+ "repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/cloudfront-keyvaluestore-apigw-routing-cdk",
+ "templateURL": "serverless-patterns/cloudfront-keyvaluestore-apigw-routing-cdk",
+ "projectFolder": "cloudfront-keyvaluestore-apigw-routing-cdk",
+ "templateFile": "lib/pattern-stack.ts"
+ }
+ },
+ "resources": {
+ "bullets": [
+ {
+ "text": "AWS Well-Architected Guide - Cell Partition",
+ "link": "https://docs.aws.amazon.com/wellarchitected/latest/reducing-scope-of-impact-with-cell-based-architecture/cell-partition.html"
+ },
+ {
+ "text": "CloudFront Key Value Store Documentation",
+ "link": "https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/kvs-with-functions.html"
+ },
+ {
+ "text": "CloudFront Functions Documentation",
+ "link": "https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-functions.html"
+ }
+ ]
+ },
+ "deploy": {
+ "text": [
+ "Clone the repository: git clone https://github.com/aws-samples/serverless-patterns",
+ "Change directory: cd cloudfront-keyvaluestore-apigw-routing-cdk",
+ "Install dependencies: npm install",
+ "Deploy the CDK stack: cdk deploy"
+ ]
+ },
+ "testing": {
+ "text": [
+ "1. Get Key Value Store ETAG: aws cloudfront-keyvaluestore describe-key-value-store --kvs-arn=[KVSTOREARN]",
+ "2. Add entries to the Key Value Store: aws cloudfront-keyvaluestore update-keys --kvs-arn=[KVSTOREARN] --if-match=[ETAG] --puts '[{\"Key\": \"APIGW1URL\", \"Value\": \"[APIGATEWAY1URL]\"},{\"Key\": \"APIGW2URL\", \"Value\": \"[APIGATEWAY2URL]\"}]'",
+ "3. Access CloudFront URL: curl -i -L [CLOUDFRONTDOMAINNAME]",
+ "4. The request should be redirected to either API Gateway 1 or API Gateway 2, showing a response like {\"message\": \"Hello from API 1\"} or {\"message\": \"Hello from API 2\"}",
+ "5. Make multiple requests to observe routing between the two API Gateway endpoints."
+ ]
+ },
+ "cleanup": {
+ "text": ["Delete the stack: cdk destroy"]
+ },
+ "authors": [
+ {
+ "name": "Marco Jahn",
+ "image": "https://sessionize.com/image/e99b-400o400o2-pqR4BacUSzHrq4fgZ4wwEQ.png",
+ "bio": "Senior Solutions Architect, Amazon Web Services",
+ "linkedin": "marcojahn"
+ }
+ ]
+}
diff --git a/cloudfront-keyvaluestore-apigw-routing-cdk/lib/pattern-stack.ts b/cloudfront-keyvaluestore-apigw-routing-cdk/lib/pattern-stack.ts
new file mode 100644
index 000000000..84e210c24
--- /dev/null
+++ b/cloudfront-keyvaluestore-apigw-routing-cdk/lib/pattern-stack.ts
@@ -0,0 +1,133 @@
+import * as cdk from "aws-cdk-lib";
+import * as cloudfront from "aws-cdk-lib/aws-cloudfront";
+import * as origins from "aws-cdk-lib/aws-cloudfront-origins";
+import * as apigateway from "aws-cdk-lib/aws-apigateway";
+import * as s3 from "aws-cdk-lib/aws-s3";
+import { Construct } from "constructs";
+
+export class PatternStack extends cdk.Stack {
+ constructor(scope: Construct, id: string, props?: cdk.StackProps) {
+ super(scope, id, props);
+
+ // create two Rest API GWs, both with a http status 200 mock response, but with individual payload
+ const api1 = new apigateway.RestApi(this, "api1", {
+ description: "API 1",
+ endpointConfiguration: {
+ types: [apigateway.EndpointType.REGIONAL],
+ },
+ });
+ api1.root.addMethod(
+ "GET",
+ new apigateway.MockIntegration({
+ integrationResponses: [
+ {
+ statusCode: "200",
+ responseTemplates: {
+ "application/json": `{"message": "Hello from API 1"}`,
+ },
+ },
+ ],
+ requestTemplates: {
+ "application/json": '{"statusCode": 200}',
+ },
+ }),
+ {
+ methodResponses: [{ statusCode: "200" }],
+ },
+ );
+ const api2 = new apigateway.RestApi(this, "api2", {
+ description: "API 2",
+ endpointConfiguration: {
+ types: [apigateway.EndpointType.REGIONAL],
+ },
+ });
+ api2.root.addMethod(
+ "GET",
+ new apigateway.MockIntegration({
+ integrationResponses: [
+ {
+ statusCode: "200",
+ responseTemplates: {
+ "application/json": `{"message": "Hello from API 2"}`,
+ },
+ },
+ ],
+ requestTemplates: {
+ "application/json": '{"statusCode": 200}',
+ },
+ }),
+ {
+ methodResponses: [{ statusCode: "200" }],
+ },
+ );
+
+ const kvStore = new cloudfront.KeyValueStore(this, "KVStore", {});
+
+ const bucket = new s3.Bucket(this, "DistributionBucket", {
+ bucketName: `distribution-bucket-${this.account}`,
+ enforceSSL: true,
+ removalPolicy: cdk.RemovalPolicy.DESTROY,
+ });
+
+ // 2. Create CloudFront Function for redirects
+ const redirectFunction = new cloudfront.Function(this, "RedirectFunction", {
+ code: cloudfront.FunctionCode.fromInline(`
+ import cf from 'cloudfront';
+
+ // This fails if there is no key value store associated with the function
+ const kvsHandle = cf.kvs();
+
+ async function handler(event) {
+ const request = event.request;
+
+ const kvKey = 'APIGW' + (Math.random() < 0.5 ? 1 : 2) + 'URL';
+
+ const redirectUrl = await kvsHandle.get(kvKey);
+
+ const response = {
+ statusCode: 302,
+ statusDescription: 'Found',
+ headers:
+ { "location": { "value": redirectUrl } }
+ }
+
+ return response;
+ }
+ `),
+ // Note that JS_2_0 must be used for Key Value Store support
+ runtime: cloudfront.FunctionRuntime.JS_2_0,
+ keyValueStore: kvStore,
+ });
+
+ // add cloudfront distribution with no behaviour
+ const cloudFrontDistribution = new cloudfront.Distribution(this, "CloudFrontDistribution", {
+ defaultBehavior: {
+ origin: origins.S3BucketOrigin.withOriginAccessControl(bucket),
+ functionAssociations: [
+ {
+ function: redirectFunction,
+ eventType: cloudfront.FunctionEventType.VIEWER_REQUEST,
+ },
+ ],
+ },
+ });
+
+ // Output Cloudfront URL as CloudFormation output
+ new cdk.CfnOutput(this, "CLOUDFRONTDOMAINNAME", {
+ value: cloudFrontDistribution.distributionDomainName,
+ });
+
+ new cdk.CfnOutput(this, "APIGATEWAY1URL", {
+ value: api1.url,
+ });
+
+ new cdk.CfnOutput(this, "APIGATEWAY2URL", {
+ value: api2.url,
+ });
+
+ // output kv arn
+ new cdk.CfnOutput(this, "KVSTOREARN", {
+ value: kvStore.keyValueStoreArn,
+ });
+ }
+}
diff --git a/cloudfront-keyvaluestore-apigw-routing-cdk/package.json b/cloudfront-keyvaluestore-apigw-routing-cdk/package.json
new file mode 100644
index 000000000..421c1ab7a
--- /dev/null
+++ b/cloudfront-keyvaluestore-apigw-routing-cdk/package.json
@@ -0,0 +1,23 @@
+{
+ "name": "cloudfront-keyvaluestore-apigw-routing-cdk",
+ "version": "0.1.0",
+ "bin": {
+ "cloudfront-keyvaluestore-apigw-routing-cdk": "bin/cloudfront-keyvaluestore-apigw-routing-cdk.js"
+ },
+ "scripts": {
+ "build": "tsc",
+ "watch": "tsc -w",
+ "cdk": "cdk"
+ },
+ "devDependencies": {
+ "@types/jest": "^29.5.14",
+ "@types/node": "22.7.9",
+ "aws-cdk": "2.1003.0",
+ "ts-node": "^10.9.2",
+ "typescript": "~5.6.3"
+ },
+ "dependencies": {
+ "aws-cdk-lib": "2.181.1",
+ "constructs": "^10.0.0"
+ }
+}
diff --git a/cloudfront-keyvaluestore-apigw-routing-cdk/tsconfig.json b/cloudfront-keyvaluestore-apigw-routing-cdk/tsconfig.json
new file mode 100644
index 000000000..aaa7dc510
--- /dev/null
+++ b/cloudfront-keyvaluestore-apigw-routing-cdk/tsconfig.json
@@ -0,0 +1,31 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "module": "commonjs",
+ "lib": [
+ "es2020",
+ "dom"
+ ],
+ "declaration": true,
+ "strict": true,
+ "noImplicitAny": true,
+ "strictNullChecks": true,
+ "noImplicitThis": true,
+ "alwaysStrict": true,
+ "noUnusedLocals": false,
+ "noUnusedParameters": false,
+ "noImplicitReturns": true,
+ "noFallthroughCasesInSwitch": false,
+ "inlineSourceMap": true,
+ "inlineSources": true,
+ "experimentalDecorators": true,
+ "strictPropertyInitialization": false,
+ "typeRoots": [
+ "./node_modules/@types"
+ ]
+ },
+ "exclude": [
+ "node_modules",
+ "cdk.out"
+ ]
+}