<?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: iAmSherif 💎</title>
    <description>The latest articles on DEV Community by iAmSherif 💎 (@iamsherif).</description>
    <link>https://dev.to/iamsherif</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%2F1069965%2F2956d1af-a76e-4604-8d57-3f180d14be94.jpeg</url>
      <title>DEV Community: iAmSherif 💎</title>
      <link>https://dev.to/iamsherif</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/iamsherif"/>
    <language>en</language>
    <item>
      <title>Migrating a Lambda to a Durable Lambda Function</title>
      <dc:creator>iAmSherif 💎</dc:creator>
      <pubDate>Sun, 01 Feb 2026 13:53:04 +0000</pubDate>
      <link>https://dev.to/iamsherif/migrating-a-lambda-to-a-durable-lambda-function-1ki2</link>
      <guid>https://dev.to/iamsherif/migrating-a-lambda-to-a-durable-lambda-function-1ki2</guid>
      <description>&lt;p&gt;I migrated an AWS Lambda function that simulates a patient health insurance verification workflow into a Durable Lambda execution. The function verifies a patient’s insurance and proceeds to schedule a health-check appointment only when the verification succeeds.&lt;/p&gt;

&lt;p&gt;At this point, you probably already understand what AWS Lambda is. This article focuses specifically on what changes when you migrate a Lambda function to a Durable Lambda, why those changes are necessary, and the errors you are likely to encounter if anything is misconfigured.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisite:&lt;/strong&gt;&lt;br&gt;
You should already understand how AWS Lambda works.&lt;/p&gt;

&lt;p&gt;Before discussing durability, it’s important to understand the workflow itself.&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%2Ftxyuc4m8q5yft2wxisky.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%2Ftxyuc4m8q5yft2wxisky.png" alt="Workflow illustration" width="800" height="182"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this flow, we can see that the function goes through a series of sequential steps to complete its work:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Validate Patient Information&lt;/strong&gt; - Checks if patient ID and name are provided&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check Insurance Database&lt;/strong&gt; - Simulates lookup in insurance database&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify Insurance Coverage&lt;/strong&gt; - Gets coverage details and limits&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authorize Health Check Procedures&lt;/strong&gt; - Determines which procedures are covered&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Schedule Health Checks&lt;/strong&gt; - Creates appointment schedule for authorized procedures.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each step depends on the successful completion of the previous one. This dependency chain is what makes durability valuable.&lt;/p&gt;

&lt;p&gt;Before we dive deep, let's talk a bit about Durable Lambda Function.&lt;/p&gt;
&lt;h2&gt;
  
  
  What is a Durable Lambda Function?
&lt;/h2&gt;

&lt;p&gt;A Durable Lambda function is still a Lambda function running inside the Lambda runtime. What changes is how execution is managed.&lt;/p&gt;

&lt;p&gt;A durable function can run for up to one year, maintaining progress across failures, restarts, and retries, without incurring wait-time charges. This is achieved through a mechanism called a durable execution.&lt;/p&gt;

&lt;p&gt;A durable execution uses checkpoints to track progress. If a failure occurs, the function is replayed from the beginning, but completed steps are skipped and their results reused.&lt;/p&gt;

&lt;p&gt;Durable Lambda exposes special operations, most notably &lt;code&gt;step&lt;/code&gt; and &lt;code&gt;wait&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;step&lt;/code&gt; executes business logic with built-in progress tracking and replay support.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;wait&lt;/code&gt; pauses execution without consuming compute, which is useful for long-running or human-in-the-loop workflows.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Lambda vs Durable Lambda?
&lt;/h3&gt;

&lt;p&gt;This is not a replacement. Durable Lambda still runs on Lambda.&lt;br&gt;
What changes is the execution model. Durable Lambda improves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Visibility into execution flow&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Recovery from failures&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Retry behavior&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Developer experience when working with long or multi-step workflows&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You are not switching platforms. You are adopting a stricter execution discipline.&lt;/p&gt;

&lt;p&gt;Now that we've had a brief understanding of Durable Lambda function, let's dive into migrating our lambda function to durable lambda.&lt;/p&gt;
&lt;h3&gt;
  
  
  What the Lambda Function Looked Like
&lt;/h3&gt;

&lt;p&gt;Before durability was introduced, the function followed a familiar sequential pattern. Everything happened inside a single invocation, and the only “state” was whatever lived in memory during execution.&lt;/p&gt;

&lt;p&gt;Conceptually, the Lambda looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&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="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&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;patientId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;patientId&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;patientName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;patientName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Validate patient information&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;patientId&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;patientName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid patient information&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="c1"&gt;// Check insurance&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hasInsurance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;checkInsuranceStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;patientId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;hasInsurance&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="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                    &lt;span class="nx"&gt;patientId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="nx"&gt;patientName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;REJECTED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Patient does not have valid health insurance.&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="c1"&gt;// Verify coverage&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;coverage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getInsuranceCoverage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;patientId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Authorize procedures&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authorizedProcedures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;authorizeHealthChecks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;coverage&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Schedule health checks&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;scheduledAppointments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;scheduleHealthChecks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nx"&gt;patientId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;authorizedProcedures&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="nx"&gt;patientId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;patientName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;APPROVED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;insuranceCoverage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;coverage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;authorizedProcedures&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;scheduledAppointments&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;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&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="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="nx"&gt;patientId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;patientName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ERROR&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&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="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code is readable and easy to reason about, but it hides a critical weakness.&lt;/p&gt;

&lt;p&gt;Every step is tightly coupled to the same execution. If the function times out, crashes, or is retried, everything restarts from the beginning. External systems are called again, and partial progress is lost.&lt;/p&gt;

&lt;p&gt;This is the exact problem Durable Lambda solves.&lt;/p&gt;

&lt;h3&gt;
  
  
  Introducing Durable Execution
&lt;/h3&gt;

&lt;p&gt;Below is the Durable Lambda version of the same function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;withDurableExecution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configureLogger&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;customLogger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;modeAware&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&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;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&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;patientId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;patientId&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;patientName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;patientName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Step 1: Validating patient information&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="nx"&gt;patientId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;patientName&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;patientId&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;patientName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid patient information&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;hasInsurance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;validate-patientid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stepContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;stepContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Validating user claims&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;checkInsuranceStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;patientId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt;

            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;hasInsurance&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="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                        &lt;span class="nx"&gt;patientId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="nx"&gt;patientName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;REJECTED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Patient does not have valid health insurance.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;coverage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;verify-insurance&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stepContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;stepContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Verify insurance coverage&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getInsuranceCoverage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;patientId&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;authorizedProcedures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;authorize-health-checks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stepContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nx"&gt;stepContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Authorize health check procedures&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;authorizeHealthChecks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;coverage&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;scheduledAppointments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;schedule-health-checks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stepContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nx"&gt;stepContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Schedule health checks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;scheduleHealthChecks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;patientId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;authorizedProcedures&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="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                    &lt;span class="nx"&gt;patientId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="nx"&gt;patientName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;APPROVED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;insuranceCoverage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;coverage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="nx"&gt;authorizedProcedures&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="nx"&gt;scheduledAppointments&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;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&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="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                    &lt;span class="nx"&gt;patientId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="nx"&gt;patientName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ERROR&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&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="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;At first glance, the business logic looks almost identical. That similarity is intentional. Durable Lambda is designed so you do not have to rewrite your domain logic from scratch.&lt;/p&gt;

&lt;p&gt;The real change is where durability is introduced.&lt;/p&gt;

&lt;h4&gt;
  
  
  What Actually Changed?
&lt;/h4&gt;

&lt;p&gt;The most important difference is the &lt;code&gt;withDurableExecution&lt;/code&gt; wrapper. This single addition changes the execution model of the function. Instead of treating the handler as a one-shot computation, it turns it into a resumable workflow. The function can now pause, fail, retry, and resume without losing progress.&lt;/p&gt;

&lt;p&gt;The second major change is the introduction of &lt;code&gt;context.step&lt;/code&gt; from DurableContext. In the Lambda, each async call simply executes and returns. In the durable version, every critical operation is wrapped in a named &lt;code&gt;step&lt;/code&gt;. That name is not cosmetic. It becomes the durable checkpoint that allows the runtime to remember, “this work has already been completed.”&lt;/p&gt;

&lt;p&gt;For example, insurance validation used to be just this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;checkInsuranceStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;patientId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the durable version, it becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;validate-patientid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;checkInsuranceStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;patientId&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 single change prevents duplicate calls when retries happen. If the function crashes after this step succeeds, Durable Lambda does not re-run it. It replays the stored result and moves forward.&lt;/p&gt;

&lt;p&gt;Logging also changes subtly but importantly. Instead of relying on global logging assumptions, logging is now tied to execution context and step context. This is why logging behavior felt different after migration. The function is no longer guaranteed to run once from top to bottom; parts of it may be replayed.&lt;/p&gt;

&lt;p&gt;THAT'S ALL FOR THE FUNCTION CODE REFACTORING&lt;/p&gt;

&lt;h2&gt;
  
  
  Infrastructure Configuration Matters
&lt;/h2&gt;

&lt;p&gt;Durable Lambda is not only about code. It requires explicit infrastructure configuration.&lt;br&gt;
Your lambda function configuration might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;patientHealthCheckFunction&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;PatientHealthCheckFunction&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_20_X&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="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-package&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&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="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;NODE_ENV&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;LOG_LEVEL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INFO&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above configuration, the function uses Lambda's NodeJS 20  runtime, identifies the handler, navigates to the function, set timeout limit, and attaches some env variables that would be used by the function code.&lt;br&gt;
When migrating to Durable Lambda, you must:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Use a supported runtime (Node.js 22 or 24)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Assign a role that allows checkpointing&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Configure durableConfig&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use versions and aliases&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Misconfigurations lead directly to runtime errors.&lt;/p&gt;

&lt;p&gt;I will walk you through actual errors that occurs when your durable function isn't configured properly and also we going to discuss each of their fixes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Error #1: Durable Execution Would Not Start&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The first failure happened immediately after deployment:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Unexpected payload provided to start the durable execution. Check your resource configurations to confirm the durability is set.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This error had nothing to do with business logic. Durable Lambda requires its configuration to be explicitly enabled in infrastructure. Without that configuration, the runtime treats the function like a normal Lambda and rejects the durable execution payload.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;durableConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;executionTimeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hours&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;retentionPeriod&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;days&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&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;Once configured with an execution timeout and retention period, the function was able to start durable execution correctly.&lt;/p&gt;

&lt;p&gt;This was the first signal that Durable Lambda is not just a code change; it is an execution contract enforced at the infrastructure level.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Error #2: Synchronous Invocation Still Has Limits&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After enabling durability, the next error appeared:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You cannot synchronously invoke a durable function with an &lt;code&gt;executionTimeout&lt;/code&gt; greater than 15 minutes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When invoked synchronously, a durable function must still complete within 15 minutes. Reducing the execution timeout resolved the issue.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;durableConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;executionTimeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;retentionPeriod&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;days&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&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 reinforced an important point: Durable Lambda adds persistence, not infinite runtime.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Error #3: Permission Error&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The next failure was caused by permission error:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Failed to checkpoint durable execution.  User is not authorized to perform &lt;code&gt;lambda:CheckpointDurableExecution&lt;/code&gt; on resource &lt;code&gt;arn:aws:…&lt;/code&gt; because no identity-based policy allows the &lt;code&gt;lambda:CheckpointDurableExecution&lt;/code&gt; action&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Durable Lambda requires explicit IAM permissions to store and retrieve execution state.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="nx"&gt;lambdaRole&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addToPolicy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;iam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PolicyStatement&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;:&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:CheckpointDurableExecution&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="s1"&gt;lambda:GetDurableExecutionState&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="s1"&gt;lambda:InvokeFunction&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;resources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="s2"&gt;`arn:aws:lambda:&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="nx"&gt;region&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&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="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:function:PatientHealthCheckStack*`&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="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without these permissions, durability silently fails.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed after migration
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Area&lt;/th&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After Durable Lambda&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;State handling&lt;/td&gt;
&lt;td&gt;Stateless&lt;/td&gt;
&lt;td&gt;Persistent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Retries&lt;/td&gt;
&lt;td&gt;Restart entire flow&lt;/td&gt;
&lt;td&gt;Resume from failure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Invocation rules&lt;/td&gt;
&lt;td&gt;Flexible&lt;/td&gt;
&lt;td&gt;Strict but safer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Versioning&lt;/td&gt;
&lt;td&gt;Optional&lt;/td&gt;
&lt;td&gt;Required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Observability&lt;/td&gt;
&lt;td&gt;Simple&lt;/td&gt;
&lt;td&gt;Needs discipline&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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

