<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Gerald Stewart</title>
    <description>The latest articles on DEV Community by Gerald Stewart (@_gerald20).</description>
    <link>https://dev.to/_gerald20</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F393860%2Ffc863b68-758a-4194-b502-f6a737658ea1.jpg</url>
      <title>DEV Community: Gerald Stewart</title>
      <link>https://dev.to/_gerald20</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/_gerald20"/>
    <language>en</language>
    <item>
      <title>Migrating 85 Million DynamoDB Records Across AWS Accounts</title>
      <dc:creator>Gerald Stewart</dc:creator>
      <pubDate>Mon, 27 Mar 2023 15:33:28 +0000</pubDate>
      <link>https://dev.to/aws-builders/migrating-85-million-dynamodb-records-across-aws-accounts-5996</link>
      <guid>https://dev.to/aws-builders/migrating-85-million-dynamodb-records-across-aws-accounts-5996</guid>
      <description>&lt;p&gt;As part of a merger with another team, my team migrated 8 DynamoDB tables from one AWS account to another.&lt;/p&gt;

&lt;p&gt;This was a challenging process, in this blog I'll be covering everything the AWS documentation doesn't tell you to look out for when migrating DynamoDB table across AWS Accounts.&lt;/p&gt;

&lt;h1&gt;
  
  
  Design
&lt;/h1&gt;

&lt;p&gt;Initially, we were investigating the use of AWS Glue following &lt;a href="https://aws.amazon.com/blogs/database/cross-account-replication-with-amazon-dynamodb/" rel="noopener noreferrer"&gt;this blog&lt;/a&gt;. AWS Glue was a service we were unfamiliar with and it would have resulted in us needing to write a different Python Glue script for each table. We ruled this our as a potential option based on this.&lt;/p&gt;

&lt;p&gt;During our investigation into a suitable approach for this work, AWS released the new &lt;a href="https://aws.amazon.com/blogs/database/amazon-dynamodb-can-now-import-amazon-s3-data-into-a-new-table/" rel="noopener noreferrer"&gt;import to S3 functionality&lt;/a&gt;, we were able to leverage this alongside a table export to S3 to complete the data move.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fegyqx4qmuoeyp7083wc5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fegyqx4qmuoeyp7083wc5.png" alt="Architecture diagram of export"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While AWS gives us the steps needed to complete this move using the console, we are typically unable to do this due to restricted access to anything above our development environment. Plus the steps outlined in the blog show creating a table through the console, hardly a suitable process for any real-life project.&lt;/p&gt;

&lt;p&gt;We came up with the following process to complete this work that would work with the level of access we could get: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Elevate into the IAM role with permissions to trigger an S3 export and write to the target account data transfer bucket. Permissions required can be found &lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/S3DataExport_Requesting.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Trigger export, specifying target account ID and bucket name.&lt;/li&gt;
&lt;li&gt;Once complete this will generate a new folder in the data transfer bucket. This will look like &lt;code&gt;AWSDynamoDB/&amp;lt;id&amp;gt;/data&lt;/code&gt; with  being a generated ID.&lt;/li&gt;
&lt;li&gt;This path needs to be specified in the import parameters used to trigger the import and create the new table.&lt;/li&gt;
&lt;li&gt;After adding this ID to your code, begin deployment of the new database, this will trigger an import as part of the deployment. Eventually, you will have a created table with the data present.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Full credit to &lt;a href="https://twitter.com/EliasBrange" rel="noopener noreferrer"&gt;Elias Brange&lt;/a&gt; for &lt;a href="https://www.eliasbrange.dev/posts/migrate-dynamodb-with-zero-downtime/" rel="noopener noreferrer"&gt;this fantastic blog post on how to trigger imports and table creation using the AWS CDK&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dynamodb-table.html#cfn-dynamodb-table-importsourcespecification" rel="noopener noreferrer"&gt;CloudFormation documentation&lt;/a&gt; for &lt;code&gt;ImportSourceSpecification&lt;/code&gt; has now been released and is considered stable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenges
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Zero Feedback on Progress
&lt;/h3&gt;

&lt;p&gt;After triggering an import or export, the AWS Console will just say "importing". One of the tables that we imported had 55 million rows and took nearly 1 hour and 30 minutes to import. All while we had a production outage to facilitate the data migration.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fflyizdgu7pho2r70fn1n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fflyizdgu7pho2r70fn1n.png" alt="DynamoDB Export"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Some indication of progress or estimated time remaining would instil more confidence in this process.&lt;/p&gt;

&lt;p&gt;In addition to this, the import time varied widely and there was no way to speed it up. As we took a considerable production outage to migrate the data we ideally would have wanted a faster process for larger tables.&lt;/p&gt;

&lt;h3&gt;
  
  
  DynamoDB Global Tables
&lt;/h3&gt;

&lt;p&gt;As part of the move, we switched to global tables as we look to enable multi-region for our applications.&lt;/p&gt;