&lt;p&gt;Migrating to Durable Lambda did not make the system simpler; it made it more explicit.&lt;/p&gt;

&lt;p&gt;Failures stopped being destructive. Retries stopped being accidental. Progress became something the system could reason about instead of guess. The workflow shifted from “hope this finishes” to “this will eventually complete correctly.”&lt;/p&gt;

&lt;p&gt;Durable Lambda is not something you reach for by default. But when your Lambda function starts behaving like a workflow—multi-step, failure-prone, and externally dependent, durability stops being optional.&lt;/p&gt;

&lt;p&gt;At that point, it becomes a design decision about correctness.&lt;/p&gt;

&lt;p&gt;And in systems like healthcare workflows, correctness is the only acceptable outcome.&lt;/p&gt;

&lt;p&gt;——————————————&lt;/p&gt;

&lt;p&gt;&lt;em&gt;For more articles, follow my social handles:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/sherifawofiranye" rel="noopener noreferrer"&gt;&lt;em&gt;LinkedIn&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.x.com/sherif_on_x" rel="noopener noreferrer"&gt;&lt;em&gt;Twitter&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/iamsherif"&gt;&lt;em&gt;Dev&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@awofiranyesherif4" rel="noopener noreferrer"&gt;&lt;em&gt;Medium&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>lambda</category>
      <category>serverless</category>
      <category>aws</category>
      <category>programming</category>
    </item>
    <item>
      <title>A Step-by-Step Guide to Deploying CrewAI on Amazon Bedrock AgentCore</title>
      <dc:creator>iAmSherif 💎</dc:creator>
      <pubDate>Sun, 03 Aug 2025 21:12:02 +0000</pubDate>
      <link>https://dev.to/iamsherif/a-step-by-step-guide-to-deploying-crewai-on-amazon-bedrock-agentcore-293n</link>
      <guid>https://dev.to/iamsherif/a-step-by-step-guide-to-deploying-crewai-on-amazon-bedrock-agentcore-293n</guid>
      <description>&lt;p&gt;In 2024, I built &lt;a href="https://main.dumvtvqtcpc4p.amplifyapp.com/" rel="noopener noreferrer"&gt;Curiouser&lt;/a&gt; an agent-to-agent (A2A) application using &lt;a href="https://crewai.com/" rel="noopener noreferrer"&gt;CrewAI&lt;/a&gt; with the Ollama LLM. It was my first real experience orchestrating multiple agents in a single app. As someone curious about agentic frameworks, CrewAI felt intuitive and developer-friendly.&lt;/p&gt;

&lt;p&gt;But I ran into limitations. I was running the application locally on my 8GB RAM AMD Ryzen laptop with a 256GB SSD, and it will take an average of 2–3 hours to complete a run (no bluff). Plus, I couldn’t take it beyond my local machine.&lt;/p&gt;

&lt;p&gt;Then AWS announced &lt;strong&gt;Amazon Bedrock AgentCore&lt;/strong&gt; at the New York Summit — and it felt like it was built for people like me. It's a &lt;strong&gt;serverless runtime&lt;/strong&gt; for deploying and operating AI agents securely at scale, using any framework, including CrewAI, LangGraph, LlamaIndex, and Strands Agents, as well as any foundation model in or outside of Amazon Bedrock, without managing infrastructure. So I decided to migrate my local CrewAI app to production using this new service.&lt;/p&gt;

&lt;p&gt;This blog post is a step-by-step guide for doing exactly that.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: This guide assumes you already have a working CrewAI application. I’ll only walk you through the changes needed to get it running on Bedrock AgentCore.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  What I Built
&lt;/h3&gt;

&lt;p&gt;I built &lt;strong&gt;Curiouser&lt;/strong&gt; — a multi-agent AI application designed for curious minds.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It provides detailed yet concise summaries of tech topics.&lt;/li&gt;
&lt;li&gt;It generates test questions to help you evaluate your understanding.&lt;/li&gt;
&lt;li&gt;It uses three cooperating agents, each with a different role.&lt;/li&gt;
&lt;li&gt;I switched from Ollama to the Amazon Bedrock Nova Pro model.&lt;/li&gt;
&lt;li&gt;It also stores user-generated content in Amazon S3.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;To follow along, you'll need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A working CrewAI app&lt;/li&gt;
&lt;li&gt;An AWS account with access to:

&lt;ul&gt;
&lt;li&gt;Amazon Bedrock&lt;/li&gt;
&lt;li&gt;Bedrock AgentCore&lt;/li&gt;
&lt;li&gt;S3&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Python 3.10+&lt;/li&gt;

&lt;li&gt;Docker installed and running&lt;/li&gt;

&lt;li&gt;AWS CLI installed and configured&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;bedrock-agentcore&lt;/code&gt; and &lt;code&gt;bedrock-agentcore-starter-toolkit&lt;/code&gt; Python packages&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 1 - Update Your Agents to Use a Bedrock-Supported LLM
&lt;/h3&gt;

&lt;p&gt;Bedrock AgentCore supports only Amazon Bedrock-compatible foundational models. You’ll need to update your CrewAI agents to use one of these.&lt;/p&gt;

&lt;p&gt;Check out the &lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/models-supported.html" rel="noopener noreferrer"&gt;supported models here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2 - Create a Remote Entrypoint for Bedrock AgentCore
&lt;/h3&gt;

&lt;p&gt;We'll convert your local app into a remote one by modifying the entrypoint. Here's what to do:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Import AgentCore:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;   &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;bedrock_agentcore.runtime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BedrockAgentCoreApp&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Initialize the runtime app:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;   &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BedrockAgentCoreApp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Define the entrypoint handler:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;   &lt;span class="nd"&gt;@app.entrypoint&lt;/span&gt;
   &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;app_entry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
       &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Handle agent invocations&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
       &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
           &lt;span class="n"&gt;user_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prompt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Web3&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
           &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;crew&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;kickoff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;topic&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;user_message&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
           &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;result&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
           &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Run the app:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
       &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;AgentCore automatically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sets up an HTTP server on port 8080&lt;/li&gt;
&lt;li&gt;Exposes &lt;code&gt;/invocations&lt;/code&gt; and &lt;code&gt;/ping&lt;/code&gt; endpoints&lt;/li&gt;
&lt;li&gt;Manages content types, responses, and errors&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 3 - Configure IAM Role for AgentCore
&lt;/h3&gt;

&lt;p&gt;You’ll need a dedicated IAM role that allows your agent to run in the cloud. Below is a Bash script I wrote to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a trust policy&lt;/li&gt;
&lt;li&gt;Create permissions policy&lt;/li&gt;
&lt;li&gt;Attach the permissions policy&lt;/li&gt;
&lt;li&gt;Grant access to ECR, Bedrock Agentcore, and Bedrock&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The script also configures your agent with AgentCore:&lt;br&gt;
&lt;code&gt;agentcore configure --entrypoint src/curiouser/main.py -er &amp;lt;ROLE_ARN&amp;gt;&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="c"&gt;# Setup script for CrewAI with Amazon Bedrock AgentCore&lt;/span&gt;
&lt;span class="c"&gt;# This script creates the necessary IAM role and configures agentcore&lt;/span&gt;

&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt;  &lt;span class="c"&gt;# Exit on any error&lt;/span&gt;

&lt;span class="c"&gt;# Configuration variables&lt;/span&gt;
&lt;span class="nv"&gt;ROLE_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Curioser-CrewAI-BedrockAgentCore-Role"&lt;/span&gt;
&lt;span class="nv"&gt;POLICY_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Curioser-CrewAI-BedrockAgentCore-Policy"&lt;/span&gt;
&lt;span class="nv"&gt;TRUST_POLICY_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"trust-policy.json"&lt;/span&gt;
&lt;span class="nv"&gt;PERMISSIONS_POLICY_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"permissions-policy.json"&lt;/span&gt;
&lt;span class="nv"&gt;ENTRYPOINT_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"src/curiouser/main.py"&lt;/span&gt;


&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'\033[0m'&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"Setting up CrewAI with Amazon Bedrock AgentCore&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Check if AWS CLI is installed and configured&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nb"&gt;command&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; aws &amp;amp;&amp;gt; /dev/null&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"❌ AWS CLI is not installed. Please install it first.&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# Get AWS account ID and region&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"📋 Getting AWS account information...&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;ACCOUNT_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;aws sts get-caller-identity &lt;span class="nt"&gt;--query&lt;/span&gt; Account &lt;span class="nt"&gt;--output&lt;/span&gt; text&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;REGION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;aws configure get region&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$REGION&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"⚠️  No default region set. Using us-east-1&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nv"&gt;REGION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"us-east-1"&lt;/span&gt;
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"✓ Account ID: &lt;/span&gt;&lt;span class="nv"&gt;$ACCOUNT_ID&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"✓ Region: &lt;/span&gt;&lt;span class="nv"&gt;$REGION&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Create trust policy for the IAM role&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"📝 Creating trust policy..."&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$TRUST_POLICY_FILE&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AssumeRolePolicy",
      "Effect": "Allow",
      "Principal": {
        "Service": "bedrock-agentcore.amazonaws.com"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
            "StringEquals": {
                "aws:SourceAccount": "&lt;/span&gt;&lt;span class="nv"&gt;$ACCOUNT_ID&lt;/span&gt;&lt;span class="sh"&gt;"
            },
            "ArnLike": {
                "aws:SourceArn": "arn:aws:bedrock-agentcore:&lt;/span&gt;&lt;span class="nv"&gt;$REGION&lt;/span&gt;&lt;span class="sh"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;$ACCOUNT_ID&lt;/span&gt;&lt;span class="sh"&gt;:*"
            }
       }
    }
  ]
}
&lt;/span&gt;&lt;span class="no"&gt;
EOF

&lt;/span&gt;&lt;span class="c"&gt;# Create permissions policy with dynamic values&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"📝 Creating permissions policy..."&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$PERMISSIONS_POLICY_FILE&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "ECRImageAccess",
            "Effect": "Allow",
            "Action": [
                "ecr:BatchGetImage",
                "ecr:GetDownloadUrlForLayer"
            ],
            "Resource": [
                "arn:aws:ecr:&lt;/span&gt;&lt;span class="nv"&gt;$REGION&lt;/span&gt;&lt;span class="sh"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;$ACCOUNT_ID&lt;/span&gt;&lt;span class="sh"&gt;:repository/*"
            ]        
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:DescribeLogStreams",
                "logs:CreateLogGroup"
            ],
            "Resource": [
                "arn:aws:logs:&lt;/span&gt;&lt;span class="nv"&gt;$REGION&lt;/span&gt;&lt;span class="sh"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;$ACCOUNT_ID&lt;/span&gt;&lt;span class="sh"&gt;:log-group:/aws/bedrock-agentcore/runtimes/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:DescribeLogGroups"
            ],
            "Resource": [
                "arn:aws:logs:&lt;/span&gt;&lt;span class="nv"&gt;$REGION&lt;/span&gt;&lt;span class="sh"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;$ACCOUNT_ID&lt;/span&gt;&lt;span class="sh"&gt;:log-group:*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": [
                "arn:aws:logs:&lt;/span&gt;&lt;span class="nv"&gt;$REGION&lt;/span&gt;&lt;span class="sh"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;$ACCOUNT_ID&lt;/span&gt;&lt;span class="sh"&gt;:log-group:/aws/bedrock-agentcore/runtimes/*:log-stream:*"
            ]
        },
        {
            "Sid": "ECRTokenAccess",
            "Effect": "Allow",
            "Action": [
                "ecr:GetAuthorizationToken"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow", 
            "Action": [ 
                "xray:PutTraceSegments", 
                "xray:PutTelemetryRecords", 
                "xray:GetSamplingRules", 
                "xray:GetSamplingTargets"
            ],
            "Resource": [ "*" ] 
        },
        {
            "Effect": "Allow",
            "Resource": "*",
            "Action": "cloudwatch:PutMetricData",
            "Condition": {
                "StringEquals": {
                    "cloudwatch:namespace": "bedrock-agentcore"
                }
            }
        },
        {
            "Sid": "GetAgentAccessToken",
            "Effect": "Allow",
            "Action": [
                "bedrock-agentcore:GetWorkloadAccessToken",
                "bedrock-agentcore:GetWorkloadAccessTokenForJWT",
                "bedrock-agentcore:GetWorkloadAccessTokenForUserId"
            ],
            "Resource": [
                "arn:aws:bedrock-agentcore:&lt;/span&gt;&lt;span class="nv"&gt;$REGION&lt;/span&gt;&lt;span class="sh"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;$ACCOUNT_ID&lt;/span&gt;&lt;span class="sh"&gt;:workload-identity-directory/default",
                "arn:aws:bedrock-agentcore:&lt;/span&gt;&lt;span class="nv"&gt;$REGION&lt;/span&gt;&lt;span class="sh"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;$ACCOUNT_ID&lt;/span&gt;&lt;span class="sh"&gt;:workload-identity-directory/default/workload-identity/agentName-*"
            ]
        },
        {
            "Sid": "BedrockModelInvocation", 
            "Effect": "Allow", 
            "Action": [ 
                "bedrock:InvokeModel", 
                "bedrock:InvokeModelWithResponseStream"
            ], 
            "Resource": [
                "arn:aws:bedrock:*::foundation-model/*",
                "arn:aws:bedrock:&lt;/span&gt;&lt;span class="nv"&gt;$REGION&lt;/span&gt;&lt;span class="sh"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;$ACCOUNT_ID&lt;/span&gt;&lt;span class="sh"&gt;:*"
            ]
        }
    ]
}
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="c"&gt;# Check if role already exists&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"🔍 Checking if IAM role exists...&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;aws iam get-role &lt;span class="nt"&gt;--role-name&lt;/span&gt; &lt;span class="nv"&gt;$ROLE_NAME&lt;/span&gt; &amp;amp;&amp;gt; /dev/null&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"⚠️  Role &lt;/span&gt;&lt;span class="nv"&gt;$ROLE_NAME&lt;/span&gt;&lt;span class="s2"&gt; already exists. Updating policies...&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

    &lt;span class="c"&gt;# Update the role's trust policy&lt;/span&gt;
    aws iam update-assume-role-policy &lt;span class="nt"&gt;--role-name&lt;/span&gt; &lt;span class="nv"&gt;$ROLE_NAME&lt;/span&gt; &lt;span class="nt"&gt;--policy-document&lt;/span&gt; file://&lt;span class="nv"&gt;$TRUST_POLICY_FILE&lt;/span&gt;

    &lt;span class="c"&gt;# Delete existing inline policy if it exists&lt;/span&gt;
    aws iam delete-role-policy &lt;span class="nt"&gt;--role-name&lt;/span&gt; &lt;span class="nv"&gt;$ROLE_NAME&lt;/span&gt; &lt;span class="nt"&gt;--policy-name&lt;/span&gt; &lt;span class="nv"&gt;$POLICY_NAME&lt;/span&gt; &amp;amp;&amp;gt; /dev/null &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true
&lt;/span&gt;&lt;span class="k"&gt;else
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"🔨 Creating IAM role..."&lt;/span&gt;
    aws iam create-role &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;--role-name&lt;/span&gt; &lt;span class="nv"&gt;$ROLE_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;--assume-role-policy-document&lt;/span&gt; file://&lt;span class="nv"&gt;$TRUST_POLICY_FILE&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;--description&lt;/span&gt; &lt;span class="s2"&gt;"IAM role for CrewAI with Bedrock AgentCore"&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# Attach the permissions policy&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;YELLOW&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;📎 Attaching permissions policy...&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
aws iam put-role-policy &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--role-name&lt;/span&gt; &lt;span class="nv"&gt;$ROLE_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--policy-name&lt;/span&gt; &lt;span class="nv"&gt;$POLICY_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--policy-document&lt;/span&gt; file://&lt;span class="nv"&gt;$PERMISSIONS_POLICY_FILE&lt;/span&gt;

&lt;span class="c"&gt;# Get the role ARN&lt;/span&gt;
&lt;span class="nv"&gt;ROLE_ARN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;aws iam get-role &lt;span class="nt"&gt;--role-name&lt;/span&gt; &lt;span class="nv"&gt;$ROLE_NAME&lt;/span&gt; &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'Role.Arn'&lt;/span&gt; &lt;span class="nt"&gt;--output&lt;/span&gt; text&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"✓ IAM Role ARN: &lt;/span&gt;&lt;span class="nv"&gt;$ROLE_ARN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Check if src/curiouser/main.py exists&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ENTRYPOINT_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"✓ Entrypoint file &lt;/span&gt;&lt;span class="nv"&gt;$ENTRYPOINT_FILE&lt;/span&gt;&lt;span class="s2"&gt; already exists and is configured for Bedrock AgentCore"&lt;/span&gt;
&lt;span class="k"&gt;else
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"❌ Entrypoint file &lt;/span&gt;&lt;span class="nv"&gt;$ENTRYPOINT_FILE&lt;/span&gt;&lt;span class="s2"&gt; not found. Please ensure your CrewAI project structure is correct."&lt;/span&gt;
    &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# Wait a moment for IAM role to propagate&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"⏳ Waiting for IAM role to propagate..."&lt;/span&gt;
&lt;span class="nb"&gt;sleep &lt;/span&gt;10

&lt;span class="c"&gt;# Configure agentcore&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"🔧 Configuring agentcore..."&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="nb"&gt;command&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; agentcore &amp;amp;&amp;gt; /dev/null&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;agentcore configure &lt;span class="nt"&gt;--entrypoint&lt;/span&gt; &lt;span class="nv"&gt;$ENTRYPOINT_FILE&lt;/span&gt; &lt;span class="nt"&gt;-er&lt;/span&gt; &lt;span class="nv"&gt;$ROLE_ARN&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"✓ AgentCore configured successfully!"&lt;/span&gt;
&lt;span class="k"&gt;else
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"❌ agentcore command not found. Please install the Bedrock AgentCore CLI first."&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"💡 You can install it with: pip install bedrock-agentcore-cli"&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"📋 Manual configuration command:"&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"agentcore configure --entrypoint &lt;/span&gt;&lt;span class="nv"&gt;$ENTRYPOINT_FILE&lt;/span&gt;&lt;span class="s2"&gt; -er &lt;/span&gt;&lt;span class="nv"&gt;$ROLE_ARN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;

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

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Attach the policy that your project needs&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Step 4 - Generate Docker Configuration with AgentCore command
&lt;/h3&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%2F9p8cz0ee3hhdz6wn8mkg.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%2F9p8cz0ee3hhdz6wn8mkg.png" alt="AgentCore Configure" width="800" height="349"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;agentcore configure &lt;span class="nt"&gt;--entrypoint&lt;/span&gt; src/curiouser/main.py &lt;span class="nt"&gt;-er&lt;/span&gt; &amp;lt;ROLE_ARN&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generate a Dockerfile and &lt;code&gt;.bedrock_agentcore.yaml&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Create a .bedrock_agentcore.yaml configuration file&lt;/li&gt;
&lt;li&gt;Prepare our application for containerization&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Important Fix
&lt;/h4&gt;

&lt;p&gt;The generated Dockerfile doesn’t install &lt;code&gt;bedrock_agentcore&lt;/code&gt;, so be sure to add else you will run into a dependency error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;RUN &lt;/span&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;bedrock_agentcore
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your Dockerfile should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; public.ecr.aws/docker/library/python:3.10-slim&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; .
&lt;span class="k"&gt;RUN &lt;/span&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;bedrock_agentcore
&lt;span class="k"&gt;RUN &lt;/span&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;aws-opentelemetry-distro&amp;gt;&lt;span class="o"&gt;=&lt;/span&gt;0.10.0

&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; AWS_REGION=&amp;lt;your-region&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; AWS_DEFAULT_REGION=&amp;lt;your-region&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; DOCKER_CONTAINER=1&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;useradd &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; 1000 bedrock_agentcore
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; bedrock_agentcore&lt;/span&gt;