&lt;p&gt;One issue we had was a deployment of a table failed to complete as the &lt;code&gt;waitForReplicationToFinish&lt;/code&gt; property is defaulted to &lt;code&gt;true&lt;/code&gt; in the &lt;a href="https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_dynamodb.Table.html#waitforreplicationtofinish" rel="noopener noreferrer"&gt;AWS CDK&lt;/a&gt;. This deployment failed because the custom resource time out is limited to a maximum of 60 minutes.&lt;/p&gt;

&lt;p&gt;This resulted in this error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CloudFormation did not receive a response from your Custom Resource. Please check your logs for requestId [*****].
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This resulted in a stack being stuck in a &lt;code&gt;DELETE_FAILED&lt;/code&gt; state. As the source table could not be deleted as it had acted as a replica provider in the last 24 hours.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Resource handler returned message: "Replica cannot be deleted because it has acted as a source region for new replica(s) being added to the table in the last 24 hours.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As the actual table wasn't deleted, we were still able to read and write data from the table in a &lt;code&gt;DELETE_FAILED&lt;/code&gt; state.&lt;/p&gt;

&lt;p&gt;To repair this stack we had to export the new table to S3, delete the CloudFormation stack and re-import the data from S3 with the &lt;code&gt;waitForReplicationToFinish&lt;/code&gt; property set to get the stack in a healthy state.&lt;/p&gt;

&lt;p&gt;This may have been a user error but should serve as good learning for anyone switching from a standard DynamoDB table to a global table.&lt;/p&gt;

&lt;h3&gt;
  
  
  Manual Process
&lt;/h3&gt;

&lt;p&gt;This was a very manual process to complete, compared with using AWS DMS to migrate data for other AWS Database offerings. It required a lot of pre-work, and investigation and wasn't a quick process to complete in production.&lt;/p&gt;

&lt;p&gt;I identified 9 steps that we needed to take for each migration:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Deploy the application branch to shut off writes to the source database&lt;/li&gt;
&lt;li&gt;Verify this has been completed before proceeding&lt;/li&gt;
&lt;li&gt;Trigger export of source database&lt;/li&gt;
&lt;li&gt;Add import ID to new database branch&lt;/li&gt;
&lt;li&gt;Verify export has been completed before proceeding&lt;/li&gt;
&lt;li&gt;Deploy the new database branch with import ID&lt;/li&gt;
&lt;li&gt;Verify import completes&lt;/li&gt;
&lt;li&gt;Revert application branch to resume writes to the database&lt;/li&gt;
&lt;li&gt;Verify new writes happening to DB&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I would ideally have liked a managed solution from AWS to handle this migration without downtime or as much of a manual process.&lt;/p&gt;

&lt;h3&gt;
  
  
  Redundant CloudFormation Properties
&lt;/h3&gt;

&lt;p&gt;To trigger the imports, we used CDK escape hatches to specify &lt;code&gt;ImportSourceSpecification&lt;/code&gt; when creating our DynamoDB table.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cfnTable.addPropertyOverride('ImportSourceSpecification.S3BucketSource.S3Bucket', bucketName);
cfnTable.addPropertyOverride('ImportSourceSpecification.S3BucketSource.S3KeyPrefix', bucketPath);
cfnTable.addPropertyOverride('ImportSourceSpecification.InputCompressionType', 'GZIP');
cfnTable.addPropertyOverride('ImportSourceSpecification.InputFormat', 'DYNAMODB_JSON');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As per the &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dynamodb-table.html#cfn-dynamodb-table-importsourcespecification" rel="noopener noreferrer"&gt;CloudFormation documentation for DynamoDB tables&lt;/a&gt; the update policy of this is &lt;code&gt;Replacement&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa1xe88gvmdd7ygrvisuu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa1xe88gvmdd7ygrvisuu.png" alt="CloudFormation Documentation for DynamoDB table"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ideally, we would have liked to remove this property from our CDK stacks after that initial table creation and successful completion of the import. We have a large number of tables and want to keep our code neat and tidy.&lt;/p&gt;

&lt;p&gt;It's definitely introduced a bit of technical debt to these projects as if someone inadvertently removes these properties it will break the deployment of the table. We have a warning comment above these lines in every project, but again this is a far from optimal solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;If you are looking to migrate data, the export to S3 functionality is a good solution. Just be extra cautious of the things I've outlined in this post.&lt;/p&gt;

&lt;p&gt;I'd also recommend outlining a plan to "abort" a migration once you have started it if anything goes wrong. This process has a lot of moving parts and a lot of potential failure points.&lt;/p&gt;

&lt;p&gt;I'd also love if AWS solved some of the issues outlined in this post, it wasn't the best experience compared to if I had of been migrating a DB supported by DMS. Always felt weird that DynamoDB wasn't supported by this service.&lt;/p&gt;

&lt;p&gt;Have you migrated DynamoDB data in a different way than I have, if so I'd love to hear about your approach in the comments!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Improving Operational Excellence using Game Days</title>
      <dc:creator>Gerald Stewart</dc:creator>
      <pubDate>Tue, 24 Jan 2023 11:43:48 +0000</pubDate>
      <link>https://dev.to/aws-builders/improving-operational-excellence-using-game-days-23cg</link>
      <guid>https://dev.to/aws-builders/improving-operational-excellence-using-game-days-23cg</guid>
      <description>&lt;p&gt;A game day is a practice event that simulates a failure or outage so that you can test your systems, your processes and your team's response to remediate or act on that particular event.&lt;/p&gt;