&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 8080&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["opentelemetry-instrument", "python", "-m", "src.app.main"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 5 - Launch the Agent to the Cloud
&lt;/h3&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%2Fblu7djvek0c2yi3yfp7r.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%2Fblu7djvek0c2yi3yfp7r.png" alt="Launch the Agent to the Cloud" width="800" height="264"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once everything is ready, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;agentcore launch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build the Docker image&lt;/li&gt;
&lt;li&gt;Push it to Amazon ECR&lt;/li&gt;
&lt;li&gt;Create a Bedrock AgentCore runtime&lt;/li&gt;
&lt;li&gt;And deploy your agent to the cloud&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 6 - Test Your Deployed Agent
&lt;/h3&gt;

&lt;p&gt;Use the CLI to invoke your agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;agentcore invoke &lt;span class="s1"&gt;'{"prompt": "Hello"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or test directly from the AWS Console.&lt;/p&gt;

&lt;h3&gt;
  
  
  Final Thoughts
&lt;/h3&gt;

&lt;p&gt;That’s it, you’ve just seen how to take a multi-agent CrewAI application from local development to a cloud-native, production-ready deployment using Amazon Bedrock AgentCore.&lt;/p&gt;

&lt;p&gt;Personally, moving from a painfully slow, local setup on limited hardware to a serverless runtime that scales, monitors, and secures my workload automatically was a game-changer. No more babysitting long processes or worrying about whether my laptop will crash before the task finishes. With Amazon Bedrock AgentCore, deployment is fast, observability is built-in, and your agentic logic becomes accessible from anywhere, anytime.&lt;/p&gt;

&lt;p&gt;For developers building serious agentic applications, especially multi-agent systems with orchestration and external data workflows. Amazon Bedrock AgentCore unlocks scalability and reliability without the traditional ops overhead. And because it’s part of the AWS ecosystem, integrating other services like S3, CloudWatch, and IAM is straightforward and secure.&lt;/p&gt;

&lt;p&gt;Whether you’re:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Building a knowledge assistant like &lt;a href="https://main.dumvtvqtcpc4p.amplifyapp.com/" rel="noopener noreferrer"&gt;Curiouser&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;Orchestrating tools and LLMs across complex workflows,&lt;/li&gt;
&lt;li&gt;Experimenting with autonomous agents in a safe and scalable environment,&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Amazon Bedrock AgentCore gives you a strong foundation to focus on the intelligence of your application, not the plumbing.&lt;/p&gt;

&lt;p&gt;If you’ve already got a local CrewAI project up and running, there’s no better time to bring it to life in the cloud.&lt;/p&gt;

&lt;p&gt;Let me know if you try this out or run into any blockers — always happy to connect with fellow builders.&lt;/p&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/bedrock-agentcore/" rel="noopener noreferrer"&gt;Amazon Bedrock AgentCore Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/awslabs/amazon-bedrock-agentcore-samples.git" rel="noopener noreferrer"&gt;Amazon Bedrock AgentCore GitHub Samples&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/models-supported.html" rel="noopener noreferrer"&gt;Supported Foundation Models on Bedrock&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.crewai.com/en/introduction" rel="noopener noreferrer"&gt;CrewAI Framework Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/what-is-bedrock.html" rel="noopener noreferrer"&gt;Amazon Bedrock Developer Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;——————————————&lt;/p&gt;

&lt;p&gt;&lt;em&gt;For more articles, follow my social handles:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/sherifawofiranye" rel="noopener noreferrer"&gt;&lt;em&gt;LinkedIn&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.x.com/sherif_on_x" rel="noopener noreferrer"&gt;&lt;em&gt;Twitter&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/iamsherif"&gt;&lt;em&gt;Dev&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@awofiranyesherif4" rel="noopener noreferrer"&gt;&lt;em&gt;Medium&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>bedrockagentcore</category>
      <category>crewai</category>
      <category>aws</category>
    </item>
    <item>
      <title>How to capture data changes in DynamoDB using Streams and Lambda (Node.js + AWS CDK)</title>
      <dc:creator>iAmSherif 💎</dc:creator>
      <pubDate>Tue, 15 Jul 2025 00:18:34 +0000</pubDate>
      <link>https://dev.to/iamsherif/how-to-capture-data-changes-in-dynamodb-using-streams-and-lambda-nodejs-aws-cdk-4n9n</link>
      <guid>https://dev.to/iamsherif/how-to-capture-data-changes-in-dynamodb-using-streams-and-lambda-nodejs-aws-cdk-4n9n</guid>
      <description>&lt;p&gt;One of the biggest advantages of serverless services is their event-driven nature. When something (an event) happens, another service reacts. DynamoDB is a serverless NoSQL database that fits perfectly into this pattern. It allows you to build scalable, event-driven applications that respond to changes in your data in near real time.&lt;/p&gt;

&lt;p&gt;In this article, I’ll show you how to capture data changes in DynamoDB using DynamoDB Streams, and then use the stream as an event source to a Lambda function, which then logs the stream information to CloudWatch Logs, all implemented using Node.js and AWS CDK as Iac.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Capture Data Changes?
&lt;/h3&gt;

&lt;p&gt;Before we dive into the implementation, let’s consider a few use cases where capturing data changes can be valuable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Audit logging: Keep track of item-level changes for compliance or debugging.&lt;/li&gt;
&lt;li&gt;Triggering side effects: Send notifications, update search indexes, or replicate data in real time.&lt;/li&gt;
&lt;li&gt;Analytics: Track user behavior or system events as they happen.&lt;/li&gt;
&lt;li&gt;Data synchronization: Sync changes between microservices or external systems.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How DynamoDB Streams Work
&lt;/h3&gt;

&lt;p&gt;When you enable Streams on a DynamoDB table, DynamoDB records every item-level change (creates, updates, and deletes) in a time-ordered sequence.&lt;/p&gt;

&lt;p&gt;Each stream record contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The primary key of the modified item&lt;/li&gt;
&lt;li&gt;Metadata about the operation (INSERT, MODIFY, REMOVE)&lt;/li&gt;
&lt;li&gt;Optional “before” and “after” images of the data (if configured)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These stream records are stored for up to 24 hours and can be read by AWS services like Lambda, which you can set up to react to each change automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  What We’ll Build
&lt;/h3&gt;

&lt;p&gt;We’ll create:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A DynamoDB table with Streams enabled&lt;/li&gt;
&lt;li&gt;A Lambda function that listens to the stream&lt;/li&gt;
&lt;li&gt;Logging of the change details to CloudWatch Logs&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  So Let’s Get Started
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Define a DynamoDB Table with Stream Enabled
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AttributeType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;StreamViewType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Table&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-cdk-lib/aws-dynamodb&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;table&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;Table&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;MyTable&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;partitionKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AttributeType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STRING&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;StreamViewType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NEW_AND_OLD_IMAGES&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Enables streams with both before/after images&lt;/span&gt;
  &lt;span class="c1"&gt;// Other configuration&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Stream View Types
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;StreamViewType&lt;/code&gt; determines what data is recorded in the stream for each item change:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;KEYS_ONLY&lt;/code&gt; – Only the primary key attributes are written to the stream.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;NEW_IMAGE&lt;/code&gt; – The entire item, as it appears after the modification, is written to the stream.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;OLD_IMAGE&lt;/code&gt; – The item as it appeared before the modification is written to the stream.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;NEW_AND_OLD_IMAGES&lt;/code&gt; – Both the new and old versions of the item are included.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  2. Create a Lambda Function to Handle Stream Events
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;Function&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;Code&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-cdk-lib/aws-lambda&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;LambdaIntegration&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-cdk-lib/aws-apigateway&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&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;streamHandler&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;StreamHandlerFunction&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_20_X&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="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="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&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&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Sample &lt;code&gt;index.js&lt;/code&gt; Lambda code:&lt;/strong&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;unmarshall&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@aws-sdk/util-dynamodb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for &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;record&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Records&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;newImage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewImage&lt;/span&gt;
      &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;unmarshall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewImage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&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;oldImage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OldImage&lt;/span&gt;
      &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;unmarshall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OldImage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Event Type:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eventName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;New Image:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newImage&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Old Image:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;oldImage&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&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;h4&gt;
  
  
  Why do we use &lt;code&gt;unmarshall&lt;/code&gt;?
&lt;/h4&gt;

&lt;p&gt;When DynamoDB Streams triggers our Lambda function, it passes the item images in DynamoDB JSON format, which looks like this:&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;"id"&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;span class="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"asdf"&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;"uuid"&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;span class="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"foo"&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;"status"&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;span class="nl"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"new"&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;To work with standard JavaScript objects, we use the &lt;code&gt;unmarshall&lt;/code&gt; utility from &lt;code&gt;@aws-sdk/util-dynamodb&lt;/code&gt;. This transforms the DynamoDB JSON into a regular JavaScript object:&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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"asdf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"uuid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"foo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"new"&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;This makes it easier to log or manipulate the data in our code.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Connect the Stream to Lambda
&lt;/h4&gt;

&lt;p&gt;To allow our Lambda function to process events from the DynamoDB stream, we need to do two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Grant the Lambda the proper execution role permission to read from the stream&lt;/li&gt;
&lt;li&gt;Register the DynamoDB table as an event source
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Grant the Lambda the proper execution role permission to read from the stream&lt;/span&gt;
&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;grantStreamRead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;streamHandler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Attach DynamoDB stream as an event source&lt;/span&gt;
&lt;span class="nx"&gt;streamHandler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventSource&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;DynamoEventSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;startingPosition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;StartingPosition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LATEST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;batchSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;retryAttempts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&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;h4&gt;
  
  
  Configuration Options
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;startingPosition&lt;/code&gt; – Defines where the Lambda function should start reading the stream (e.g., &lt;code&gt;LATEST&lt;/code&gt; for new records only).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;batchSize&lt;/code&gt; – The maximum number of records to send to the function in a single invocation. The Lambda will receive all these records in the event payload.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;retryAttempts&lt;/code&gt; – The maximum number of times Lambda will retry a failed batch before discarding or sending it to a dead-letter destination (if configured).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;By using DynamoDB Streams, you can build powerful real-time event-driven systems with minimal operational overhead. In this example, we simply logged data changes to CloudWatch, but you can extend this to trigger notifications, sync systems, or persist audit logs to S3.&lt;/p&gt;

&lt;p&gt;——————————————&lt;/p&gt;

&lt;p&gt;&lt;em&gt;For more articles, follow my social handles:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/sherifawofiranye" rel="noopener noreferrer"&gt;&lt;em&gt;LinkedIn&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.x.com/sherif_on_x" rel="noopener noreferrer"&gt;&lt;em&gt;Twitter&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/iamsherif"&gt;&lt;em&gt;Dev&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@awofiranyesherif4" rel="noopener noreferrer"&gt;&lt;em&gt;Medium&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>dynamodb</category>
      <category>lambda</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Deploying a Static E-commerce Site to AWS Using Pulumi</title>
      <dc:creator>iAmSherif 💎</dc:creator>
      <pubDate>Sat, 05 Apr 2025 20:47:40 +0000</pubDate>
      <link>https://dev.to/iamsherif/deploying-a-static-e-commerce-site-to-aws-using-pulumi-1nlf</link>
      <guid>https://dev.to/iamsherif/deploying-a-static-e-commerce-site-to-aws-using-pulumi-1nlf</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/pulumi"&gt;Pulumi Deploy and Document Challenge&lt;/a&gt;: Fast Static Website Deployment&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;I built and deployed &lt;strong&gt;Ticaz Bags &amp;amp; Luggage&lt;/strong&gt;, a sleek and modern static e-commerce website where users can browse and shop for stylish bags and durable luggage. The website features clean UI, responsive design, and smooth navigation, all tailored to create an enjoyable online shopping experience.&lt;/p&gt;

&lt;p&gt;To bring this project to life, I used Pulumi to set up the entire cloud infrastructure on AWS from scratch. This includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An &lt;strong&gt;S3 bucket&lt;/strong&gt; for hosting the static build&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;CloudFront distribution&lt;/strong&gt; for fast and secure global content delivery&lt;/li&gt;
&lt;li&gt;Proper &lt;strong&gt;IAM roles and bucket policies&lt;/strong&gt; for access control and caching&lt;/li&gt;
&lt;li&gt;A well-structured &lt;strong&gt;Pulumi&lt;/strong&gt; stack for consistent, repeatable deployments
&lt;em&gt;All of which are fully-managed by &lt;strong&gt;Pulumi&lt;/strong&gt;&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The site was developed using &lt;strong&gt;React&lt;/strong&gt;, &lt;strong&gt;Vite&lt;/strong&gt;, and &lt;strong&gt;Tailwind CSS&lt;/strong&gt;, offering fast performance and responsive design.&lt;/p&gt;

&lt;p&gt;This project was both a dev and DevOps learning experience, combining frontend polish with cloud-native deployment!&lt;/p&gt;

&lt;p&gt;In this post, I’ll walk you through my journey and how you, too, can deploy a static website to &lt;strong&gt;AWS&lt;/strong&gt; using &lt;strong&gt;Pulumi as Infrastructure as Code (IaC)&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Live Demo Link
&lt;/h2&gt;

&lt;p&gt;Access the live site via the CDN link below:&lt;br&gt;
-&amp;gt;  &lt;a href="https://dyk9aqch11ytc.cloudfront.net/" rel="noopener noreferrer"&gt;https://dyk9aqch11ytc.cloudfront.net/&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Project Repo
&lt;/h2&gt;

&lt;p&gt;🔗 &lt;a href="https://github.com/iAmSherifCodes/TicazOnAWSPulumi.git" rel="noopener noreferrer"&gt;GitHub – Ticaz Bags &amp;amp; Luggage&lt;/a&gt;  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The repo includes the full frontend source code and the Pulumi configuration used to deploy it. The README includes setup instructions and deployment steps.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  My Journey
&lt;/h2&gt;

&lt;p&gt;Before this challenge, I already had the &lt;strong&gt;Ticaz Bags &amp;amp; Luggage&lt;/strong&gt; website built, but it hadn’t yet been deployed to AWS. I discovered the &lt;a href="https://www.pulumi.com/templates/static-website/aws/" rel="noopener noreferrer"&gt;Pulumi Static Website Template for AWS&lt;/a&gt; and followed the guide to get everything deployed smoothly.&lt;/p&gt;

&lt;p&gt;Along the way, I learned that there are &lt;strong&gt;two main ways&lt;/strong&gt; to connect your static build to your Pulumi project:&lt;/p&gt;
&lt;h3&gt;
  
  
  ✅ Option 1: Use &lt;code&gt;pulumi config set path&lt;/code&gt; via CLI
&lt;/h3&gt;

&lt;p&gt;This method lets you set the path to your static build folder (like &lt;code&gt;dist/&lt;/code&gt;) using the CLI. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pulumi config &lt;span class="nb"&gt;set &lt;/span&gt;path /home/user/Documents/codes/frontend/dist
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;💡 In my case, I first ran &lt;code&gt;npm run build&lt;/code&gt; inside the frontend project, which generated the &lt;code&gt;/dist&lt;/code&gt; folder.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This command updates your &lt;code&gt;Pulumi.&amp;lt;stack-name&amp;gt;.yaml&lt;/code&gt; file, and Pulumi uses that path when deploying to S3.&lt;br&gt;&lt;br&gt;
It’s quick and easy, but note that &lt;strong&gt;your frontend code stays outside&lt;/strong&gt; the Pulumi project. So while your build is deployed, your local project structure remains disconnected.&lt;/p&gt;


&lt;h3&gt;
  
  
  ✅ Option 2: Move the frontend into your Pulumi project
&lt;/h3&gt;

&lt;p&gt;With this approach, I moved the built frontend folder into the Pulumi project directory (e.g., &lt;code&gt;www/frontend/dist&lt;/code&gt;) and &lt;strong&gt;manually edited&lt;/strong&gt; the Pulumi YAML config like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;&amp;lt;stack-name&amp;gt;:path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;www/frontend/dist&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allowed me to &lt;strong&gt;keep my infrastructure and app code together&lt;/strong&gt;, making it easier to maintain and understand everything in one place.&lt;/p&gt;

&lt;h3&gt;
  
  
  🧠My Decision
&lt;/h3&gt;

&lt;p&gt;I tested &lt;strong&gt;both approaches&lt;/strong&gt;, and while they both worked, I ultimately chose the &lt;strong&gt;second method&lt;/strong&gt;. Here's why:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I had better control over the deployment&lt;/li&gt;
&lt;li&gt;My infrastructure and frontend code lived together in one repo&lt;/li&gt;
&lt;li&gt;I could track everything more cleanly with version control&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It gave me a clearer understanding of how Pulumi interacts with the application build and made debugging and updating easier going forward.&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%2Faoulvpwugli5mb2t7flf.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%2Faoulvpwugli5mb2t7flf.png" alt="Different ways to deploy your static website to aws using pulumi" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Pulumi
&lt;/h2&gt;

&lt;p&gt;Pulumi made the deployment process seamless, structured, and developer-friendly. I didn’t have to worry about manually setting up S3 buckets, configuring IAM permissions, or writing extensive boilerplate IaC code from scratch.&lt;/p&gt;

&lt;p&gt;Here’s how I used Pulumi in this project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Infrastructure as Code:&lt;/strong&gt; I provisioned AWS resources like S3 and CloudFront using Pulumi’s TypeScript SDK. Everything was version-controlled and easy to manage.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Simple Configuration:&lt;/strong&gt; My main task was linking the application’s build folder (the &lt;code&gt;/dist&lt;/code&gt; directory) to the Pulumi project. Once connected, Pulumi handled the rest—uploading the files, configuring the CDN, and setting proper access.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Automation:&lt;/strong&gt; With just one command (&lt;code&gt;pulumi up&lt;/code&gt;), I could deploy changes, test updates, or even roll back &lt;code&gt;pulumi cancel&lt;/code&gt; when needed—no AWS Console clicking required.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Conclusion:&lt;/strong&gt; Pulumi enabled me to streamline deployment without getting entangled in low-level infrastructure tasks. It’s a powerful tool for full-stack and solo developers who want to manage cloud infrastructure with familiar programming languages and clean, version-controlled code.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>pulumichallenge</category>
      <category>webdev</category>
      <category>cloud</category>
    </item>
    <item>
      <title>How to set up CORS in AWS Lambda and API Gateway (RestApi)</title>
      <dc:creator>iAmSherif 💎</dc:creator>
      <pubDate>Thu, 06 Feb 2025 15:25:47 +0000</pubDate>
      <link>https://dev.to/iamsherif/how-to-set-up-cors-in-aws-lambda-and-api-gateway-restapi-34a2</link>
      <guid>https://dev.to/iamsherif/how-to-set-up-cors-in-aws-lambda-and-api-gateway-restapi-34a2</guid>
      <description>&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%2F7oy3jo93ltizq88s9fx8.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%2F7oy3jo93ltizq88s9fx8.png" alt="How to set up CORS in AWS Lambda and API Gateway (RestApi)" width="800" height="240"&gt;&lt;/a&gt;Cross-Origin Resource Sharing (CORS) is a security feature implemented by web browsers that restricts how resources on a web server can be requested from  a different domain. When building serverless applications using AWS Lambda and API Gateway, you need to configure CORS properly to allow client applications from different origins to access your API.&lt;/p&gt;

&lt;p&gt;CORS is enforced at the browser level. When you deploy a REST API service to a domain, the browser must agree to the service's terms before communicating with it.&lt;/p&gt;

&lt;p&gt;Imagine you have a Lambda backend service exposed through API Gateway's REST API. You integrate this API into your client application using communication services like &lt;code&gt;Axios&lt;/code&gt; or JavaScript's &lt;code&gt;fetch&lt;/code&gt;. You expect it to work smoothly because you've tested it with API testing tools such as Postman or even the AWS Management Console. But then &lt;em&gt;poof!&lt;/em&gt; a strange 403 error appears. Why is this happening?&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Do You Get a CORS Error from the Browser?
&lt;/h2&gt;

&lt;p&gt;The reason is simple: unlike tools like Postman that make direct requests, browsers enforce the same-origin policy as a security measure. If your frontend is hosted on &lt;a href="https://frontend.com" rel="noopener noreferrer"&gt;https://frontend.com&lt;/a&gt; and it tries to fetch data from &lt;a href="https://api.com" rel="noopener noreferrer"&gt;https://api.com&lt;/a&gt;, the browser blocks the request unless the API explicitly allows it.&lt;/p&gt;

&lt;p&gt;CORS settings in API Gateway define whether such cross-origin requests should be permitted. The key configurations involve setting allowed origins, HTTP methods, and headers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the Request Flow: Preflight and Actual Requests
&lt;/h2&gt;

&lt;p&gt;When a client’s browser makes a request to an API hosted on a different origin, the process typically involves two steps: The Preflight Request and the Actual Request.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Preflight Request&lt;/strong&gt;:&lt;/li&gt;
&lt;/ul&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%2F2nqb2t9ysbpjxo18b14t.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%2F2nqb2t9ysbpjxo18b14t.png" alt="Preflight Request" width="550" height="250"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before sending the actual request, the browser sends an &lt;code&gt;OPTIONS&lt;/code&gt; request to the API.&lt;/p&gt;

&lt;p&gt;This request asks the server: “Am I allowed to send this request? If so, what methods and headers can I use?”&lt;/p&gt;

&lt;p&gt;API Gateway (if configured correctly) responds with the allowed origins, methods, and headers.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Actual Request&lt;/strong&gt;:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once the browser receives a successful response from the preflight check, it proceeds to send the actual request (GET, POST, etc.) to the API.&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%2Fyny637k64blsne3okmjw.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%2Fyny637k64blsne3okmjw.png" alt="Actual Request" width="550" height="250"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If the API response includes the required CORS headers, the browser allows the data to be accessed by the client application.&lt;/p&gt;

&lt;p&gt;Without proper CORS settings, the browser will block the request at the preflight stage, preventing the client from communicating with the API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up CORS in AWS API Gateway and Lambda in (CDK)
&lt;/h2&gt;

&lt;p&gt;There are two places you are required to set your headers in other for the two requests (Preflight and Actual) to be successful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First&lt;/strong&gt;, Set up &lt;code&gt;defaultCorsPreflightOptions&lt;/code&gt; in your API-Gateway.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;restApi&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="s2"&gt;`YourApi`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;defaultCorsPreflightOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;allowOrigins&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://frontend.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;allowMethods&lt;/span&gt;&lt;span class="p"&gt;:&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&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="s1"&gt;OPTIONS&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;allowHeaders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&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="s1"&gt;Authorization&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="s1"&gt;Accept&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="s1"&gt;X-Requested-With&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;allowCredentials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;defaultCorsPreflightOptions&lt;/code&gt;: adds a CORS preflight configuration to this resource and all child resources. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;allowOrigins&lt;/code&gt;: Defines the permitted origins for requests to this resource. To allow all origins, use Cors.ALL_ORIGINS or [*]. The response will include the Access-Control-Allow-Origin header, and if Cors.ALL_ORIGINS is used, the Vary: Origin header will also be included.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;allowMethods&lt;/code&gt;: The Access-Control-Allow-Methods response header defines the permitted HTTP methods for a resource in response to a preflight request. Here, only GET, POST, and OPTIONS are allowed, enforcing the principle of least privilege by restricting access to necessary methods.
If ANY is specified, it will be expanded to Cors.ALL_METHODS.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;allowHeaders&lt;/code&gt;: The Access-Control-Allow-Headers response header specifies the allowed HTTP headers in response to a preflight request, based on the Access-Control-Request-Headers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;allowCredentials&lt;/code&gt;: The Access-Control-Allow-Credentials response header determines whether the response is accessible to frontend JavaScript when the request's credentials mode is set to "include". If true, browsers expose the response only when credentials (cookies, authorization headers, or TLS client certificates) are included.&lt;/p&gt;

&lt;p&gt;In API Gateway, this ensures a successful preflight request but does not guarantee the actual request's success.&lt;br&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%2Fg1ij14enqlzemeraplig.jpg" 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%2Fg1ij14enqlzemeraplig.jpg" alt="Successful preflight request" width="734" height="53"&gt;&lt;/a&gt;&lt;br&gt;
Why? Because the API response does not include the necessary CORS headers. How can we fix that?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Second&lt;/strong&gt;, Add CORS headers to your lambda response.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&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;Access-Control-Allow-Origin&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;*&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Allow all origins&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Access-Control-Allow-Methods&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;GET,OPTIONS&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;Access-Control-Allow-Headers&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;Content-Type,Authorization&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;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;We Are Fixing CORS!&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We added CORS headers to the Lambda response. After a successful preflight request, the browser verifies these headers in the actual response. If present, the data becomes accessible.&lt;/p&gt;

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

&lt;p&gt;Setting up CORS for AWS Lambda and API Gateway is crucial when exposing APIs to frontend applications hosted on different domains. By configuring API Gateway’s preflight options and ensuring Lambda responses include CORS headers, you can successfully enable cross-origin access.&lt;/p&gt;

&lt;p&gt;——————————————&lt;/p&gt;

&lt;p&gt;&lt;em&gt;For more articles, follow my social handles:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/sherifawofiranye" rel="noopener noreferrer"&gt;&lt;em&gt;LinkedIn&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.x.com/sherif_on_x" rel="noopener noreferrer"&gt;&lt;em&gt;Twitter&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/iamsherif"&gt;&lt;em&gt;Dev&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@awofiranyesherif4" rel="noopener noreferrer"&gt;&lt;em&gt;Medium&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>cdk</category>
      <category>lambda</category>
      <category>restapi</category>
    </item>
    <item>
      <title>How to validate requests when using AWS Lambda Function Url</title>
      <dc:creator>iAmSherif 💎</dc:creator>
      <pubDate>Sun, 08 Dec 2024 07:57:31 +0000</pubDate>
      <link>https://dev.to/iamsherif/how-to-validate-requests-when-using-aws-lambda-function-url-5d72</link>
      <guid>https://dev.to/iamsherif/how-to-validate-requests-when-using-aws-lambda-function-url-5d72</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;A Lambda function URL is a built-in HTTPS endpoint for an AWS Lambda function. It allows you to directly invoke a Lambda function over HTTP without needing an intermediary service like API Gateway. This simplifies deployments when your function needs to be publicly accessible or integrated into web applications. Validating requests with Lambda Function URLs offers unique challenges and nuances, unlike API Gateway where you can use Model and RequestValidator &lt;a href="https://dev.to/iamsherif/how-to-validate-requests-in-amazon-api-gateway-4n78"&gt;See&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this article, I will guide you on how you can simply validate your event object and as well return appropriate error if there is mismatch in received event payload.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why do you need Lambda Function Url
&lt;/h2&gt;

&lt;p&gt;A Lambda function URL is a dedicated endpoint with a unique URL that provides a straightforward way to call a Lambda function over HTTP. When you create a Lambda function URL, AWS automatically generates a URL for the function, and you can configure IAM-based authentication or leave it public (for open access).&lt;/p&gt;

&lt;h3&gt;
  
  
  Importance of Lambda Function Url are:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Simplicity&lt;/strong&gt;: Removes the need to set up and manage an API Gateway when you only need a simple HTTP endpoint.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cost-Effective&lt;/strong&gt;: Reduces costs compared to using API Gateway for basic use cases since Lambda function URLs have no additional charges beyond standard Lambda pricing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Quick Deployment&lt;/strong&gt;: Ideal for rapid prototyping or use cases where setting up API Gateway is unnecessary.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Native HTTPS Support&lt;/strong&gt;: Provides secure communication without extra configuration.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Authentication Control&lt;/strong&gt;: Supports IAM-based authentication for secure access or can be set to public for open endpoints.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  When would you need Lambda Function Url
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Microservices and Webhooks&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Easily create microservices that respond to HTTP requests.&lt;/li&gt;
&lt;li&gt;Use Lambda function URLs to handle webhook callbacks from third-party services (e.g., payment systems, notifications).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Prototyping and Demos&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Quickly expose a backend function for demo purposes without setting up API Gateway.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Automation and Internal Tools&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create internal tools that employees can access directly via a simple URL.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Static Website Backends&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pair a static website hosted on Amazon S3 or CloudFront with a Lambda function URL for dynamic functionality (e.g., form submissions).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;IoT Integrations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allow IoT devices to trigger serverless functions directly via HTTP endpoints.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How to validate requests in Lambda Function Url
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Steps:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Define your request model&lt;/li&gt;
&lt;li&gt;Use the reusable request model to validate your event body data(payload)&lt;/li&gt;
&lt;li&gt;Plug the model to your handler method&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Define your request model
&lt;/h4&gt;

&lt;p&gt;Define the model for your event body. Say you want &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;email&lt;/code&gt;, and an optional &lt;code&gt;mobileNumber&lt;/code&gt;. We are going to create a model that matches the expected event body.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisite&lt;/strong&gt;:  Install Joi --&amp;gt; &lt;code&gt;npm install Joi&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Joi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;joi&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;eventModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Joi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Joi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;required&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Joi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;email&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;minDomainSegments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;tlds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;allow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;com&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="s1"&gt;net&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="na"&gt;mobileNumber&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Joi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;optional&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;h4&gt;
  
  
  Use the request model to validate your event
&lt;/h4&gt;

&lt;p&gt;After creating the model, next we will need to validate the event body data with the model; this step also ensures error is properly handled.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;validateEventData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&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;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;eventModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;validateAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&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;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;error&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Plug-in the model to your handler method
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&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;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;validateEventData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;200&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;body&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;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&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="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid request body&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;err&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Sample Error
&lt;/h3&gt;

&lt;p&gt;Say we send a mismatch event object like:&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;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"value3@gmail.com"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"mobileNumber"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"234567890"&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;Note that we took out a required field &lt;code&gt;name&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="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"statusCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"body"&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;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Invalid request body"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; is required"&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;Here's a refactored and expanded version of your conclusion section to provide more depth and reinforce key takeaways:&lt;/p&gt;




&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Properly validating incoming requests is a critical step in safeguarding your AWS Lambda functions from potential vulnerabilities such as SQL injection, script injection, and other forms of malicious input. By implementing robust validation practices, you can ensure that your application remains secure, reliable, and resilient.&lt;/p&gt;

&lt;p&gt;In this article, we demonstrated how to use &lt;a href="https://www.npmjs.com/package/joi" rel="noopener noreferrer"&gt;Joi&lt;/a&gt; library to perform request validation in AWS Lambda functions. With Joi, you can define clear validation schemas, enforce data integrity, and provide informative error messages to users when inputs do not meet your requirements. This approach not only fortifies your application against security threats but also enhances maintainability by keeping your validation logic structured and reusable.&lt;/p&gt;

&lt;p&gt;By following the steps outlined, you can seamlessly integrate input validation into your Lambda functions and handle validation errors gracefully. As a result, your serverless applications can operate more securely, giving you confidence that only well-formed, valid data is processed.&lt;/p&gt;

&lt;p&gt;Remember, validation is just one layer of a comprehensive security strategy. Pairing it with practices such as proper error logging, input sanitization, and authentication mechanisms (like AWS Cognito) will further bolster the security of your application.&lt;/p&gt;

&lt;p&gt;Secure coding practices like these are essential for building robust serverless architectures. Start implementing input validation today to protect your AWS Lambda endpoints and provide a safer experience for your users.&lt;/p&gt;

&lt;p&gt;——————————————&lt;/p&gt;

&lt;p&gt;&lt;em&gt;For more articles, follow my social handles:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/sherifawofiranye" rel="noopener noreferrer"&gt;&lt;em&gt;LinkedIn&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.x.com/sherif_on_x" rel="noopener noreferrer"&gt;&lt;em&gt;Twitter&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/iamsherif"&gt;&lt;em&gt;Dev&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@awofiranyesherif4" rel="noopener noreferrer"&gt;&lt;em&gt;Medium&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>lambda</category>
      <category>aws</category>
      <category>javascript</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Schema Validation in Amazon DynamoDB</title>
      <dc:creator>iAmSherif 💎</dc:creator>
      <pubDate>Fri, 08 Nov 2024 22:03:14 +0000</pubDate>
      <link>https://dev.to/iamsherif/schema-validation-in-amazon-dynamodb-2c73</link>
      <guid>https://dev.to/iamsherif/schema-validation-in-amazon-dynamodb-2c73</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Validating data in DynamoDB is crucial for maintaining data integrity, ensuring application reliability, and reducing errors. Unlike relational databases, DynamoDB does not enforce strict schema constraints, giving you the flexibility to store a variety of data formats. However, this flexibility means you must take responsibility for validating data before it is written to the database. In this article, we’ll go through an approach to validate data in DynamoDB using AWS Lambda.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Data Validation Matters in DynamoDB
&lt;/h2&gt;

&lt;p&gt;Without strict schema enforcement, data in DynamoDB can end up in inconsistent or incorrect formats. If validation is neglected, problems may arise, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Application Errors: Missing or incorrectly formatted data can lead to errors and application crashes.&lt;/li&gt;
&lt;li&gt;Data Inconsistencies: Querying inconsistent data formats can complicate analytics and reporting.&lt;/li&gt;
&lt;li&gt;Scalability Issues: Unvalidated data may lead to inefficient data structure and increased storage costs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To avoid these issues, validating data before saving it to DynamoDB is essential.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to validate schema using AWS Lambda
&lt;/h2&gt;

&lt;p&gt;In serverless architectures, AWS Lambda is a common approach for server-side validation. By implementing validation within Lambda functions, you can control data before it reaches DynamoDB.&lt;/p&gt;

&lt;p&gt;Here’s how you can incorporate validation in a Lambda function with Node.js:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Joi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;joi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// The schema definition using Joi&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tableSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Joi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Joi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;required&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Joi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;required&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Joi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;pattern&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;RegExp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;^[&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;w-&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;.]+@([&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;w-]+&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;.)+[&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;w-]{2,4}$&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;required&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;phone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Joi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;optional&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;validateObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&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;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;tableSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;validateAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&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;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Invalid request body&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;err&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="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lambdaHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&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;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;writeToDynamodbTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&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;result&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;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&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="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Invalid request body&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;err&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="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;writeToDynamodbTable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&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;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;validateObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&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;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;TableName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YourTableName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;phone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;phone&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;ConditionExpression&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;attribute_not_exists(id)&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;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;dynamodbClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&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;PutCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&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;res&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;error&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;In the code snippet above we:&lt;br&gt;
1- Define the schema using &lt;a href="https://joi.dev/api/" rel="noopener noreferrer"&gt;Joi&lt;/a&gt; Schema&lt;br&gt;
2- Validate our object in the validateObject function&lt;br&gt;
3- Configure our params object&lt;br&gt;
3- Send request to DynamoDB using AWS Lambda&lt;/p&gt;
&lt;h3&gt;
  
  
  SAMPLE ERROR:
&lt;/h3&gt;

&lt;p&gt;If we send a mismatch object like this:&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="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;"body"&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;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"value1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"value2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"value3@gmail.com"&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;&lt;em&gt;Note: &lt;code&gt;phone&lt;/code&gt; is not included in the object but it is a required key in the schema we defined.&lt;/em&gt;&lt;br&gt;
We will get an error like&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="err"&gt;statusCode:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;body:&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="err"&gt;message:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Invalid request body"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="err"&gt;error:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="err"&gt;phone&lt;/span&gt;&lt;span class="s2"&gt;" is required"&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;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Validating data in DynamoDB is a fundamental step to ensure data quality and avoid issues down the line. Whether you choose to validate data on the client, the server, or both, using a structured approach with reusable validation schemas will streamline the process. By following best practices, you can improve the reliability and performance of your DynamoDB-backed applications.&lt;/p&gt;

&lt;p&gt;——————————————&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Follow my social handles for more articles:&lt;/em&gt;&lt;br&gt;
&lt;em&gt;Click and follow on&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/sherifawofiranye" rel="noopener noreferrer"&gt;&lt;em&gt;LinkedIn&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.x.com/sherif_on_x" rel="noopener noreferrer"&gt;&lt;em&gt;Twitter&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/iamsherif"&gt;&lt;em&gt;Dev&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@awofiranyesherif4" rel="noopener noreferrer"&gt;&lt;em&gt;Medium&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>dynamodb</category>
      <category>aws</category>
      <category>security</category>
      <category>node</category>
    </item>
    <item>
      <title>How to Pull Resources from AWS SSM Parameter Store in AWS SAM</title>
      <dc:creator>iAmSherif 💎</dc:creator>
      <pubDate>Fri, 11 Oct 2024 23:09:35 +0000</pubDate>
      <link>https://dev.to/iamsherif/how-to-pull-resources-from-aws-ssm-parameter-store-in-aws-sam-3nb4</link>
      <guid>https://dev.to/iamsherif/how-to-pull-resources-from-aws-ssm-parameter-store-in-aws-sam-3nb4</guid>
      <description>&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;In this article, I'll guide you through the process of retrieving a DynamoDB table name stored in AWS Systems Manager Parameter Store (SSM Parameter Store) using an AWS SAM template (template.yml). Additionally, I’ll show how to use this parameter in our code and how to add the required IAM permissions to the function.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is AWS Systems Manager Parameter Store?
&lt;/h3&gt;

&lt;p&gt;AWS Systems Manager Parameter Store is a service that provides secure, hierarchical storage for managing configuration data and secrets. It allows you to store values like passwords, database strings, Amazon Machine Image (AMI) IDs, and other sensitive information as parameters. These values can be stored as plain text or encrypted, and referenced in scripts, AWS Lambda functions, and other AWS services by their unique parameter names.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a Parameter in AWS Systems Manager Parameter Store
&lt;/h3&gt;

&lt;p&gt;We will create a parameter to hold our DynamoDB table name in the SSM Parameter Store.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Steps:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the AWS Management Console, search for Systems Manager.
&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%2F1q7tsq12iy0ig8a877ji.png" alt="Systems Manager search result" width="800" height="271"&gt;
&lt;/li&gt;
&lt;li&gt;Under the Application Management section, select Parameter Store.
&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%2F8wx21s6wvdyg7ofr17v2.png" alt="Parameter Store" width="330" height="207"&gt;
&lt;/li&gt;
&lt;li&gt;Click the Create Parameter button on the left side.
&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%2Fx1s4n48c3l36wc8796m9.png" alt="Create a Parameter" width="194" height="53"&gt;
4- Name the parameter &lt;code&gt;/my/database/name&lt;/code&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%2Fx159gtea7s0h9h3y0wfd.png" alt="parameter name" width="714" height="180"&gt;
5- Set the type to &lt;strong&gt;String&lt;/strong&gt;, and enter the DynamoDB table name as the value.
&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%2Fa0sl39mnkpqad4b7cwr2.png" alt="create paramter" width="628" height="407"&gt;
6- Click Create Parameter to save.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Note: In this example, the parameter name is &lt;code&gt;/my/database/name&lt;/code&gt;, and its value is the name of your DynamoDB table.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Retrieving the Parameter in Your AWS SAM Template
&lt;/h3&gt;

&lt;p&gt;In the &lt;code&gt;template.yml&lt;/code&gt; file, we'll reference the DynamoDB table name stored in SSM. The Lambda function, &lt;code&gt;MyFunction&lt;/code&gt;, needs both read permissions for the DynamoDB table and permission to access the SSM Parameter Store.&lt;/p&gt;

&lt;p&gt;The SSM parameter is retrieved using the syntax &lt;code&gt;{{resolve:ssm:/my/database/name}}&lt;/code&gt;, which fetches the value dynamically during resource creation. Additionally, we must assign the necessary IAM roles to allow the Lambda function to read the parameter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;AWSTemplateFormatVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;2010-09-09'&lt;/span&gt;
&lt;span class="na"&gt;Transform&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Serverless-2016-10-31&lt;/span&gt;
&lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Url Sample SAM Template for url&lt;/span&gt;

&lt;span class="na"&gt;Globals&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;Function&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
    &lt;span class="na"&gt;LoggingConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;LogFormat&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;JSON&lt;/span&gt;
&lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;MyFunction&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Serverless::Function&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redirect.handler&lt;/span&gt;
      &lt;span class="na"&gt;Runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nodejs18.x&lt;/span&gt;
      &lt;span class="na"&gt;FunctionUrlConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;AuthType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NONE&lt;/span&gt;
      &lt;span class="na"&gt;Policies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;DynamoDBCrudPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;TableName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{resolve:ssm:/my/database/name}}"&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt;  &lt;span class="na"&gt;SSMParameterReadPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;ParameterName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;my/database/name"&lt;/span&gt;
      &lt;span class="na"&gt;Architectures&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;x86_64&lt;/span&gt;
      &lt;span class="na"&gt;Environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;TABLE_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/my/database/name"&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Here, the Lambda function retrieves the DynamoDB table name using the &lt;code&gt;resolve&lt;/code&gt; function from SSM and assigns the necessary policies to access both DynamoDB and the SSM Parameter Store.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: We removed the starting&lt;/em&gt; &lt;code&gt;/&lt;/code&gt; &lt;em&gt;before the parameter name.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt;  &lt;span class="na"&gt;SSMParameterReadPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;ParameterName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;my/database/name"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;If we don't, we will get an Unauthorized error.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Retrieving the Parameter Value in your Code
&lt;/h3&gt;

&lt;p&gt;In your code, you can retrieve the DynamoDB table name from the SSM Parameter Store like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SSMClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;GetParameterCommand&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@aws-sdk/client-ssm&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;table_name_path&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;TABLE_NAME&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;retrieveTable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&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="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;table_name_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;WithDecryption&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&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;command&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;GetParameterCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ssmClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;command&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Parameter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Value&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 JavaScript code initializes an SSM client, and retrieves the DynamoDB table name using the &lt;code&gt;GetParameterCommand&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: Ensure you install the &lt;code&gt;@aws-sdk/client-ssm&lt;/code&gt; package using &lt;code&gt;npm install @aws-sdk/client-ssm&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best Practice:&lt;/strong&gt; Notice that we didn't retrieve the parameter value directly within our Lambda function. We avoid adding extra latency during Lambda's cold start. This approach improves performance by reducing the number of external API calls made during execution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;In this article, we explored how to securely store and retrieve a DynamoDB table name from AWS Systems Manager Parameter Store and use it within an AWS Lambda function. By utilizing the &lt;code&gt;{{resolve:ssm}}&lt;/code&gt; syntax in the AWS SAM template, we demonstrated how to dynamically reference parameters during resource deployment. Additionally, we showed how to configure the necessary IAM permissions and retrieve the parameter value within our code using AWS SDK.&lt;/p&gt;