&lt;p&gt;AWS defines &lt;a href="https://wa.aws.amazon.com/wellarchitected/2020-07-02T19-33-23/wat.pillar.operationalExcellence.en.html" rel="noopener noreferrer"&gt;operational excellence&lt;/a&gt; as&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The Operational Excellence pillar includes the ability to support the development and run workloads effectively, gain insight into their operations, and continuously improve supporting processes and procedures to deliver business value.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To me, game days go hand-in-hand with the Operational Excellence pillar of the Well-Architected framework. They are even explicitly called out under the anticipate failure design principle.&lt;/p&gt;




&lt;p&gt;I ran a few game-day scenarios earlier this year with my team to get them comfortable with the prospect of providing 24/7 on-call support for our applications.&lt;/p&gt;

&lt;p&gt;However, I found it difficult to identify scenarios and even harder to accurately reproduce them in a not-so-obvious way.&lt;/p&gt;

&lt;p&gt;At re:Invent this year, my favourite session of the week was on this exact topic. It wasn't recorded, so I'd like to share with you all what I took away from that session in this blog.&lt;/p&gt;




&lt;h2&gt;
  
  
  Examples of Game Day Events/Types
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Security Incidents&lt;/li&gt;
&lt;li&gt;Someone leaving the company/team&lt;/li&gt;
&lt;li&gt;Infrastructure outage&lt;/li&gt;
&lt;li&gt;Application outage&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  When should I run a Game Day?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Regular Cadence&lt;/strong&gt;&lt;br&gt;
Game days should be run regularly to help your team develop a muscle memory for incident response. Your company likely runs regular safety drills to ensure employees know what to do in the event of a fire, this is no different.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Architectural Changes&lt;/strong&gt;&lt;br&gt;
If you make substantial architecture or design changes to your application, it might also be worth running a game day to ensure all team members are aware of the changing points-of-failure to be aware of in applications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Team Changes&lt;/strong&gt;&lt;br&gt;
Someone joining or leaving a team can have a big impact on the team's ability to resolve. Often team members become a "crutch" in these types of scenarios. If your star incident resolver leaves you to need to ensure the team is capable and confident in supporting your application.&lt;/p&gt;

&lt;p&gt;The same can be said about a new joiner. Getting them up to speed quickly by running game days in a controlled environment is a great way to build confidence and should be considered part of the onboarding process for any team supporting applications in production.&lt;/p&gt;




&lt;h2&gt;
  
  
  Building Effective Game Days
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Part 1:&lt;/strong&gt; How can someone triaging this scenario effectively detect that it is happening?&lt;/p&gt;

&lt;p&gt;In order for a scenario to be considered valid, there must be an effective way of detecting that something is actually happening. Let's look at an example:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; &lt;em&gt;A Lambda function invoked through an API Gateway is producing a 5XX response code&lt;/em&gt;&lt;br&gt;
In this scenario, an effective troubleshooting method may be alerting for 5XX errors at an API Gateway level.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you are identifying scenarios and struggling to find effective methods of detecting them occurring, you should consider creating monitoring or processes to enable the detection of these.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Some more examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;IP Address exhaustion - Monitored using CloudWatch alarm&lt;/li&gt;
&lt;li&gt;Denial of Service - Abnormal traffic pattern alarm&lt;/li&gt;
&lt;li&gt;Lambda timeouts - Alerting off CloudWatch metric&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Part 2:&lt;/strong&gt; How can someone resolve this scenario in an effective and efficient manner?&lt;/p&gt;

&lt;p&gt;After identifying a scenario, we need to make sure that the team has the relevant skills and information to resolve the scenario in an effective and efficient manner. This can be as simple as knowing where to look at the status of alerts or ensuring they have the correct permissions to view logs. &lt;/p&gt;

&lt;p&gt;For more specific application-level errors runbooks can be useful to understand the meaning behind error messages, or knowing who to page at 3 am at when it's a pesky downstream service causing the error.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; &lt;em&gt;A team member is called for an out-of-hours system outage&lt;/em&gt;&lt;br&gt;
Upon receiving a call about a system outage, the team member knows the location of the alerting and runbook so that they can effectively respond to the presented issue. They can resolve this on their own without the need to escalate further.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If gaps have been identified here, before proceeding with the game day scenario make sure the necessary documentation exists and the entire team is aware of it&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Part 3:&lt;/strong&gt; As a "game master" how can this scenario be reproduced in a simulated and controlled environment?&lt;/p&gt;

&lt;p&gt;In order to trigger a scenario, it needs to be able to be reproducible.&lt;/p&gt;

&lt;p&gt;Let's look at some examples and how they can be reproduced:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;EC2 instance failure - Trigged using &lt;a href="https://docs.aws.amazon.com/fis/index.html" rel="noopener noreferrer"&gt;AWS Fault Injection Simulator&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Denial of Service - Triggered using &lt;a href="https://www.artillery.io/" rel="noopener noreferrer"&gt;Artillery&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Lambda Timeouts - Downstream service timeout can be mocked using &lt;a href="https://www.mock-server.com/" rel="noopener noreferrer"&gt;mock-server&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is often the piece I find most challenging, you may need to get creative. Currently, AWS FIS only supports EC2, ECS, EKS and RDS. As someone who works mostly with AWS-managed serverless services, I would love to see support for Lambda, API Gateway, CloudFront and DynamoDB so that this is less of a headache!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 4:&lt;/strong&gt; What is the category/classification of this scenario?&lt;/p&gt;

&lt;p&gt;Scenarios can be broadly grouped into two wide categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS outages/issues&lt;/li&gt;
&lt;li&gt;Application level outages/issues&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's a good idea to run a mix of both types of scenarios so that team members understand troubleshooting, resolutions or escalation paths for both types.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 5:&lt;/strong&gt; What is the estimated time a trained person should resolve this scenario in?&lt;/p&gt;

&lt;p&gt;We should assign each scenario two time values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Expected resolution time: The expected time a trained individual should resolve this issue in.&lt;/li&gt;
&lt;li&gt;Maximum run time: The maximum amount of time the scenario is allowed to run for.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The expected resolution time is a rough number, that should be adjusted if a repeat of a particular scenario is either too generous or too harsh of a time frame. It serves as an indicator that the training, processes and documentation available are sufficient to meet the demands of supporting the application.&lt;/p&gt;

&lt;p&gt;The maximum run time should be given enough buffer room to allow someone ample time to attempt to resolve a scenario. We assign this value to avoid creating frustration with the exercise going on for an endless amount of time. If certain scenarios are hitting this regularly this should be re-assessed.&lt;/p&gt;




&lt;h2&gt;
  
  
  Example Game Day Plan
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnuinw2adzvtxtjz8w9pd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnuinw2adzvtxtjz8w9pd.png" alt="Game Day reference architecture" width="800" height="501"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's take a look at this reference architecture to identify some potential game-day scenarios. This diagram depicts a CloudFront distribution, with a Route 53 domain and ACM certificate. An API gateway with two Lambda functions, one making HTTP calls to an external service and one accessing an RDS instance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs3ofhqsuhgwkkwromxhk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs3ofhqsuhgwkkwromxhk.png" alt="Game day reference architecture with identified scenarios" width="800" height="599"&gt;&lt;/a&gt;&lt;br&gt;
The diagram above depicts some example game day scenarios in red. I left some blank to give you (the reader) a chance to think of some potential scenarios.&lt;/p&gt;

&lt;p&gt;Let's break down some of the identified scenarios for this architecture:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Detection Method&lt;/th&gt;
&lt;th&gt;Reproduction Steps&lt;/th&gt;
&lt;th&gt;Classification&lt;/th&gt;
&lt;th&gt;Resolution Time/Max Runtime&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Misconfigured Route 53 record&lt;/td&gt;
&lt;td&gt;Traffic anomaly detection&lt;/td&gt;
&lt;td&gt;Facilitator alters configuration&lt;/td&gt;
&lt;td&gt;Application Level&lt;/td&gt;
&lt;td&gt;5/10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Expiring ACM certificate&lt;/td&gt;
&lt;td&gt;Certificate expiry alert&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Application Level&lt;/td&gt;
&lt;td&gt;10/20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Third party service outage&lt;/td&gt;
&lt;td&gt;Lambda error alerting&lt;/td&gt;
&lt;td&gt;Mock Server&lt;/td&gt;
&lt;td&gt;Application Level&lt;/td&gt;
&lt;td&gt;10/20&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Scenario 1:&lt;/strong&gt; A misconfigured Route 53 record. This is a pretty common occurrence when making DNS changes. It would be a user error that causes this type of outage. To reproduce this whoever is running the scenario could go in and make a change. The goal here is to troubleshoot and revert the change in a timely manner.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scenario 2:&lt;/strong&gt; An expiring ACM certificate. AWS will notify you of this well in advance. Simulating this might be difficult as certificate renewals are usually on a yearly basis. For this, it could be a "made-up" scenario, that you walk through the steps taken to remediate the issue.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scenario 3:&lt;/strong&gt; A third-party service outage. This could be simulated with a mock server. A mock outage could be simulated. In this situation identifying the correct downstream service and mocking out contacting the team that owns the service would be a good outcome.&lt;/p&gt;

&lt;p&gt;I have intentionally left some boxes blank if you want to think about this architecture and what other possible application or AWS-level outages could occur. I'd love to hear about them in the comments.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;You've run your game day, what's next you might ask?&lt;/p&gt;