&lt;p&gt;Leveraging AWS Systems Manager Parameter Store not only helps in managing configuration data and secrets efficiently, but also enhances the security and flexibility of your serverless applications. With these steps, you can easily scale this approach to manage other sensitive configuration values across your AWS infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Follow my social handles for more articles:&lt;/em&gt;&lt;br&gt;
&lt;em&gt;Click and follow on&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/sherifawofiranye" rel="noopener noreferrer"&gt;&lt;em&gt;LinkedIn&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.x.com/sherif_on_x" rel="noopener noreferrer"&gt;&lt;em&gt;Twitter&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/iamsherif"&gt;&lt;em&gt;Dev&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@awofiranyesherif4" rel="noopener noreferrer"&gt;&lt;em&gt;Medium&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>serverless</category>
      <category>lambda</category>
      <category>dynamodb</category>
    </item>
    <item>
      <title>How to make authenticated HTTP POST and GET requests to third-party APIs in SpringBoot</title>
      <dc:creator>iAmSherif 💎</dc:creator>
      <pubDate>Thu, 26 Sep 2024 00:22:40 +0000</pubDate>
      <link>https://dev.to/iamsherif/how-to-make-authenticated-http-post-and-get-requests-in-springboot-ai7</link>
      <guid>https://dev.to/iamsherif/how-to-make-authenticated-http-post-and-get-requests-in-springboot-ai7</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Spring Boot is a powerful Java framework that simplifies software development process by providing a comprehensive suite of tools and conventions. Its ease of use, along with powerful features, makes it a popular choice for both small and large applications. In building applications, at times there is a need to consume third-party APIs within your application.&lt;/p&gt;