&lt;p&gt;I would recommend collecting feedback on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tooling and processes&lt;/li&gt;
&lt;li&gt;Education and knowledge sharing&lt;/li&gt;
&lt;li&gt;Are there any application-level changes that could help mitigate this scenario?&lt;/li&gt;
&lt;li&gt;The overall running of the game day&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I would expect the following outputs of a successful game day:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Increased team confidence&lt;/li&gt;
&lt;li&gt;Improvements in documentation&lt;/li&gt;
&lt;li&gt;Improvements in alerting&lt;/li&gt;
&lt;li&gt;Potential architecture changes to make applications more resilient &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The entire process of game days is centred around continuous improvement. Bulletproof your plans, and increase your engineer's confidence and knowledge of your systems.&lt;/p&gt;

&lt;p&gt;If you found any of this useful please let me know, make sure to attempt to identify the extra scenarios in our example architecture and leave a comment with how you would conduct a game day for them!&lt;/p&gt;

</description>
      <category>gratitude</category>
    </item>
    <item>
      <title>How Well-Architected Enables Junior Engineers</title>
      <dc:creator>Gerald Stewart</dc:creator>
      <pubDate>Wed, 24 Nov 2021 16:55:06 +0000</pubDate>
      <link>https://dev.to/aws-builders/how-well-architected-enables-junior-engineers-24j</link>
      <guid>https://dev.to/aws-builders/how-well-architected-enables-junior-engineers-24j</guid>
      <description>&lt;h1&gt;
  
  
  What is Well-Architected 🤔
&lt;/h1&gt;

&lt;p&gt;Well-Architected describes the key concepts, design principles and architecture best practices for designing your cloud workloads. It balances best practices with business goals to determine the optimal outcome.&lt;/p&gt;

&lt;p&gt;Created by AWS Solutions Architects using the lessons Amazon has learnt from running thousands of systems at a massive scale, it enables developers to compare their workloads against the rigorous standards that AWS holds itself against.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pillars 🏛
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F99a3r795l1vgh5w3wk4d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F99a3r795l1vgh5w3wk4d.png" alt="image"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Credit to &lt;a href="https://www.awsgeek.com/The-5-Pillars-of-the-AWS-Well-Architected-Framework/" rel="noopener noreferrer"&gt;Jerry Hargrove&lt;/a&gt;&lt;/em&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Operational Excellence&lt;/strong&gt; - To be able to monitor and support workloads effectively, to enable continuous improvement and to deliver business value.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt; - Improving your security posture by taking advantage of Cloud technologies to protect your assets and systems.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reliability&lt;/strong&gt; - Ensuring your workload can perform it's intended function correctly and consistently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance Efficiency&lt;/strong&gt; - Ensuring appropriate resource allocation to enable performant systems and a positive end user experience.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost Optimisation&lt;/strong&gt; - Ensuring you are delivering business value at the lowest possible cost.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Lenses 🔎
&lt;/h2&gt;

&lt;p&gt;Lenses can be applied to a Well-Architected review to get additional specific questions targeting your type of application. Examples of lenses include Serverless, Machine Learning and SaaS. You can find more out about lenses &lt;a href="https://aws.amazon.com/architecture/well-architected/?wa-lens-whitepapers.sort-by=item.additionalFields.sortDate&amp;amp;wa-lens-whitepapers.sort-order=desc#AWS_Well-Architected_Lenses" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  How to Apply Well-Architected 👨‍🔧
&lt;/h1&gt;

&lt;p&gt;Well-Architected should be applied both continuously with reviews carried out at regular intervals. Understanding the pillars, core concepts and reasons behind the pillars of the Well-Architected framework can enable you to make better architecture decisions and avoid rewrites or large changes after a full-scale review has been carried out.&lt;/p&gt;

&lt;p&gt;The AWS Console has a "Well-Architected Tool" which allows you to track the health of your workloads. This is a free service and will ask questions based on your workload type to come up with an improvement plan.&lt;/p&gt;

&lt;h1&gt;
  
  
  How Well-Architected Enabled Me as a Junior Engineer 🙋‍♂️
&lt;/h1&gt;

&lt;p&gt;As a junior engineer, being involved in design discussions can be a daunting experience.&lt;/p&gt;

&lt;p&gt;A few months ago, I took time to take a deep dive into the AWS Well-Architected framework. The knowledge I gained by doing this has been invaluable.&lt;/p&gt;

&lt;p&gt;Well-Architected is a gold standard for best practices for building on AWS. It can also be applied to other types of applications.&lt;/p&gt;

&lt;p&gt;Instead of forming opinions about how something should be done, referring to the Well-Architected framework can often yield an AWS backed approach.&lt;/p&gt;

&lt;p&gt;The key differentiator between Well-Architected and self-formed opinions is that Well-Architected is the opinion of AWS Solutions Architects with many years of experience. My own self-formed opinions are only based on my experiences, which at the beginning of my career are limited.&lt;/p&gt;

&lt;p&gt;Being able to point to documentation to back up your points is invaluable.&lt;/p&gt;

&lt;p&gt;By following Well-Architected principles and applying them in everything I did I found myself over time becoming more involved in design discussions and more high-level work.&lt;/p&gt;