&lt;p&gt;There are several ways to make requests to APIs in Spring Boot which include using &lt;code&gt;RestTemplate&lt;/code&gt;, &lt;code&gt;WebSocket&lt;/code&gt;, &lt;code&gt;Apache HttpClient&lt;/code&gt;, &lt;code&gt;OkHttp&lt;/code&gt;, and &lt;code&gt;FeignClient&lt;/code&gt;. The choice of method often depends on the specific requirements of your application. In this article, we will focus on how to make authenticated POST and GET requests to third-party APIs using &lt;code&gt;RestTemplate&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is RestTemplate?
&lt;/h3&gt;

&lt;p&gt;RestTemplate is a synchronous client provided by Spring that provides a straightforward and intuitive API for sending HTTP requests and handling responses. It is a package in Spring that is included in the Spring Web dependency. Its methods are easy to understand, making it accessible for developers of all skill levels.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to make an Authenticated POST request
&lt;/h3&gt;

&lt;p&gt;To demonstrate how to make an authenticated POST request, let's consider a scenario where we are building a wallet application that needs to create an account via a third-party API at &lt;code&gt;https://api.example.com/create&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Requirements:
&lt;/h4&gt;

&lt;p&gt;The API requires the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Headers: &lt;code&gt;Authorization bearer &amp;lt;token&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Body Parameters: &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;email&lt;/code&gt;, &lt;code&gt;bvn&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Steps
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Create a RestTemplate object.&lt;/li&gt;
&lt;li&gt;Set Up the HTTP Headers: Create a header that carries the authorization token using &lt;code&gt;HttpHeaders&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Create the HttpEntity: Construct an &lt;code&gt;HttpEntity&lt;/code&gt; object using the expected request body and the HTTP header.&lt;/li&gt;
&lt;li&gt;Make the POST Request: Use the &lt;code&gt;postForObject&lt;/code&gt; method of RestTemplate to send the request.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Example Code
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://api.example.com/create"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;RestTemplate&lt;/span&gt; &lt;span class="n"&gt;restTemplate&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;RestTemplate&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="nc"&gt;HttpHeaders&lt;/span&gt; &lt;span class="n"&gt;httpHeaders&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;HttpHeaders&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;httpHeaders&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setBasicAuth&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="nc"&gt;HttpEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;httpEntity&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;HttpEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;requestBody&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;httpHeaders&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Response from the API server&lt;/span&gt;
&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;responseObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;restTemplate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;postForObject&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;httpEntity&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;With this setup, you can successfully make a POST request to the API, provided that the token is valid.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to make an Authenticated GET request
&lt;/h3&gt;

&lt;p&gt;To make the authenticated GET request, we are going to make use of the &lt;code&gt;exchange&lt;/code&gt; method in &lt;code&gt;RestTemplate&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Example Code
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://api.example.com/balance"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;HttpHeaders&lt;/span&gt; &lt;span class="n"&gt;httpHeaders&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;HttpHeaders&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;httpHeaders&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setBasicAuth&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="nc"&gt;HttpEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;httpEntity&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;HttpEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;httpHeaders&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Response from the API server&lt;/span&gt;
&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;responseObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;restTemplate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;exchange&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;HttpMethod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;GET&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;httpEntity&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;getBody&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;By following these steps, you will be able to make the GET request to the API provided your token is valid.&lt;/p&gt;

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

&lt;p&gt;In this article, we covered how to make authenticated POST and GET requests to third-party APIs using SpringBoot's &lt;code&gt;RestTemplate&lt;/code&gt;. By leveraging RestTemplate, you can easily configure your requests to include necessary authentication headers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Additional Notes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Always ensure that sensitive data such as API keys and passwords are stored securely, using environment variables or encrypted configuration files.&lt;/li&gt;
&lt;li&gt;Consider exploring other options like WebClient for reactive programming or FeignClient for declarative API clients in more complex applications.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Follow my social handles for more articles:&lt;/em&gt;&lt;br&gt;
&lt;em&gt;Click and follow on&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/sherifawofiranye" rel="noopener noreferrer"&gt;&lt;em&gt;LinkedIn&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.x.com/sherif_on_x" rel="noopener noreferrer"&gt;&lt;em&gt;Twitter&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/iamsherif"&gt;&lt;em&gt;Dev&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@awofiranyesherif4" rel="noopener noreferrer"&gt;&lt;em&gt;Medium&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>http</category>
    </item>
    <item>
      <title>Securing Data at Rest: The Importance of Encryption and How to Implement It</title>
      <dc:creator>iAmSherif 💎</dc:creator>
      <pubDate>Sun, 14 Jul 2024 17:30:56 +0000</pubDate>
      <link>https://dev.to/iamsherif/securing-data-at-rest-the-importance-of-encryption-and-how-to-implement-it-81a</link>
      <guid>https://dev.to/iamsherif/securing-data-at-rest-the-importance-of-encryption-and-how-to-implement-it-81a</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Keeping your data safe is essential for any organization to prevent unauthorized access and breaches. In AWS's shared security responsibility model, customers are responsible for anything they put in the cloud or connect to the cloud, while AWS is responsible for the security of the cloud. For more details, you can &lt;a href="https://aws.amazon.com/compliance/shared-responsibility-model/" rel="noopener noreferrer"&gt;&lt;em&gt;read more information about AWS shared responsibility model.&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Data at rest refers to data stored in AWS data stores, such as Amazon S3 buckets and DynamoDB. In this article, I will highlight the importance of encrypting data at rest and provide a guide on how to encrypt an &lt;a href="https://aws.amazon.com/dynamodb/" rel="noopener noreferrer"&gt;&lt;em&gt;Amazon DynamoDB&lt;/em&gt;&lt;/a&gt; table using a Customer Managed key (CMK).&lt;/p&gt;

&lt;h2&gt;
  
  
  Why do we need to encrypt data at rest?
&lt;/h2&gt;

&lt;p&gt;AWS data stores offer encryption at rest using configurable options that we control. These encryption options leverage the AWS Key Management Service (AWS KMS) and keys that either we or AWS manage. By default, data on Amazon DynamoDB tables is fully encrypted. AWS offers several encryption tools, including &lt;a href="https://docs.aws.amazon.com/crypto/latest/userguide/awscryp-service-toplevel.html" rel="noopener noreferrer"&gt;&lt;em&gt;AWS Cryptographic Services and Tools&lt;/em&gt;&lt;/a&gt;, and &lt;a href="https://aws.amazon.com/kms/" rel="noopener noreferrer"&gt;AWS KMS&lt;/a&gt;. In this article, we will focus on adding encryption to DynamoDB using a &lt;a href="https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#key-mgmt" rel="noopener noreferrer"&gt;AWS KMS CMK&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The importance of encrypting data at rest includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ensuring sensitive data stored on disks is not readable by any user or application without a valid key.&lt;/li&gt;
&lt;li&gt;Maintaining the confidentiality and protection of sensitive information from unauthorized access.&lt;/li&gt;
&lt;li&gt;Enhancing customer trust by demonstrating a commitment to data security and privacy.&lt;/li&gt;
&lt;li&gt;Minimizing the impact of data breaches on business operations and reputation.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to Encrypt a DynamoDB Table Using AWS KMS CMK
&lt;/h2&gt;