&lt;p&gt;Well-Architected gave me the &lt;em&gt;right questions&lt;/em&gt; to ask, to &lt;em&gt;drive discussions&lt;/em&gt; so we could &lt;em&gt;make better choices&lt;/em&gt; in the day-to-day development of our application.&lt;/p&gt;

&lt;p&gt;When weighing up technical decisions, think &lt;strong&gt;Well-Architected&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt; - Is this as secure as it could be, what's data are we storing, who has access?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost&lt;/strong&gt; - What's the potential cost impacts of this change, is it worth it, is the business aware?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Operational Excellence&lt;/strong&gt; - What monitoring do we need for this, what metrics should we be looking at, what level of fault tolerance should we allow?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt; - What will this do to performance, do we need to tweak/re-evaluate resource allocation as a result of this change?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reliability&lt;/strong&gt; - What happens if this fails, if a downstream system is down?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Asking these questions and driving conversations led to me progressing pretty quickly to becoming a Senior Software Engineer. &lt;/p&gt;

&lt;p&gt;I had plenty of examples of how I identified improvements to our application that I identified by applying Well-Architected.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;If I could recommend one topic of learning to a junior engineer or someone looking to up their game designing and building on AWS it would be to read the Well-Architected framework and understand how to apply it. &lt;/p&gt;

&lt;p&gt;If you or your team applies Well-Architected I'd love to hear how it made a difference to your application in the comments! &lt;/p&gt;

&lt;h1&gt;
  
  
  Learning Materials &amp;amp; Links ⛓
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/architecture/well-architected/" rel="noopener noreferrer"&gt;AWS Well-Architected Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.aws.training/Details/Curriculum?id=42037" rel="noopener noreferrer"&gt;AWS Well-Architected E-Learning&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/wellarchitected/latest/framework/welome.html" rel="noopener noreferrer"&gt;AWS Well-Architected Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/NFtZSvywRew?t=3073" rel="noopener noreferrer"&gt;My Well-Architected Talk&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>beginners</category>
      <category>cloud</category>
    </item>
    <item>
      <title>AWS CDK: Per-Environment Configuration Patterns</title>
      <dc:creator>Gerald Stewart</dc:creator>
      <pubDate>Wed, 26 May 2021 12:23:13 +0000</pubDate>
      <link>https://dev.to/aws-builders/aws-cdk-per-environment-configuration-patterns-48m6</link>
      <guid>https://dev.to/aws-builders/aws-cdk-per-environment-configuration-patterns-48m6</guid>
      <description>&lt;h1&gt;
  
  
  Introduction 👋
&lt;/h1&gt;

&lt;p&gt;Often projects will have different configuration values for each deployed environment. This could be feature toggles, URLs for third-party services or any number of other variables.&lt;/p&gt;

&lt;p&gt;With the AWS CDK, this is simple to configure. I have seen a few different approaches to this problem. In this blog I'll share a few suitable for use in TypeScript.&lt;/p&gt;

&lt;h1&gt;
  
  
  Method 1️⃣: Stack Configuration Function
&lt;/h1&gt;

&lt;p&gt;This approach uses a mapper function to return the configuration, you can see we have a single configuration property defined in the &lt;code&gt;EnvironmentConfig&lt;/code&gt; interface.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;IEnvironmentConfig&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;myEnvSpecificApiEndpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;environmentConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;IEnvironmentConfig&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;environmentMapper&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;myEnvSpecificApiEndpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;local&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;myEnvSpecificApiEndpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://dev.google.com/api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;myEnvSpecificApiEndpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://test.google.com/api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;production&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;myEnvSpecificApiEndpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://google.com/api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;environmentMapper&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;environmentName&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function would be called from the stack like this, &lt;code&gt;process.env.ENV_NAME&lt;/code&gt; would correspond to the environment name (replace this with your environment name variable for your chosen CI/CD pipeline) or default to local if undefined.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ENV_NAME&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;local&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;envConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IEnvironmentConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;environmentConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can then access the configuration like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;apiEndpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;envConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;myEnvSpecificApiEndpoint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;apiEndpoint&lt;/code&gt; variable is now ready to be used in your stack.&lt;/p&gt;

&lt;h1&gt;
  
  
  Method 2️⃣: CDK Runtime Context
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/cdk/latest/guide/context.html" rel="noopener noreferrer"&gt;CDK Context&lt;/a&gt; values are key-value pairs that can be associated with a stack or construct. There are a number of different ways these values can be configured, for more information on that see the link above to the documentation.&lt;/p&gt;

&lt;p&gt;In this example, I'm going to use &lt;code&gt;cdk.context.json&lt;/code&gt; file in the root of a CDK project to configure a stack.&lt;/p&gt;

&lt;p&gt;Here is an example &lt;code&gt;cdk.context.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"local"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"myEnvSpecificApiEndpoint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"https://dev.google.com/api"&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"myEnvSpecificApiEndpoint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"https://test.google.com/api"&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"production"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"myEnvSpecificApiEndpoint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"https://google.com/api"&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Interfaces can also be created to define the type of configuration data expected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;IEnvironmentConfig&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;myEnvSpecificApiEndpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These values can be accessed like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ENV_NAME&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;local&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;envConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IEnvironmentConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tryGetContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;apiEndpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;envConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;myEnvSpecificApiEndpoint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Method 3️⃣: Extending StackProps
&lt;/h1&gt;