&lt;p&gt;The steps below guides on how to encrypt a DynamoDB table using AWS KMS CMK from AWS Management Console:&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Create an AWS KMS Customer Managed Key
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Log in to your &lt;strong&gt;AWS Management Console&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Navigate to AWS Key Management Service (KMS)&lt;/strong&gt; and click on &lt;strong&gt;Create key&lt;/strong&gt;.&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%2Feu5ix93fzf3ndnw5wqfq.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%2Feu5ix93fzf3ndnw5wqfq.png" alt="Create key image on management console" width="800" height="356"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Configure Key&lt;/strong&gt;.&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%2Fewe13a98nrgihb4w3zts.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%2Fewe13a98nrgihb4w3zts.png" alt="Configure key image on management console" width="800" height="619"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Configure Add Labels&lt;/strong&gt;: Name the key "mykey".&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%2Fskozjw97ltzogv74ye1s.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%2Fskozjw97ltzogv74ye1s.png" alt="Configure Add Labels" width="800" height="771"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Define Key Administrative Permissions and Usage Permissions&lt;/strong&gt;. &lt;a href="https://repost.aws/questions/QU4A3jhSKwRy-3vUUrS2Fqzw/assign-role-for-administrative-and-usage-permission-kms" rel="noopener noreferrer"&gt;&lt;em&gt;Read more&lt;/em&gt;&lt;/a&gt; about assigning roles for administrative and usage permissions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Review your configurations&lt;/strong&gt; and click &lt;strong&gt;Finish&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 2: Encrypt DynamoDB Table Data Using the Key
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Go to the DynamoDB console&lt;/strong&gt; and select &lt;strong&gt;Tables&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click on &lt;strong&gt;Create table&lt;/strong&gt;.&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%2F8oa6ouvwz5sv7tjicugx.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%2F8oa6ouvwz5sv7tjicugx.png" alt="Click on Create table" width="514" height="91"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;On the next page, name your table "&lt;code&gt;myTable&lt;/code&gt;" and add a partition key.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In &lt;strong&gt;Table Settings&lt;/strong&gt;, click on &lt;strong&gt;Customize settings&lt;/strong&gt;.&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%2Fs2qmm602dw5zojg4iutz.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%2Fs2qmm602dw5zojg4iutz.png" alt="Customize settings" width="800" height="784"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Scroll down to &lt;strong&gt;Encryption at rest&lt;/strong&gt; and add your custom key.&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%2Fz2dhq180kvd37k0k1zuc.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%2Fz2dhq180kvd37k0k1zuc.png" alt="Add our own custom key" width="800" height="383"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Choose the key you created named "mykey".&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click &lt;strong&gt;Create table&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&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%2Fjfoukzvclyptnqjbcc15.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%2Fjfoukzvclyptnqjbcc15.png" alt="Create table" width="495" height="209"&gt;&lt;/a&gt;&lt;br&gt;
Your table will now be encrypted using the selected CMK.&lt;/p&gt;

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

&lt;p&gt;Encrypting data at rest in AWS is a critical step in ensuring the security and integrity of your organization's sensitive information. By leveraging AWS KMS Customer Managed Keys (CMK), you can maintain control over your encryption keys and meet compliance requirements. This guide has walked you through the process of creating a custom key and using it to encrypt a DynamoDB table. Implementing these encryption practices not only protects your data from unauthorized access but also enhances customer trust and minimizes the impact of potential data breaches. Prioritizing data security is essential for safeguarding your business operations and reputation.&lt;/p&gt;

&lt;p&gt;Follow my social handles for more on AWS Serverless services:&lt;br&gt;
Click to follow on&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/sherifawofiranye" rel="noopener noreferrer"&gt;&lt;em&gt;LinkedIn&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.x.com/sherif_on_x" rel="noopener noreferrer"&gt;&lt;em&gt;Twitter&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/iamsherif"&gt;&lt;em&gt;Dev&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@awofiranyesherif4" rel="noopener noreferrer"&gt;&lt;em&gt;Medium&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>security</category>
      <category>serverless</category>
      <category>data</category>
      <category>dynamodb</category>
    </item>
    <item>
      <title>How to validate requests in Amazon API Gateway using Request Validator and Validator Model in AWS CDK</title>
      <dc:creator>iAmSherif 💎</dc:creator>
      <pubDate>Sun, 30 Jun 2024 21:39:19 +0000</pubDate>
      <link>https://dev.to/iamsherif/how-to-validate-requests-in-amazon-api-gateway-4n78</link>
      <guid>https://dev.to/iamsherif/how-to-validate-requests-in-amazon-api-gateway-4n78</guid>
      <description>&lt;p&gt;In this article, I will share my experience validating requests in Amazon API Gateway. First, let's start with why you need to validate requests at the API Gateway level.&lt;br&gt;
One of the key features of Serverless architecture is its cost-efficient model (pay-per-use). By following best practices, validating requests at the API Gateway level is a good idea for efficiency and security. It's also worth noting that API Gateway does not charge for unauthorized or invalid requests. When an endpoint is invoked with a bad request, API Gateway intercepts and rejects the request, returning a 400 status code to the user.&lt;/p&gt;

&lt;p&gt;API Gateway is a fully managed AWS service that makes it easy for developers to create, publish, maintain, monitor, and secure APIs at any scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  API Gateway Model and RequestValidator Class
&lt;/h2&gt;

&lt;p&gt;We can request validation from API Gateway by using the &lt;code&gt;RequestValidator&lt;/code&gt; in &lt;code&gt;api-gateway&lt;/code&gt; module from the &lt;code&gt;aws-cdk-lib&lt;/code&gt; library.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code Sample:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const requestValidator = new RequestValidator(
      this,
      "RequestValidator",
      {
        restApi: api,
        requestValidatorName: "requestBodyValidator",
        validateRequestBody: true,
        validateRequestParameters: false,
      }
    );
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The props:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;restApi: The string identifier of the associated RestApi. (api) is a reference to the API Gateway instance.&lt;/li&gt;
&lt;li&gt;requestValidatorName: The name of this RequestValidator.&lt;/li&gt;
&lt;li&gt;validateRequestBody: A Boolean flag indicating whether to validate the request body according to the configured &lt;em&gt;Model schema&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;validateRequestParameters: A Boolean flag indicating whether to validate request parameters (true) or not (false).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;RequestValidator&lt;/code&gt; helps set up basic validation rules for incoming requests to the API. To validate the request body, we need to set up a &lt;code&gt;Model&lt;/code&gt; schema. The Model schema defines the structure of a request or response payload for an API method.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a Model Schema
&lt;/h3&gt;

&lt;p&gt;Let's create a Model schema for an API Gateway request validator that includes &lt;code&gt;firstName&lt;/code&gt;, &lt;code&gt;lastName&lt;/code&gt;, and &lt;code&gt;portfolioLink&lt;/code&gt; as properties.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code Sample:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const validatorModel = new Model(this, "RequestValidatorModel", {
      restApi: api,
      contentType: "application/json",
      description: "Validate Long Url",
      modelName: "ValidatorModel",
      schema: {
        schema: JsonSchemaVersion.DRAFT4,
        title: "ModelValidator",
        type: JsonSchemaType.OBJECT,
        properties: {
          firstName: {
            type: JsonSchemaType.STRING,
            minLength: 1,
          },
          lastName: {
            type: JsonSchemaType.STRING,
            minLength: 1,
          },
          portfolioLink: {
            type: JsonSchemaType.STRING,
            pattern: "^(http://|https://|www\\.).*",
          }
        },
        required: ["firstName", "lastName"],
      },
    });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this &lt;code&gt;Model&lt;/code&gt;, we defined &lt;code&gt;firstName&lt;/code&gt; and &lt;code&gt;lastName&lt;/code&gt; as required properties in the request payload with a minimum length of 1. We also defined &lt;code&gt;portfolioLink&lt;/code&gt; of type String and enforced a specific regex pattern.&lt;/p&gt;

&lt;p&gt;The Props:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;restApi&lt;/code&gt;: The string identifier of the associated RestApi - (api) is a reference to API Gateway instance.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;contentType&lt;/code&gt;: The content type for the model. By default, it is 'application/json', so if you are configuring for text, it will be 'text/HTML'.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;description&lt;/code&gt;: A string that identifies the model.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;modelName&lt;/code&gt;: A name for the model. By default, AWS CloudFormation generates a unique physical ID and uses that ID for the model name.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;schema&lt;/code&gt;: The schema to use to transform data to one or more output formats. In API Gateway models are defined using the JSON schema draft 4. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;title&lt;/code&gt;: Defines the schema title.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;type&lt;/code&gt;: Specifies that the root of the JSON document must be an object.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;properties&lt;/code&gt;: Defines the properties the object must have.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;required&lt;/code&gt;: A list of properties that must be present in the object. In our case, &lt;code&gt;firstName&lt;/code&gt; and &lt;code&gt;lastName&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Attaching the Model and Validator to an API Gateway Method
&lt;/h3&gt;

&lt;p&gt;Next, we need to attach our &lt;code&gt;Model&lt;/code&gt; and &lt;code&gt;RequestValidator&lt;/code&gt; to an API Gateway method.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code Sample:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;api.root
      .addResource("/user")
      .addMethod("POST", user, {
        requestModels: {
          "application/json": validatorModel,
        },
        requestValidator: requestValidator,
      });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By following these steps, you can efficiently validate requests at the API Gateway level, ensuring that only properly structured requests reach your backend services. This not only improves security but also reduces unnecessary processing and potential costs.&lt;/p&gt;

</description>
      <category>apigateway</category>
      <category>serverless</category>
      <category>cloudcomputing</category>
      <category>aws</category>
    </item>
    <item>
      <title>Getting started with AWS Serverless architecture: A Paradigm Shift in Cloud Computing</title>
      <dc:creator>iAmSherif 💎</dc:creator>
      <pubDate>Tue, 28 Nov 2023 23:26:11 +0000</pubDate>
      <link>https://dev.to/iamsherif/getting-started-with-aws-serverless-architecture-a-paradigm-shift-in-cloud-computing-2ioe</link>
      <guid>https://dev.to/iamsherif/getting-started-with-aws-serverless-architecture-a-paradigm-shift-in-cloud-computing-2ioe</guid>
      <description>&lt;p&gt;Let’s delve into the realm of &lt;strong&gt;Serverless architecture&lt;/strong&gt;, where traditional deployment challenges find a transformative solution.&lt;/p&gt;

&lt;p&gt;In the past, deploying a web application on AWS often meant relying on a single server, typically an AWS EC2 instance. While EC2 instances can scale vertically to an extent, accommodating increased demand, they face limitations as traffic surges.&lt;/p&gt;

&lt;p&gt;Enter the Load Balancer👽 — a solution to handle escalating traffic by dynamically adding more servers, a concept known as horizontal scaling. However, this approach poses cost challenges. Picture this: a traffic spike on Monday prompts the Load Balancer to provision additional instances, incurring costs even during idle periods when the traffic subsides.&lt;/p&gt;

&lt;p&gt;To address this, the Auto Scaling Group comes into play, efficiently managing server instances based on demand. This ensures optimal resource utilization and cost savings, especially during periods of reduced traffic.&lt;/p&gt;

&lt;p&gt;Yet, the intricacies of manual configurations for server health and high availability raise a pertinent question: Isn’t this a lot of work?🤯🤯&lt;/p&gt;

&lt;p&gt;This is where &lt;strong&gt;Serverless&lt;/strong&gt; steps in, a veritable knight in shining armor 💂.&lt;/p&gt;

&lt;p&gt;The Serverless platform helps deal with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;how to manage the infrastructure&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;how to make provision of instances&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;how to ensure the servers are healthy &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;what metrics to use when it’s time to scale out or scale in.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then we say “SERVERLESS” means&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;No server management &lt;/li&gt;
&lt;li&gt;Flexible scaling &lt;/li&gt;
&lt;li&gt;Automated high availability &lt;/li&gt;
&lt;li&gt;No idle capacity &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With Serverless architecture, powered by AWS Lambda functions, you can run code without the hassle of provisioning or managing servers. It is an event-driven, Serverless compute service that not only reduces operational burdens but also provides flexible scaling, automated high availability across multiple zones, and substantial cost savings through its “pay-per-execution” model.&lt;/p&gt;

&lt;p&gt;In essence, AWS Serverless architecture streamlines your deployment process, decreases time to complete processes, and offers an environment that closely mimics production — all with the ease of AWS Lambda functions at its core. It makes it easier to set up your app, saves you money, and takes away the hassle of managing servers. It's like having your own tech assistant handling the tough stuff.&lt;/p&gt;

&lt;p&gt;Follow on LinkedIn and Twitter for more on AWS Serverless architecture:&lt;/p&gt;

&lt;p&gt;click to follow on &lt;a href="https://www.linkedin.com/in/sherifawofiranye" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;click to follow on &lt;a href="https://www.x.com/awofiranyesher2" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloudcomputing</category>
      <category>serverless</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