&lt;p&gt;The AWS CDK &lt;a href="https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_core.StackProps.html" rel="noopener noreferrer"&gt;StackProps&lt;/a&gt; interface can be extended to add additional configuration properties. In this example we will extend the AWS CDK interface to add a property called &lt;code&gt;myEnvSpecificApiEndpoint&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;IEnvironmentConfig&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;StackProps&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;myEnvSpecificApiEndpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now in the stack initialisation file (located in the &lt;code&gt;bin&lt;/code&gt; directory) we can pass this in.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TheScheduledLambdaStack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TheScheduledLambdaStack&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,{&lt;/span&gt;
    &lt;span class="na"&gt;myEnvSpecificApiEndpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://dev.google.com/api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, the one downfall of this is that you still need to implement something like method 1 or 2 to configure it on a per-environment basis. This would look something like this for method 1:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TheScheduledLambdaStack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TheScheduledLambdaStack&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,{&lt;/span&gt;
    &lt;span class="na"&gt;myEnvSpecificApiEndpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;envConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;myEnvSpecificApiEndpoint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Conclusion 🤌
&lt;/h1&gt;

&lt;p&gt;Looking at all three methods, I personally like method 2. Until recently I was blissfully unaware the CDK had already 'solved' this problem for us.&lt;/p&gt;

&lt;p&gt;I live by the saying 'code is a liability' - the less code you manage the better.&lt;/p&gt;

&lt;p&gt;Do you..&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use any of these methods already?&lt;/li&gt;
&lt;li&gt;have a better way of doing it?&lt;/li&gt;
&lt;li&gt;have a different opinion on the optimal solution?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let me know in the comments!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cdk</category>
      <category>iac</category>
    </item>
    <item>
      <title>AWS CDK: Lambda Versioning</title>
      <dc:creator>Gerald Stewart</dc:creator>
      <pubDate>Fri, 23 Apr 2021 11:34:32 +0000</pubDate>
      <link>https://dev.to/aws-builders/aws-cdk-lambda-versioning-3p28</link>
      <guid>https://dev.to/aws-builders/aws-cdk-lambda-versioning-3p28</guid>
      <description>&lt;h1&gt;
  
  
  Introduction 👋
&lt;/h1&gt;

&lt;p&gt;I recently set out to investigate a few different ways we could version a Serverless API Gateway backed by Lambda functions. I've seen a few different blogs talking about this issue, but none in a CDK context.&lt;/p&gt;

&lt;p&gt;In this blog I'll walk through the strategy I devised to be able to support multiple versions of a Lambda function fronted by an API Gateway, with code examples.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Disclaimer&lt;/em&gt;&lt;/strong&gt;: This may not be the most optimal way to solve this issue, just my approach. If you have a better way I'd love to hear it!&lt;/p&gt;

&lt;h1&gt;
  
  
  The Problem 🤔
&lt;/h1&gt;

&lt;p&gt;You are developing a API Gateway backed by Lambda functions and you need to be able to make a breaking change to your API without breaking your consumers. Giving consumers time to use your old API version while they make the necessary changes to move the newest version.&lt;/p&gt;

&lt;p&gt;In this example, we do not care for making code changes to previous versions of the Lambda.&lt;/p&gt;

&lt;h1&gt;
  
  
  Lambda Versioning 🗄
&lt;/h1&gt;

&lt;p&gt;Lambda supports &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/configuration-versions.html" rel="noopener noreferrer"&gt;versioning&lt;/a&gt;, by default if no are versions explicitly defined the &lt;code&gt;$LATEST&lt;/code&gt; version will be overwritten. This is fine until you need to support two versions of a function simultaneously.&lt;/p&gt;

&lt;p&gt;Lambda versioning is also briefly covered in the &lt;a href="https://docs.aws.amazon.com/wellarchitected/latest/serverless-applications-lens/lambda-version-control.html" rel="noopener noreferrer"&gt;AWS Well-Architected Framework Serverless Lens&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Introducing my Serverless API versioning strategy:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fann38c6kluep7rc3sipf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fann38c6kluep7rc3sipf.png" alt="Lambda Versioning Strategy"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The above allows for active development of the &lt;code&gt;/v2/greeting&lt;/code&gt; endpoint while maintaining a active &lt;code&gt;/v1/greeting&lt;/code&gt; endpoint buying consumers some time. In my case the end goal is to shut off &lt;code&gt;/v1/greeting&lt;/code&gt; once consumers have made the necessary changes.&lt;/p&gt;

&lt;p&gt;Lets take a look at how this looks and works using the AWS CDK!&lt;/p&gt;

&lt;h3&gt;
  
  
  Lambda Code 🖥
&lt;/h3&gt;

&lt;p&gt;In this example, &lt;code&gt;helloLambda&lt;/code&gt; is returning a JSON response, this is what it will return in v1 of the Lambda:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;greeting&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello World!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;version&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;v1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The code below is from the CDK stack file:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;helloLambda&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;helloLambda&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODEJS_14_X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Code&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromAsset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lambda-fns&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;index.handler&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;helloLambdaV1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Version&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="nx"&gt;helloLambda&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;v1&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;helloLambda&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;helloLambdaV1Alias&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Alias&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="nx"&gt;helloLambda&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;v1&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;alias&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;aliasName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;helloLambda-v1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;helloLambdaV1&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Documentation: &lt;a href="https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.Function.html" rel="noopener noreferrer"&gt;Function&lt;/a&gt;, &lt;a href="https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.Version.html" rel="noopener noreferrer"&gt;Version&lt;/a&gt;, &lt;a href="https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.Alias.html" rel="noopener noreferrer"&gt;Alias&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This code snippet defines a new Lambda function &lt;code&gt;helloLambda&lt;/code&gt; and creates a new version &lt;code&gt;helloLambda-v1&lt;/code&gt;. An Alias is created &lt;code&gt;helloLambda-v1-alias&lt;/code&gt; that is associated with the version &lt;code&gt;helloLambda-v1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next we need to set up two API endpoints, going to different versions of our &lt;code&gt;helloLambda&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  API Gateway Code 🖥
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RestApi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;greeting-api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;v1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;v1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;v1Greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;v1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;greeting&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;v1Greeting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LambdaIntegration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;helloLambdaV1Alias&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Documentation: &lt;a href="https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-apigateway.RestApi.html" rel="noopener noreferrer"&gt;RestApi&lt;/a&gt;, &lt;a href="https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-apigateway.LambdaIntegration.html" rel="noopener noreferrer"&gt;LambdaIntegration&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This leaves us with a &lt;code&gt;/v1/greeting&lt;/code&gt; endpoint pointing to the alias &lt;code&gt;helloLambdaV1Alias&lt;/code&gt;. The next step is to add a &lt;code&gt;/v2/greeting&lt;/code&gt; endpoint allowing us to point to the &lt;code&gt;$LATEST&lt;/code&gt; version of the function so we can continue to develop the newest version of our API.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;v2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;v2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;v2Greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;v2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;greeting&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;v2Greeting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LambdaIntegration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;helloLambda&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Documentation: &lt;a href="https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-apigateway.RestApi.html" rel="noopener noreferrer"&gt;RestApi&lt;/a&gt;, &lt;a href="https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-apigateway.LambdaIntegration.html" rel="noopener noreferrer"&gt;LambdaIntegration&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It's important to note, if you want to point to &lt;code&gt;$LATEST&lt;/code&gt; do not define a new Lambda version. In the v2 code snippet above we reference &lt;code&gt;helloLambda&lt;/code&gt; directly instead of referencing the version &lt;code&gt;helloLambdaV1Alias&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Reference&lt;/code&gt;, &lt;code&gt;Alias&lt;/code&gt; and &lt;code&gt;Function&lt;/code&gt; are all accepted types for setting up a new &lt;code&gt;LambdaIntegration&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;As we now have &lt;code&gt;/v2/greeting&lt;/code&gt; pointing to &lt;code&gt;$LATEST&lt;/code&gt; version of the Lambda function, we can update the Lambda handler code to return a different hardcoded value:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;greeting&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello World!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;version&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$LATEST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Deploying this updated handler code would make it return &lt;code&gt;"version": "$LATEST"&lt;/code&gt; when calling the &lt;code&gt;/v2/greeting&lt;/code&gt; endpoint and return &lt;code&gt;"version": "v1"&lt;/code&gt; when calling the &lt;code&gt;/v1/greeting&lt;/code&gt; endpoint.&lt;/p&gt;

&lt;h1&gt;
  
  
  Summary 🤌
&lt;/h1&gt;

&lt;p&gt;This pattern is good for supporting basic API versioning. I was also amazed at how easy this was to accomplish with the AWS CDK and felt I had to share it!&lt;/p&gt;

&lt;p&gt;In order to clean up old Lambda versions you need to use the &lt;a href="https://docs.aws.amazon.com/cli/latest/reference/lambda/delete-function.html" rel="noopener noreferrer"&gt;AWS CLI lambda delete-function&lt;/a&gt; command specifying a qualifier to target specific versions you no longer need.&lt;/p&gt;

&lt;h3&gt;
  
  
  Alternative Solution 🤷‍♂️
&lt;/h3&gt;

&lt;p&gt;If you require backwards support for code changes I'm unaware of anything besides duplicating Lambda functions for each supported version that can accomplish that.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuymaj81kbg3f8qoktjdr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuymaj81kbg3f8qoktjdr.png" alt="Lambda Versioning Strategy - Dupe the Lambda"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This has it's drawbacks, duplicating code is never good. However if you do need full backwards support it can still work.&lt;/p&gt;

&lt;p&gt;If you've tried either of these strategies, or you have a better one I'd love to hear about it in the comments!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cdk</category>
      <category>versioning</category>
      <category>serverless</category>
    </item>
  </channel>
</rss>
