<?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: Sidath Munasinghe</title>
    <description>The latest articles on DEV Community by Sidath Munasinghe (@sidathasiri).</description>
    <link>https://dev.to/sidathasiri</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%2F1018679%2F8ecdd5d4-06fb-4d2f-99f0-340caece6577.jpeg</url>
      <title>DEV Community: Sidath Munasinghe</title>
      <link>https://dev.to/sidathasiri</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sidathasiri"/>
    <language>en</language>
    <item>
      <title>Efficient Nested Resolvers in AWS AppSync with Lambda Batching</title>
      <dc:creator>Sidath Munasinghe</dc:creator>
      <pubDate>Thu, 12 Jun 2025 13:36:38 +0000</pubDate>
      <link>https://dev.to/aws-builders/efficient-nested-resolvers-in-aws-appsync-with-lambda-batching-1771</link>
      <guid>https://dev.to/aws-builders/efficient-nested-resolvers-in-aws-appsync-with-lambda-batching-1771</guid>
      <description>&lt;p&gt;GraphQL has emerged as a modern alternative to RESTful APIs, offering a more flexible and efficient way for clients to query data. Unlike REST, where clients often make multiple requests to different endpoints and receive fixed response structures, GraphQL allows clients to request exactly the data they need — and nothing more — in a single round trip. This reduces the issues of over-fetching and under-fetching common in REST, and gives frontend developers more control over the shape of the response.&lt;/p&gt;

&lt;p&gt;AWS AppSync is a managed service that helps developers build scalable, real-time GraphQL APIs with minimal operational overhead. It integrates seamlessly with various AWS data sources, including DynamoDB, Lambda, RDS, and OpenSearch, and supports features such as offline access, subscriptions, and fine-grained authorization. AppSync takes care of scaling and security, allowing teams to focus on defining their data and resolvers.&lt;/p&gt;

&lt;p&gt;In AppSync, resolvers are the core building blocks that connect GraphQL fields to data sources. Each field in a GraphQL query — including nested fields — can have its own resolver. When a query is executed, AppSync invokes these resolvers individually, mapping request and response data using Velocity templates (VTL) or direct Lambda functions. While this resolver-per-field model gives developers flexibility, it can introduce a performance challenge known as the N+1 problem when working with nested data.&lt;/p&gt;

&lt;p&gt;In this post, we’ll explore what the N+1 problem looks like in AWS AppSync, why it becomes a bottleneck at scale, and how to architect efficient resolvers to solve it using batch resolvers and Lambda optimizations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the N+1 Problem in AppSync
&lt;/h2&gt;

&lt;p&gt;When working with GraphQL, it’s common to request nested data in a single query. AppSync supports this by allowing each field — including deeply nested ones — to have its own resolver that fetches data from a backend data source. While this design provides flexibility and modularity, it can lead to an inefficient execution pattern known as the &lt;strong&gt;N+1 problem&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Is the N+1 Problem?
&lt;/h3&gt;

&lt;p&gt;The N+1 problem usually occurs with list queries. When your GraphQL API ends up making one query to fetch the root items (1), and N additional queries for each nested field, where N is the number of root items returned in the list.&lt;/p&gt;

&lt;p&gt;Let’s take an example to understand this clearly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;query {
  books {
    name
    title
    author {
      firstnName
      lastName
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s what typically happens behind the scenes in AppSync&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%2Fv91bx4endfw371zruobu.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%2Fv91bx4endfw371zruobu.png" alt="Query execution plan" width="336" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;books resolver fetches a list of books — let’s say 100 (N) items.&lt;/li&gt;
&lt;li&gt;For each of those 100 books, the author resolver is called individually (resulting in 100 calls).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In total, that’s 1 + 100 = 101 (N+1) resolver invocations for a single client query.&lt;/p&gt;

&lt;p&gt;If you have even more nested queries, this becomes worse. In the below query, there is an additional field (address) that requires more resolver invocations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;query {
  books {
    name
    title
    author {
      firstName
      lastName
      address {
        city
        state
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;books resolver fetches a list of books — let’s say 100 items.&lt;/li&gt;
&lt;li&gt;For each of those 100 books, the author resolver is called individually (resulting in 100 calls).&lt;/li&gt;
&lt;li&gt;Then for each author, the address resolver is called again (another 100 calls).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In total, that’s &lt;strong&gt;1 + 100 + 100 = 301&lt;/strong&gt; resolver invocations for a single client query.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Is This a Problem?
&lt;/h2&gt;

&lt;p&gt;This approach scales poorly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Performance degrades linearly with the number of parent items.&lt;/li&gt;
&lt;li&gt;It results in high latency due to the number of sequential or parallel resolver invocations.&lt;/li&gt;
&lt;li&gt;It increases backend load and pressure on data sources like Lambda, RDS, or DynamoDB.&lt;/li&gt;
&lt;li&gt;It can quickly hit throttling limits or increase costs when using Lambda or other pay-per-request services.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While this might be acceptable for small datasets or low traffic, the N+1 pattern becomes a serious performance bottleneck at scale. Imagine serving thousands of queries per second — this inefficient pattern can overwhelm backend systems, increase response times, and degrade the user experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solving N+1 with Batch Resolvers in AppSync
&lt;/h2&gt;

&lt;p&gt;One of the most effective ways to overcome the N+1 problem in AWS AppSync is by using batch resolvers. The idea is simple: instead of resolving nested fields one-by-one (which results in many resolver calls), we batch them together into a single call , usually handled by a Lambda function.&lt;/p&gt;

&lt;p&gt;Let’s explore how this works and why it’s such a powerful pattern.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Batch Resolvers Work
&lt;/h3&gt;

&lt;p&gt;In AppSync, each nested field (such as author or address) can have its own resolver, which is typically invoked for each parent object.&lt;/p&gt;

&lt;p&gt;To convert this into a batch operation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Instead of calling the author resolver N times (once for each book), you configure the author field to invoke a single Lambda function that accepts a list of book IDs (or author IDs).&lt;/li&gt;
&lt;li&gt;This Lambda function fetches all the authors in one go and returns the results mapped back to their respective books.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think of it as “fan-in” batching: one resolver invocation processes multiple parent objects.&lt;/p&gt;

&lt;p&gt;Let’s apply this to our previous query and see how this works.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;query {
  books {
    name
    title
    author {
      firstName
      lastName
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you use a batch resolver for the author field:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AppSync groups all books[*].author field resolvers into one Lambda call.&lt;/li&gt;
&lt;li&gt;You receive an array of bookIds or authorIds within the lambda function.&lt;/li&gt;
&lt;li&gt;The Lambda fetches and returns the authors in bulk.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this optimization, you’ve reduced the number of records from N+1 to just 2, which is a substantial improvement. Moreover, it’s now independent of the number of records.&lt;/p&gt;

&lt;p&gt;Here are some additional benefits of this solution:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fewer Resolver Invocations:&lt;/strong&gt; Reduces hundreds of resolver calls to just one. This saves you from the lambda concurrency limit and also reduces the pressure on downstream services.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Faster Performance:&lt;/strong&gt; Lower network overhead and latency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clean Separation:&lt;/strong&gt; Keeps resolver responsibilities modular while still optimizing performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost-Efficient:&lt;/strong&gt; Fewer Lambda invocations result in reduced AWS costs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Enabling Batch Resolvers
&lt;/h3&gt;

&lt;p&gt;Batch resolvers are currently only compatible with Lambda data sources, and this feature is not enabled by default. However, enabling this is very straightforward.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a Lambda datasource as usual&lt;/li&gt;
&lt;li&gt;Go to create a resolver and select the created Lambda datasource&lt;/li&gt;
&lt;li&gt;Enable batching and set the batching size&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%2Fumakcd3wvjbz252iwgtq.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%2Fumakcd3wvjbz252iwgtq.png" alt="Enabling lambda batching" width="800" height="135"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;4.Update the resolver request function to use the BatchInvoke operation&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export function request(ctx) {
    return {
        operation: 'BatchInvoke',
        payload: {
            ctx: ctx
        },
    };
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;5.Now your lambda function will receive not a single context, but an array of contexts for each listed item. You can update the lambda function logic to do a batch get and return the results. You must ensure the returned items are in the same order as the received context order.&lt;/p&gt;

&lt;p&gt;It’s as simple as that, but it offers significant performance gains to your GraphQL service.&lt;/p&gt;

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

&lt;p&gt;Optimizing GraphQL queries in AWS AppSync is essential when building scalable and performant APIs — especially when dealing with nested data structures. The N+1 problem, while subtle, can lead to serious performance bottlenecks if left unaddressed.&lt;/p&gt;

&lt;p&gt;By leveraging batch resolvers, you can drastically reduce the number of resolver calls, minimize round-trips to your data source, and deliver faster, more efficient responses to your clients. Whether you choose direct Lambda resolvers or pipeline resolvers, designing with batching in mind ensures your AppSync APIs are ready to perform at scale.&lt;/p&gt;

&lt;p&gt;As your application grows, keeping an eye on resolver patterns and query performance becomes even more important. With the right strategy, tools, and architecture in place, you can build GraphQL services that are both elegant and efficient.&lt;/p&gt;

</description>
      <category>appsync</category>
      <category>aws</category>
      <category>graphql</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Efficient Nested Resolvers in AWS AppSync with Lambda Batching</title>
      <dc:creator>Sidath Munasinghe</dc:creator>
      <pubDate>Thu, 12 Jun 2025 13:36:38 +0000</pubDate>
      <link>https://dev.to/aws-builders/efficient-nested-resolvers-in-aws-appsync-with-lambda-batching-3jin</link>
      <guid>https://dev.to/aws-builders/efficient-nested-resolvers-in-aws-appsync-with-lambda-batching-3jin</guid>
      <description>&lt;p&gt;GraphQL has emerged as a modern alternative to RESTful APIs, offering a more flexible and efficient way for clients to query data. Unlike REST, where clients often make multiple requests to different endpoints and receive fixed response structures, GraphQL allows clients to request exactly the data they need — and nothing more — in a single round trip. This reduces the issues of over-fetching and under-fetching common in REST, and gives frontend developers more control over the shape of the response.&lt;/p&gt;

&lt;p&gt;AWS AppSync is a managed service that helps developers build scalable, real-time GraphQL APIs with minimal operational overhead. It integrates seamlessly with various AWS data sources, including DynamoDB, Lambda, RDS, and OpenSearch, and supports features such as offline access, subscriptions, and fine-grained authorization. AppSync takes care of scaling and security, allowing teams to focus on defining their data and resolvers.&lt;/p&gt;

&lt;p&gt;In AppSync, resolvers are the core building blocks that connect GraphQL fields to data sources. Each field in a GraphQL query — including nested fields — can have its own resolver. When a query is executed, AppSync invokes these resolvers individually, mapping request and response data using Velocity templates (VTL) or direct Lambda functions. While this resolver-per-field model gives developers flexibility, it can introduce a performance challenge known as the N+1 problem when working with nested data.&lt;/p&gt;

&lt;p&gt;In this post, we’ll explore what the N+1 problem looks like in AWS AppSync, why it becomes a bottleneck at scale, and how to architect efficient resolvers to solve it using batch resolvers and Lambda optimizations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the N+1 Problem in AppSync
&lt;/h2&gt;

&lt;p&gt;When working with GraphQL, it’s common to request nested data in a single query. AppSync supports this by allowing each field — including deeply nested ones — to have its own resolver that fetches data from a backend data source. While this design provides flexibility and modularity, it can lead to an inefficient execution pattern known as the &lt;strong&gt;N+1 problem&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Is the N+1 Problem?
&lt;/h3&gt;

&lt;p&gt;The N+1 problem usually occurs with list queries. When your GraphQL API ends up making one query to fetch the root items (1), and N additional queries for each nested field, where N is the number of root items returned in the list.&lt;/p&gt;

&lt;p&gt;Let’s take an example to understand this clearly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;query {
  books {
    name
    title
    author {
      firstnName
      lastName
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s what typically happens behind the scenes in AppSync&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%2Fv91bx4endfw371zruobu.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%2Fv91bx4endfw371zruobu.png" alt="Query execution plan" width="336" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;books resolver fetches a list of books — let’s say 100 (N) items.&lt;/li&gt;
&lt;li&gt;For each of those 100 books, the author resolver is called individually (resulting in 100 calls).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In total, that’s 1 + 100 = 101 (N+1) resolver invocations for a single client query.&lt;/p&gt;

&lt;p&gt;If you have even more nested queries, this becomes worse. In the below query, there is an additional field (address) that requires more resolver invocations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;query {
  books {
    name
    title
    author {
      firstName
      lastName
      address {
        city
        state
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;books resolver fetches a list of books — let’s say 100 items.&lt;/li&gt;
&lt;li&gt;For each of those 100 books, the author resolver is called individually (resulting in 100 calls).&lt;/li&gt;
&lt;li&gt;Then for each author, the address resolver is called again (another 100 calls).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In total, that’s &lt;strong&gt;1 + 100 + 100 = 301&lt;/strong&gt; resolver invocations for a single client query.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Is This a Problem?
&lt;/h2&gt;

&lt;p&gt;This approach scales poorly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Performance degrades linearly with the number of parent items.&lt;/li&gt;
&lt;li&gt;It results in high latency due to the number of sequential or parallel resolver invocations.&lt;/li&gt;
&lt;li&gt;It increases backend load and pressure on data sources like Lambda, RDS, or DynamoDB.&lt;/li&gt;
&lt;li&gt;It can quickly hit throttling limits or increase costs when using Lambda or other pay-per-request services.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While this might be acceptable for small datasets or low traffic, the N+1 pattern becomes a serious performance bottleneck at scale. Imagine serving thousands of queries per second — this inefficient pattern can overwhelm backend systems, increase response times, and degrade the user experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solving N+1 with Batch Resolvers in AppSync
&lt;/h2&gt;

&lt;p&gt;One of the most effective ways to overcome the N+1 problem in AWS AppSync is by using batch resolvers. The idea is simple: instead of resolving nested fields one-by-one (which results in many resolver calls), we batch them together into a single call , usually handled by a Lambda function.&lt;/p&gt;

&lt;p&gt;Let’s explore how this works and why it’s such a powerful pattern.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Batch Resolvers Work
&lt;/h3&gt;

&lt;p&gt;In AppSync, each nested field (such as author or address) can have its own resolver, which is typically invoked for each parent object.&lt;/p&gt;

&lt;p&gt;To convert this into a batch operation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Instead of calling the author resolver N times (once for each book), you configure the author field to invoke a single Lambda function that accepts a list of book IDs (or author IDs).&lt;/li&gt;
&lt;li&gt;This Lambda function fetches all the authors in one go and returns the results mapped back to their respective books.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think of it as “fan-in” batching: one resolver invocation processes multiple parent objects.&lt;/p&gt;

&lt;p&gt;Let’s apply this to our previous query and see how this works.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;query {
  books {
    name
    title
    author {
      firstName
      lastName
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you use a batch resolver for the author field:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AppSync groups all books[*].author field resolvers into one Lambda call.&lt;/li&gt;
&lt;li&gt;You receive an array of bookIds or authorIds within the lambda function.&lt;/li&gt;
&lt;li&gt;The Lambda fetches and returns the authors in bulk.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this optimization, you’ve reduced the number of records from N+1 to just 2, which is a substantial improvement. Moreover, it’s now independent of the number of records.&lt;/p&gt;

&lt;p&gt;Here are some additional benefits of this solution:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fewer Resolver Invocations:&lt;/strong&gt; Reduces hundreds of resolver calls to just one. This saves you from the lambda concurrency limit and also reduces the pressure on downstream services.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Faster Performance:&lt;/strong&gt; Lower network overhead and latency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clean Separation:&lt;/strong&gt; Keeps resolver responsibilities modular while still optimizing performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost-Efficient:&lt;/strong&gt; Fewer Lambda invocations result in reduced AWS costs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Enabling Batch Resolvers
&lt;/h3&gt;

&lt;p&gt;Batch resolvers are currently only compatible with Lambda data sources, and this feature is not enabled by default. However, enabling this is very straightforward.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a Lambda datasource as usual&lt;/li&gt;
&lt;li&gt;Go to create a resolver and select the created Lambda datasource&lt;/li&gt;
&lt;li&gt;Enable batching and set the batching size&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%2Fumakcd3wvjbz252iwgtq.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%2Fumakcd3wvjbz252iwgtq.png" alt="Enabling lambda batching" width="800" height="135"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;4.Update the resolver request function to use the BatchInvoke operation&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export function request(ctx) {
    return {
        operation: 'BatchInvoke',
        payload: {
            ctx: ctx
        },
    };
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;5.Now your lambda function will receive not a single context, but an array of contexts for each listed item. You can update the lambda function logic to do a batch get and return the results. You must ensure the returned items are in the same order as the received context order.&lt;/p&gt;

&lt;p&gt;It’s as simple as that, but it offers significant performance gains to your GraphQL service.&lt;/p&gt;

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

&lt;p&gt;Optimizing GraphQL queries in AWS AppSync is essential when building scalable and performant APIs — especially when dealing with nested data structures. The N+1 problem, while subtle, can lead to serious performance bottlenecks if left unaddressed.&lt;/p&gt;

&lt;p&gt;By leveraging batch resolvers, you can drastically reduce the number of resolver calls, minimize round-trips to your data source, and deliver faster, more efficient responses to your clients. Whether you choose direct Lambda resolvers or pipeline resolvers, designing with batching in mind ensures your AppSync APIs are ready to perform at scale.&lt;/p&gt;

&lt;p&gt;As your application grows, keeping an eye on resolver patterns and query performance becomes even more important. With the right strategy, tools, and architecture in place, you can build GraphQL services that are both elegant and efficient.&lt;/p&gt;

</description>
      <category>appsync</category>
      <category>aws</category>
      <category>graphql</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Creating Smart AI Agents with AWS Bedrock</title>
      <dc:creator>Sidath Munasinghe</dc:creator>
      <pubDate>Mon, 23 Dec 2024 05:43:35 +0000</pubDate>
      <link>https://dev.to/aws-builders/creating-smart-ai-agents-with-aws-bedrock-4741</link>
      <guid>https://dev.to/aws-builders/creating-smart-ai-agents-with-aws-bedrock-4741</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Generative AI is transforming industries by automating tasks, improving user experiences, and driving efficiency. One of the most powerful uses of AI is the creation of AI agents — intelligent systems that can perform tasks autonomously based on user input or predefined rules. These agents are being used in everything from customer support to data analysis and even in complex decision-making systems. With the advent of AWS Bedrock, building these AI agents has become more accessible than ever.&lt;/p&gt;

&lt;p&gt;In this post, we'll dive into what AI agents are, why AWS Bedrock is the perfect platform to build them and guide you through creating your first AI agent on AWS Bedrock.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding AI Agents
&lt;/h2&gt;

&lt;p&gt;AI agents are autonomous systems that perform tasks or make decisions without continuous human intervention. They can interact with users, learn from data, and even evolve.&lt;/p&gt;

&lt;p&gt;Common types of AI agents include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Chatbots:&lt;/strong&gt; AI agents that simulate human conversations to assist customers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recommendation Systems:&lt;/strong&gt; AI agents that suggest products or content based on user behavior.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Personal Assistants:&lt;/strong&gt; Agents that help users by scheduling tasks, setting reminders, and more.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automation Bots:&lt;/strong&gt; Agents that automate repetitive business processes, such as data entry or transaction processing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI agents can either be reactive (responding to user inputs) or proactive (anticipating user needs based on patterns or previous interactions). In this guide, we will focus on building an AI agent that leverages AWS Bedrock for its powerful foundation models.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Use AWS Bedrock for AI Agents?
&lt;/h2&gt;

&lt;p&gt;AWS Bedrock provides a suite of tools and services designed to simplify the creation, customization, and deployment of AI models.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Never heard of BedRock before? Read my previous post &lt;a href="https://sidathasiri.github.io/2024/05/01/Generative-AI-on-AWS-with-Amazon-Bedrock/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It offers several benefits when building AI agents:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Access to State-of-the-Art Foundation Models:&lt;/strong&gt; AWS Bedrock provides pre-trained models from top AI research labs like Anthropic, Stability AI, and Cohere. These models serve as the backbone for your AI agents, allowing you to focus on customization rather than training models from scratch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Serverless Architecture:&lt;/strong&gt; AWS Bedrock takes care of the infrastructure, enabling you to build AI agents without worrying about scaling or resource management. This makes it an ideal solution for businesses of all sizes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customizable Models:&lt;/strong&gt; While you can use pre-trained models, AWS Bedrock also allows you to fine-tune these models on your own datasets. This means your AI agent can be trained for specific domains, such as customer support or medical inquiries, enhancing its accuracy and relevance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Seamless Integration with AWS Services:&lt;/strong&gt; AWS Bedrock integrates well with other AWS services like Lambda, S3, etc, enabling you to create a fully integrated solution that can interact with other applications or databases in your environment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security and Compliance:&lt;/strong&gt; With AWS Bedrock, you benefit from the robust security and compliance features provided by AWS, ensuring your AI agents operate securely and meet industry standards.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Components of an AI Agent
&lt;/h2&gt;

&lt;p&gt;An AI Agent has several components. The diagram below illustrates the high-level architecture of how Bedrock agents operate. AWS Bedrock simplifies these components, making it easier for developers to build and deploy AI agents. Let's explore each component. Since it is entirely serverless, we only need to configure each component to make the agent work as we require.&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%2Frpwbe0gakm8mj2dr7d69.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%2Frpwbe0gakm8mj2dr7d69.png" alt="Source: https://docs.aws.amazon.com/bedrock/latest/userguide/agents-how.html&amp;lt;br&amp;gt;
" width="388" height="307"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, let's take a moment to understand the purpose of each component.&lt;/p&gt;
&lt;h3&gt;
  
  
  Foundational model
&lt;/h3&gt;

&lt;p&gt;The foundational model serves as the &lt;strong&gt;“backbone”&lt;/strong&gt; of your AI agent. These pre-trained, large-scale machine learning models provide natural language understanding, text generation, and more capabilities. AWS Bedrock offers access to various foundational models from leading providers like Anthropic, HuggingFace, Cohere, Amazon, and many more.&lt;/p&gt;

&lt;p&gt;The foundational model provides the base intelligence for the agent, saving you from the need to train models from scratch.&lt;/p&gt;
&lt;h3&gt;
  
  
  Instructions
&lt;/h3&gt;

&lt;p&gt;Instructions act as the “brain” of the AI agent by defining how the foundational model should behave. These guidelines specify the scope, tone, and task of the agent. Instructions can include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The agent's role (e.g., “You are a customer service assistant.”).&lt;/li&gt;
&lt;li&gt;Behavior and restrictions (e.g., “Answer politely and avoid technical jargon.”).&lt;/li&gt;
&lt;li&gt;Desired outputs (e.g., “Provide short, concise answers.”).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Providing clear instructions ensures the foundational model behaves according to your application's requirements.&lt;/p&gt;
&lt;h3&gt;
  
  
  Action Groups
&lt;/h3&gt;

&lt;p&gt;Action groups enable the AI agent to &lt;strong&gt;perform specific tasks or trigger actions&lt;/strong&gt; beyond text generation. These could include API calls, database queries, or interactions with other systems. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Retrieving user details from a database.&lt;/li&gt;
&lt;li&gt;Sending notifications via an email or messaging API.&lt;/li&gt;
&lt;li&gt;Performing calculations or processing data inputs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Action groups allow the AI agent to go beyond static responses and interact dynamically with external systems, making it more functional and capable of solving real-world problems.&lt;/p&gt;

&lt;p&gt;In Bedrock, you can integrate a lambda function or OpenAPI schema to define the API operations to invoke an API.&lt;/p&gt;
&lt;h3&gt;
  
  
  Knowledge bases
&lt;/h3&gt;

&lt;p&gt;A knowledge base provides the AI agent with &lt;strong&gt;domain-specific information&lt;/strong&gt;, enabling it to answer questions or perform tasks that require contextual knowledge. AWS Bedrock allows you to integrate custom datasets (e.g., documents, product catalogs, FAQs) as a knowledge base.&lt;/p&gt;

&lt;p&gt;The agent uses this knowledge base to generate more accurate and relevant responses tailored to your organization or use case. Due to this, it is optional to use a knowledge base.&lt;/p&gt;
&lt;h3&gt;
  
  
  Prompt Templates
&lt;/h3&gt;

&lt;p&gt;Prompt templates provide a structured way to send input to the foundational model. They combine user input with predefined instructions or placeholders to ensure consistency in responses. Amazon Bedrock Agents exposes the default four base prompt templates that are used during the pre-processing, orchestration, knowledge base response generation, and post-processing. By optionally customizing these prompt templates, you can control the quality and format of the AI agent's behavior &amp;amp; outputs.&lt;/p&gt;
&lt;h2&gt;
  
  
  Creating Your First AI Agent
&lt;/h2&gt;

&lt;p&gt;In this section, we'll walk through the steps to create an AI agent using AWS Bedrock and see how easy it would be to create one. Here, we will create a simple AI Agent that can handle medical appointments to demonstrate its capabilities.&lt;/p&gt;

&lt;p&gt;There are several ways that we can create agents on AWS. The easiest way would be to use the conversational builder so that it will interact with us to get the requirements and create the agent according to our responses. However, we will manually configure the agent to gain a better understanding.&lt;/p&gt;

&lt;p&gt;1) First, we must request access to a foundation model that can work with agents. Here, we are going to use the &lt;strong&gt;Nova Pro&lt;/strong&gt; model. You can request access to the model via the model access section in the Bedrock configuration on the AWS Management Console.&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%2F1tdeckxod173v0oxgm2k.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%2F1tdeckxod173v0oxgm2k.png" alt="Request access for base models" width="800" height="359"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;2) Then, we can start creating an agent from the builder tools by entering the agent name and description. Since we will create only an agent and not integrate with multiple agents, we are not enabling multi-agent collaboration.&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%2Fkcye2vprvqtkgu82fnfy.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%2Fkcye2vprvqtkgu82fnfy.png" alt="Creating an agent" width="584" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;3) After that, we can further configure the agent via the agent builder. You can attach the foundation model to the agent and provide instructions. The instructor must be clear and precise to ensure the model works accurately.&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%2Fpf45sx10hgcgg46npkd9.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%2Fpf45sx10hgcgg46npkd9.png" alt="Use agent builder for further configurations" width="800" height="328"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;4) Then, we can add action groups to provide additional capabilities to the agent. Here, we are going to add three lambda functions to,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;check whether an appointment is available,&lt;/li&gt;
&lt;li&gt;list available appointments&lt;/li&gt;
&lt;li&gt;make an appointment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can create an action group in the console like the one below, which will also create a Lambda function for us. Later, we can update the logic as needed.&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%2F4qc8ep3a4mapxjsmiwv5.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%2F4qc8ep3a4mapxjsmiwv5.png" alt="Creating action groups" width="800" height="471"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Further, we need to define the required parameters for the lambda function. We must also provide a meaningful description so the AI model can infer the values from the user input and invoke the lambda function.&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%2F9u0vace72gn2uknbp80t.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%2F9u0vace72gn2uknbp80t.png" alt="Define action parameters" width="800" height="180"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can follow the same method to create all three action groups.&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%2Fq2edffmtbam7v58tyqde.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%2Fq2edffmtbam7v58tyqde.png" alt="Creating all required action groups" width="800" height="121"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;5) Once all three action groups have been created, there should also be three lambda functions corresponding to each. We need to update the logic in each lambda function to perform each action.&lt;/p&gt;

&lt;p&gt;Below is a sample lambda handler implementation to check the availability of a given appointment. You can update this implementation to query a database or invoke an API to get the result. This implementation guarantees that appointments will be available except for December 31, 2024. As you can see, we can access the previously defined parameters from the lambda event to implement the logic based on the input values.&lt;/p&gt;

&lt;p&gt;Additionally, there is an expected response structure from Lambda functions in Bedrock. The lambda handler should return the correct payload. You can find more information about this structure &lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/agents-lambda.html#agents-lambda-response" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import json

def lambda_handler(event, context):
    agent = event['agent']
    actionGroup = event['actionGroup']
    function = event['function']
    parameters = event.get('parameters', [])

    print(parameters)

    paramDict = {item['name']: item['value'] for item in parameters}

    print(paramDict['date'])
    print(paramDict['location'])
    print(paramDict['time'])
    print(paramDict['providerName'])

    # Execute your business logic here. For more information, refer to: https://docs.aws.amazon.com/bedrock/latest/userguide/agents-lambda.html
    if(paramDict['date'] == "31/12/2024"):
        print("Unavailable date")
        responseBody =  {
            "TEXT": {
                "body": "This slot is not available"
            }
        }

    else:
        print("Available date")
        responseBody =  {
            "TEXT": {
                "body": "This slot is available"
            }
        }

    action_response = {
        'actionGroup': actionGroup,
        'function': function,
        'functionResponse': {
            'responseBody': responseBody
        }

    }

    dummy_function_response = {'response': action_response, 'messageVersion': event['messageVersion']}
    print("Response: {}".format(dummy_function_response))

    return dummy_function_response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Similarly, we can implement the lambda handler to list appointments by hardcoding some available dates. Again, you can customize this to meet any specific business requirements.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import json

def lambda_handler(event, context):
    agent = event['agent']
    actionGroup = event['actionGroup']
    function = event['function']
    parameters = event.get('parameters', [])

    print("Looking for all available slots")

    # Execute your business logic here. For more information, refer to: https://docs.aws.amazon.com/bedrock/latest/userguide/agents-lambda.html
    responseBody =  {
        "TEXT": {
            "body": "These are the available slots: On 01/01/2025, an appointment is available in Colombo at 9am with Dr. Silva. Another slot is open on 15/01/2025 in Kandy at 11am with Dr. Fernando."
        }
    }

    action_response = {
        'actionGroup': actionGroup,
        'function': function,
        'functionResponse': {
            'responseBody': responseBody
        }

    }

    dummy_function_response = {'response': action_response, 'messageVersion': event['messageVersion']}
    print("Response: {}".format(dummy_function_response))

    return dummy_function_response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we can implement the lambda function to create the appointment. We will only add a print statement to confirm the behavior in the sample implementation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import json

def lambda_handler(event, context):
    agent = event['agent']
    actionGroup = event['actionGroup']
    function = event['function']
    parameters = event.get('parameters', [])

    paramDict = {item['name']: item['value'] for item in parameters}

    print("Placed appointment for:", paramDict)

    # Execute your business logic here. For more information, refer to: https://docs.aws.amazon.com/bedrock/latest/userguide/agents-lambda.html
    responseBody =  {
        "TEXT": {
            "body": "Appointment placed successfully"
        }
    }

    action_response = {
        'actionGroup': actionGroup,
        'function': function,
        'functionResponse': {
            'responseBody': responseBody
        }

    }

    dummy_function_response = {'response': action_response, 'messageVersion': event['messageVersion']}
    print("Response: {}".format(dummy_function_response))

    return dummy_function_response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need to deploy the lambda functions with the new changes we added. We must also save and update the configuration we added on Bedrock to test it.&lt;/p&gt;

&lt;p&gt;Here, we will not use a knowledge base or prompt templates to keep it simple. But we can use them to customize the agent even more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Here is the output of the agent we created. It asks for missing details if the user hasn't given enough information to proceed. Furthermore, as we defined in the lambda function, the agent says that there are no available appointments on &lt;strong&gt;31/12/2024&lt;/strong&gt; and it uses the &lt;strong&gt;ListAppointments&lt;/strong&gt; action to recommend available slots. Finally, it is using the &lt;strong&gt;CreateAppointment&lt;/strong&gt; action to make the appointment.&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%2Fqwfrwahirtrb5k4tk4dc.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%2Fqwfrwahirtrb5k4tk4dc.png" alt="Demo of the created agent" width="800" height="1030"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://drive.google.com/file/d/1zRQL1sY1j1SVlVcFLOEjbcEiYdf3UR4v/view?usp=sharing&amp;amp;source=post_page-----a638cc12fa1d--------------------------------" rel="noopener noreferrer"&gt;Here &lt;/a&gt;is a video demo of the agent we created. In the CloudWatch logs, we can see all the parameters we entered are captured correctly as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advanced Features
&lt;/h2&gt;

&lt;p&gt;Once you’ve built a basic AI agent, AWS Bedrock offers a range of advanced features that can elevate your solution to the next level. These features enable better customization, optimization, scalability, and integration, making your AI agents smarter and more adaptable for real-world applications.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Custom Fine-Tuning for Domain-Specific Tasks:&lt;/strong&gt; AWS Bedrock allows you to fine-tune foundational models to better align with specific use cases by providing domain-specific datasets (e.g., legal, healthcare, e-commerce). Using this fine-tuned model, you can enhance the agent's performance and accuracy for specialized tasks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-Agent Systems:&lt;/strong&gt; AWS Bedrock supports the design of multi-agent systems, where multiple AI agents collaborate to perform complex tasks. Each agent can specialize in a specific function and work together by exchanging data and context.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Guardrails for Safe and Responsible AI:&lt;/strong&gt; AWS Bedrock allows you to implement guardrails to ensure AI agents act responsibly and align with business and ethical guidelines. Guardrails can be customized to filter, block, or monitor specific behaviors, enhancing the trustworthiness of AI outputs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration with other AWS services:&lt;/strong&gt; By integrating with other AWS services, you can easily address countless use cases (e.g., integration with step functions to provide AI capabilities to complex workflows).&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;AI agents powered by &lt;strong&gt;AWS Bedrock&lt;/strong&gt; open up endless possibilities for businesses looking to integrate intelligent automation, enhance user experiences, and drive innovation. By leveraging foundational models, dynamic knowledge bases, guardrails, and multi-agent systems, you can build &lt;strong&gt;scalable, secure, and highly customizable solutions&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;AWS Bedrock's powerful features make it accessible to teams of all sizes, enabling them to develop sophisticated AI solutions without requiring deep machine-learning expertise. Whether you're automating workflows, building interactive customer support systems, or analyzing complex data, Bedrock provides the tools and flexibility needed to succeed.&lt;/p&gt;

&lt;p&gt;As AI continues to evolve, adopting these technologies ensures your business remains &lt;strong&gt;competitive&lt;/strong&gt; and &lt;strong&gt;future-ready&lt;/strong&gt;. Start exploring AWS Bedrock today to unlock the full potential of AI agents and accelerate your journey towards smarter, automated solutions.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>bedrock</category>
      <category>aws</category>
      <category>agents</category>
    </item>
    <item>
      <title>Unleashing the Power of CDK and Terraform in Cloud Deployments</title>
      <dc:creator>Sidath Munasinghe</dc:creator>
      <pubDate>Sat, 22 Jun 2024 07:59:02 +0000</pubDate>
      <link>https://dev.to/aws-builders/unleashing-the-power-of-cdk-and-terraform-in-cloud-deployments-5680</link>
      <guid>https://dev.to/aws-builders/unleashing-the-power-of-cdk-and-terraform-in-cloud-deployments-5680</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Deploying applications to the cloud has become a cornerstone of modern software development. AWS offers CloudFormation as a service to facilitate cloud deployments and tools like the AWS Cloud Development Kit (CDK). At the same time, Terraform has emerged as a powerful solution for Infrastructure as Code (IaC), enabling faster deployments to multiple cloud providers. In this article, we’ll explore the benefits of using AWS CDK and Terraform together and walk through a practical example of creating a REST API with CDK in TypeScript.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Terraform and CDK?
&lt;/h2&gt;

&lt;p&gt;Terraform and CDK are prominent tools that empower the definition of infrastructure as code. Each solution possesses its own set of advantages and disadvantages. Let's delve into a bit more information on both.&lt;/p&gt;

&lt;h3&gt;
  
  
  Terraform
&lt;/h3&gt;

&lt;p&gt;Terraform is a tool created by HashiCorp that allows you to define your infrastructure in a high-level configuration language called HCL (HashiCorp Configuration Language). Terraform is cloud-agnostic and can manage infrastructure across various cloud providers, including AWS, Azure, and Google Cloud Platform. It also enables faster deployments when compared to CloudFormation, specifically for AWS.&lt;/p&gt;

&lt;h3&gt;
  
  
  AWS CDK
&lt;/h3&gt;

&lt;p&gt;The AWS Cloud Development Kit (CDK) is an open-source software development framework for defining cloud infrastructure in code and provisioning it through AWS CloudFormation. CDK uses familiar programming languages, including TypeScript, to model your applications. Underneath, CDK generates plain CloudFormation templates to create the infrastructure using the code we implement with CDK. The advantage is due to this abstraction, we could generate very lengthy CloudFormation templates within a few lines using high-level CDK constructs. So, it helps developers implement and maintain infrastructure code conveniently with their favourite programming language.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits of Using Terraform and CDK Together
&lt;/h2&gt;

&lt;p&gt;Using both tools together, we can enjoy the benefits of both worlds. Although Terraform uses HCL, it may not be very convenient for developers. CDK solves this by providing high-level reusable CDK constructs to implement the infrastructure within a few lines. Also, since we use a very familiar programming language, it feels so close to the developers.&lt;/p&gt;

&lt;p&gt;On the other hand, CDK uses CloudFormation behind the scenes, which is usually slower than Terraform. However, when we use CDK and Terraform together, we can make much faster cloud deployments since we use Terraform to perform the deployments.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We can achieve this through the use of &lt;a href="https://developer.hashicorp.com/terraform/cdktf" rel="noopener noreferrer"&gt;CDK for Terraform&lt;/a&gt;, which is introduced as Cloud Development Kit for Terraform (CDKTF), allowing us to utilise familiar programming languages to define and provision infrastructure.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Setting up a Project
&lt;/h2&gt;

&lt;p&gt;Let’s set up a Terraform project with CDK using Typescript as the language. We need to set up a few prerequisites for using CDK for Terraform.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli" rel="noopener noreferrer"&gt;Terraform CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nodejs.org/en" rel="noopener noreferrer"&gt;NodeJS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.typescriptlang.org/" rel="noopener noreferrer"&gt;TypeScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.hashicorp.com/terraform/tutorials/cdktf/cdktf-install" rel="noopener noreferrer"&gt;CDKTF CLI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once the setup is complete, we can initiate a project. First, let’s create a folder to set up the initial code.&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%2F30cwddrxv9ix2b0m6iks.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%2F30cwddrxv9ix2b0m6iks.png" alt="Creating the project folder" width="800" height="108"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then we can initiate a project with below CLI command. Here we are going to use TypeScript.&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%2F8uxk1g1zxa5nxlc0q60i.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%2F8uxk1g1zxa5nxlc0q60i.png" alt="Initializing the project" width="800" height="108"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the project is initialized, we can update the main.ts file to define the infrastructure we need. Within the main.ts file, it has created a CDK app as well as a Stack. We can update the resources within the stack as needed to deploy. Let’s build a simple hello world REST API using API Gateway and a Lambda function.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a REST API
&lt;/h2&gt;

&lt;p&gt;Before adding any AWS resources, let’s configure the AWS provider in Terraform since we will use AWS as the cloud provider. Further, we can use a S3 bucket to store the Terraform backend and track the deployment states.&lt;/p&gt;

&lt;p&gt;We can simply configure this by adding the necessary CDK constructs (AwsProvider, S3Backend) with the required parameters like below.&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%2Fdoykj03sg8vcytzj1xoq.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%2Fdoykj03sg8vcytzj1xoq.png" alt="Configuring AWS provider with a S3 backend" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here, we have configured the AWS provider by providing the AWS account ID we need to deploy with the region. Similarly, we have configured the S3 backend by providing the bucket name and other configurations.&lt;/p&gt;

&lt;p&gt;Now, let’s create an IAM role as the execution role for the Lambda function, including the permissions for a basic lambda execution role.&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%2Fgdfg5jk1w5od0cd10l0o.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%2Fgdfg5jk1w5od0cd10l0o.png" alt="Creating an IAM role for the Lambda function" width="800" height="739"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, it’s time to create the Lambda function. Let’s add the below code for the Lambda function code inside index.ts file within the src folder. Since we are building a simple hello-world application, the Lambda function is returning a simple hello-world response.&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%2Fwt1ywygtlkcptujhy5cb.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%2Fwt1ywygtlkcptujhy5cb.png" alt="Lambda function handler implementation" width="800" height="468"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once we have added the Lambda function handler implementation, we can add the CDK implementation to refer to that and create the Lambda function resource.&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%2Ffedzswjgoy0dn5qog55m.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%2Ffedzswjgoy0dn5qog55m.png" alt="Creating the Lambda function resource" width="800" height="720"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The above definition will create a S3 bucket to hold the function code and create the Lambda function. The role we defined earlier is also provided as the execution role for the function.&lt;/p&gt;

&lt;p&gt;Once the Lambda function is ready, we can now create the API Gateway REST API and integrate the Lambda function with it.&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%2Fqxlwb1bz526kuugzyn1x.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%2Fqxlwb1bz526kuugzyn1x.png" alt="Creating the API Gateway REST API" width="800" height="812"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here, we are defining the constructs for the API Gateway, a resource for the &lt;code&gt;/hello&lt;/code&gt; path and the GET method under that for the &lt;code&gt;/hello&lt;/code&gt; &lt;code&gt;GET&lt;/code&gt; endpoint. Finally, we have integrated it with the lambda function we created earlier as a proxy integration.&lt;/p&gt;

&lt;p&gt;Since things are integrated correctly, we can create a stage in the API Gateway and create a deployment like the one below.&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%2F9pu5d4gvgyh62hbfuca6.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%2F9pu5d4gvgyh62hbfuca6.png" alt="API Gateway stage and deployment" width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have provided the stage name and API we want to create in the configurations.&lt;/p&gt;

&lt;p&gt;Now, we have created all the resources we need. But there is one more thing we need to do. We need to ensure that the API Gateway service can invoke the provided lambda function. To do that, we must create and attach a resource-based policy to allow that action within the Lambda function. We can do it like below easily using the &lt;code&gt;LambdaPermission&lt;/code&gt; construct.&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%2Fpnbl4gdfld9a3uyfj9mx.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%2Fpnbl4gdfld9a3uyfj9mx.png" alt="Granting permissions to allow lambda invocation from API Gateway" width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This construct will add the required permissions to the Lambda function to be invoked by the API we created earlier. With this, we are complete with the implementation.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The full implementation of this project can be found on this &lt;a href="https://github.com/sidathasiri/cdk-terraform" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now everything is ready to deploy. Ensure you have configured your AWS credentials correctly so the Terraform can access AWS to provision the infrastructure. We can first build the code and then deploy it using the command below.&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%2Fx8e5jn5keqohjirj71w8.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%2Fx8e5jn5keqohjirj71w8.png" alt="Building the code and deploying to AWS" width="800" height="109"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the above command is executed, CDK for Terraform will install if there are any missing packages and start the deployment. After the deployment is complete, you can verify the created resources and play with 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%2Ffmydxln4kqkll9wkkplz.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%2Ffmydxln4kqkll9wkkplz.png" alt="Testing the deployed API" width="800" height="356"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Moreover, we can discern that Terraform is executing the deployment significantly faster than CloudFormation, which is incredibly advantageous.&lt;/p&gt;

&lt;p&gt;To delete the resources you created, you can run the cdktf destroy command. This will ensure that all the resources created by the project are properly cleaned up.&lt;/p&gt;

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

&lt;p&gt;Using AWS CDK with Terraform offers several notable benefits for managing cloud infrastructure. CDK’s deep integration with AWS and support for familiar programming languages like TypeScript make defining AWS resources intuitive and maintainable. Terraform’s cloud-agnostic capabilities complement CDK by allowing for seamless management across multiple cloud providers. This combination provides flexibility, ease of use, and modularity, enhancing the overall infrastructure management workflow. By leveraging both tools, you can streamline deployments, improve efficiency, and achieve a more robust and versatile infrastructure management solution.&lt;/p&gt;

</description>
      <category>cdk</category>
      <category>terraform</category>
      <category>aws</category>
      <category>iac</category>
    </item>
    <item>
      <title>Generative AI on AWS with Amazon Bedrock</title>
      <dc:creator>Sidath Munasinghe</dc:creator>
      <pubDate>Mon, 06 May 2024 04:14:32 +0000</pubDate>
      <link>https://dev.to/aws-builders/generative-ai-on-aws-with-amazon-bedrock-25hd</link>
      <guid>https://dev.to/aws-builders/generative-ai-on-aws-with-amazon-bedrock-25hd</guid>
      <description>&lt;p&gt;Amazon Bedrock is a managed service that provides high-performing foundation models (FMs) from leading AI companies using a single interface. With Bedrock, we don’t need to worry about hosting and managing the infrastructure for the foundation models. We can directly jump into consuming these models with its APIs and start building apps. Further, we can customize these foundation models to fit our use cases and also integrate them with knowledge bases and agents to provide enhanced features.&lt;/p&gt;

&lt;p&gt;Here are some key features of Amazon Bedrock.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Play with several foundation models and see which suites your use case mostly, and start building apps&lt;/li&gt;
&lt;li&gt;Fine-tune or customize the foundation models with specific datasets and parameters to enhance its capabilities&lt;/li&gt;
&lt;li&gt;Integrate knowledge bases and tailor and augment foundation models to specific tasks or domains&lt;/li&gt;
&lt;li&gt;Integrate agents and enrich reasoning capabilities to trigger intelligent actions&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Foundation Models
&lt;/h2&gt;

&lt;p&gt;Foundation models are the basic building block of Bedrock. The following diagram shows a few foundation models provided by different AI companies on Bedrock. This list will continue to grow as AWS adds more models. Each model is specific for certain tasks, and depending on your use case, the most appropriate one needs to be selected. Further, each model has different pricing models.&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%2F1mcxgzmbx0mcf5o8gy5s.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%2F1mcxgzmbx0mcf5o8gy5s.png" alt="Supported foundation models in Bedrock" width="640" height="318"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;AWS Bedrock provides a playground where you can experiment with different models by adjusting their parameters like temperature and observe how their behaviour change. The following diagram shows a scenario of using the Titan model created by Amazon to handle text inputs.&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%2F036xiexxlb53qq2yw321.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%2F036xiexxlb53qq2yw321.png" alt="Text to text processing with Titan model" width="640" height="313"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Additionally, to the playground, we can access these models programmatically with a single API using the AWS SDK. The implementation remains the same even if you want to change the model occasionally because of that. It’s simply a matter of updating the configurations to utilize the appropriate model.&lt;/p&gt;

&lt;p&gt;Below is a script written in NodeJS where we can access these foundational models programmatically and get responses accordingly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const client = new BedrockRuntimeClient({
  region: 'us-east-1',
  credentials: {
    accessKeyId: process.env.AWS_ACCESS_KEY_ID,
    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
  },
});

async function ask(prompt) {
  const params = {
    modelId: 'amazon.titan-text-express-v1',
    body: JSON.stringify({
      inputText: prompt,
      textGenerationConfig: {
        temperature: 0.7,
        topP: 0.9,
        maxTokenCount: 800,
      },
    }),
    accept: 'application/json',
    contentType: 'application/json',
  };
  console.log('Prompt:', prompt);
  const command = new InvokeModelCommand(params);
  const response = await client.send(command);
  const decodedString = convertByteToString(response?.body);
  const data = convertToJSON(decodedString);
  return data?.results[0]?.outputText;
}

ask('Give me a short description about Sri Lanka').then((response) =&amp;gt; console.log("Answer:", response));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the script is run, we can see that it is giving us responses.&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%2Ftr2p9j5msae58rh7w0hi.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%2Ftr2p9j5msae58rh7w0hi.png" alt="Accessing Bedrock AI models programmatically" width="640" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The full implementation can be found on this &lt;a href="https://github.com/sidathasiri/aws-bedrock-client-sample-app" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This can be seamlessly integrated into any app and further expanded by customizing the prompt based on specific use cases. See how using Bedrock to fulfil the generative AI needs is effortless.&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom Models
&lt;/h2&gt;

&lt;p&gt;A common drawback with generative AI is that it’s too generic, meaning it’s trained with outdated data or doesn’t have specific knowledge of a given domain. We can enhance a foundation model’s performance for particular tasks by training it with more data and imparting it with more knowledge using the custom model capability.&lt;/p&gt;

&lt;p&gt;If we have an unlabelled dataset, we can use the continued pre-training option, and if we have a labelled dataset, we can use the fine-tuning option. To perform this, we can follow the wizard in the AWS console by providing the dataset from an S3 location. We require a specific format for the training dataset, which is detailed here.&lt;/p&gt;

&lt;p&gt;Once the necessary configurations are in place, we can start the training job, and based on the dataset size and the training parameters, it can take a while (usually, it takes hours!). AWS will manage all the infrastructure related to the training job. Once the training is complete, we can directly use the custom model and run queries against it like a regular foundation model.&lt;/p&gt;

&lt;p&gt;Let’s create a very simple custom model with the below as the content in the dataset. We need to prepare a JSONL file containing the dataset to finetune the foundation models.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{"prompt": "who are you?", "completion": "I'm a customized Amazon Titan model"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above dataset should be able to customize the model name. As per the below screenshot, the original foundation model calls itself as a Titan build by Amazon. After training, we can see that for the same question, it gives a different output based on our training dataset.&lt;/p&gt;

&lt;p&gt;Here is the response from the foundation model.&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%2Fxu0prhecf8ovf2h33bqp.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%2Fxu0prhecf8ovf2h33bqp.png" alt="Response by foundation model" width="640" height="322"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is the response from the custom model.&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%2F8lt1btzn6aa8ct2k77no.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%2F8lt1btzn6aa8ct2k77no.png" alt="Response by custom model" width="640" height="322"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Further, it’s not just a rule-based training to provide the given answer for the given prompt. If you see the prompt in the given dataset and what I have asked are not exactly the same but they are similar. The model has been trained properly to answer similar types of queries as well, which is really great.&lt;/p&gt;

&lt;h2&gt;
  
  
  Knowledge Bases
&lt;/h2&gt;

&lt;p&gt;Knowledge bases can be utilized to provide foundational AI models with additional contextual information, enabling them to generate customized or more accurate responses akin to custom models without the need for extensive retraining. So we don’t need to spend much time retraining the models with additional data.&lt;/p&gt;

&lt;p&gt;We must employ a technique called Retrieval Augmented Generation (RAG) to accomplish this with LLMs. This technique helps to draw information from an external data store to augment the responses generated by Large Language Models (LLMs) without retraining the entire model. We can provide this additional information using a specialized database called a vector database, which generative AI models can understand.&lt;/p&gt;

&lt;p&gt;With the knowledge base feature on Bedrock, we only need to provide a dataset, and it has the fully managed capability to fetch the documents, divide them into blocks of text, convert the text into embeddings, and store the embeddings in your vector database using RAG. You must first upload the dataset to a S3 bucket to create a knowledge base. Then, you can use the wizard in the AWS console to create the knowledge base by pointing to the uploaded dataset and integrating it with a foundation model for generating responses. By doing this, Bedrock will create an Amazon OpenSearch Serverless vector database to retrieve newly uploaded data.&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%2Feuf061dr9ajimrc69r1z.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%2Feuf061dr9ajimrc69r1z.png" alt="Source: https://docs.aws.amazon.com/bedrock/latest/userguide/kb-how-it-works.html" width="640" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the vector database is ready, we can use it directly to see retrieved information stored from the vector store. Otherwise, we can use it with a foundation model to generate more user-friendly responses that match our query. However, only the Anthropic Claude models are currently supported in generating responses.&lt;/p&gt;

&lt;p&gt;The diagram below illustrates how the vector database can be utilized as an input to a foundation model to generate augmented responses.&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%2Fzvfkmq36zu5dzfuuch0h.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%2Fzvfkmq36zu5dzfuuch0h.png" alt="Source: https://docs.aws.amazon.com/bedrock/latest/userguide/kb-how-it-works.html" width="640" height="180"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I have created a knowledge base using the AWS documentation for bedrock using its PDF version. Once the knowledge base is ready, we can query it as shown below. Since I’m not utilizing a foundation model to create responses, I retrieve the row information from the vector database without performing any post-processing. Nonetheless, a pleasing feedback can be attained by employing a foundation model to generate a response.&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%2Fm4oicui300yzbwhotmyw.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%2Fm4oicui300yzbwhotmyw.png" alt="Testing the created knowledge base" width="435" height="708"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Agents
&lt;/h2&gt;

&lt;p&gt;Bedrock agents allow the triggering of actions based on specific inputs and the creation of autonomous agents. For instance, you could create an agent to accept hotel room reservations from customers by configuring an agent with a knowledge base of room availability and other relevant data and the respective backend to place reservations. When configuring the backend, we need to provide an OpenAPI specification of the backend services so that it knows which endpoints to call to satisfy the request.&lt;/p&gt;

&lt;p&gt;To have this capability, we need to configure the below components in Bedrock.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Foundation model:&lt;/strong&gt; This is needed to interpret the user input and continue the orchestration. Currently, only the Anthropic Claude models are supported.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Instructions:&lt;/strong&gt; Instructions are prompts describing what the agent is supposed to do. Having a clear and detailed prompt for the instruction is crucial for getting accurate results from the agent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action groups:&lt;/strong&gt; Here, we need to define the agent's actions. This consists of a lambda function and an OpenAPI specification. The lambda function has the implementation to act, and the OpenAPI specification provides the agent details on invoking the function. For example, we could implement a POST /reservation endpoint in the lambda function to create a reservation and provide the API specification on the details of the request, such as URL, request body, validation requirements, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Knowledge base:&lt;/strong&gt; Knowledge base is optional but is mandatory in most cases. This can be used to provide contextual information to the agent. For example, in this case, it would be some information about the room availability, pricing details, etc, so that the agent knows to perform the actions as intended.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once the agent is correctly configured, it understands its responsibilities based on the provided instructions. The knowledge base contains comprehensive information about the specific domain. The action group provides details on initiating each action and achieving the desired outcomes. Then, the foundation model can do the magic by orchestrating the workflow to handle a given request and provide the output to the user.&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%2Fkbfbxpps6oggcubwotp4.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%2Fkbfbxpps6oggcubwotp4.png" alt="Source: https://docs.aws.amazon.com/bedrock/latest/userguide/agents-how.html" width="640" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can see a cool demonstration of an agent working with a knowledge base &lt;a href="https://www.youtube.com/watch?v=P9n8BE693go" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Besides these, Bedrock offers additional features for developing responsible AI policies, including guardrails and watermark detection. We can anticipate introducing more capabilities to Bedrock as the potential of generative AI continues to unfold.&lt;/p&gt;

&lt;p&gt;In conclusion, Amazon Bedrock offers a powerful platform for leveraging generative AI capabilities on AWS. With its Foundation models and easy-to-use APIs, developers can quickly integrate AI-driven features into their applications. Additionally, the ability to create custom models, knowledge bases, and agents opens up endless possibilities for tailoring AI solutions to specific needs. By harnessing the power of Bedrock, developers can unlock new levels of innovation and create intelligent, personalized experiences for their users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read more
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/what-is-bedrock.html" rel="noopener noreferrer"&gt;What is Amazon Bedrock?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/custom-models.html" rel="noopener noreferrer"&gt;Custom Models&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/what-is/retrieval-augmented-generation/#:~:text=RAG%20extends%20the%20already%20powerful,and%20useful%20in%20various%20contexts." rel="noopener noreferrer"&gt;What is RAG?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/knowledge-base.html" rel="noopener noreferrer"&gt;Knowledge bases for Amazon Bedrock&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/agents-how.html" rel="noopener noreferrer"&gt;How Agents for Amazon Bedrock Works?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>aws</category>
      <category>bedrock</category>
    </item>
    <item>
      <title>Deploy Kubernetes in Minutes: Effortless Infrastructure Creation and Application Deployment with Cluster.dev and Helm Charts</title>
      <dc:creator>Sidath Munasinghe</dc:creator>
      <pubDate>Sat, 17 Feb 2024 17:48:50 +0000</pubDate>
      <link>https://dev.to/aws-builders/deploy-kubernetes-in-minutes-effortless-infrastructure-creation-and-application-deployment-with-clusterdev-and-helm-charts-dhj</link>
      <guid>https://dev.to/aws-builders/deploy-kubernetes-in-minutes-effortless-infrastructure-creation-and-application-deployment-with-clusterdev-and-helm-charts-dhj</guid>
      <description>&lt;p&gt;Kubernetes has quickly become the leading orchestration tool for containerized applications, celebrated for its ability to scale applications robustly and resiliently. Its success lies in a powerful framework that adeptly handles the complex life cycles of distributed applications. Yet, deploying Kubernetes cluster infrastructure, essential for tapping into this platform’s capabilities, presents significant challenges. This complexity requires considerable effort and poses a major hurdle for many seeking to leverage Kubernetes for scalable application deployment.&lt;/p&gt;

&lt;p&gt;This guide is designed to demystify the process, showing you how to set up a Kubernetes infrastructure swiftly and without hassle. We aim to transform the perceived daunting task of Kubernetes deployment into a streamlined and straightforward process so you don’t want to struggle with its complexities. By the end of this article, you’ll be equipped to utilize the full power of Kubernetes, making infrastructure deployment not just feasible but also simple, efficient, and repeatable. Let’s embark on this journey to simplify Kubernetes deployment, turning obstacles into opportunities for growth and innovation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Complexities with Kubernetes
&lt;/h2&gt;

&lt;p&gt;If you have tried to create your own Kubernetes cluster, you know the pain behind the complexities of that. The biggest problem is having a highly available and scalable control plane for cluster management. The easiest way to solve this challenge is to hand over that complexity to a managed service by a cloud provider so that you don’t need to worry about it.&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%2Fz1m55xa6e3fhkm5ue9vm.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%2Fz1m55xa6e3fhkm5ue9vm.png" alt=" " width="800" height="174"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, that’s not the end. Still, you will need to do a lot of configurations to get it working. If you see the &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/getting-started.html" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; of Elastic Kubernetes Service (EKS), the managed service for Kubernetes from AWS, it has a lot of things to do, like setting up IAM roles, creating certain subnets in the VPC, etc. Although we can use an IaC to provision infrastructure, implementing them would take significant effort. We can resolve this with Cluster.dev using its reusable templates so we don’t need to implement the same code repeatedly. With Cluster.dev, we can get a working Kubernetes cluster effortlessly within a few minutes. If you are not familiar with Cluster.dev, read my previous articles from &lt;a href="https://aws.plainenglish.io/revolutionizing-infrastructure-management-with-cluster-dev-a-journey-into-effortless-orchestration-759b9379cebe" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We now have an operational Kubernetes cluster ready to accept deployments. If you are familiar with Kubernetes concepts, to deploy an application, we need to create several Kubernetes resources such as deployments, services, ingress controllers, config maps, stateful sets, etc, as needed, which takes some effort to create the necessary YAML files including configurations. To simplify this, we can use Helm charts.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://helm.sh/" rel="noopener noreferrer"&gt;Helm&lt;/a&gt; is a package manager that automates Kubernetes applications' creation, packaging, configuration, and deployment by combining your configuration files into a single reusable package. This eliminates the requirement to create the mentioned Kubernetes resources by ourselves since they have been implemented within the Helm chart. All we need to do is configure it as needed to match our requirements. From the public Helm chart repository, we can get the charts for common software packages like Consul, Jenkins SonarQube, etc. We can also create our own Helm charts for our custom applications so that we don’t need to repeat ourselves and simplify deployments.&lt;/p&gt;
&lt;h2&gt;
  
  
  Setting up a Jenkins Service with Cluster.dev and Helm on Kubernetes
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fig85dkbwukorl7429d80.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%2Fig85dkbwukorl7429d80.png" alt=" " width="800" height="254"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, let’s see how we can use these tools together to deploy and run a Jenkins service on AWS EKS. Since Cluster.dev natively supports Helm, we can make this even more effortless.&lt;/p&gt;

&lt;p&gt;Let’s start by setting up the necessary prerequisites. We need to install the below CLIs to start the deployments. Although there are several tools to install, please note that this is a one-time setup. So we only need to spend time to install them only once.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli" rel="noopener noreferrer"&gt;Terraform&lt;/a&gt;: We use this to provision the AWS infrastructure to run the Kubernetes cluster&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.cluster.dev/installation-upgrade/" rel="noopener noreferrer"&gt;Cluster.dev&lt;/a&gt;: We use this to orchestrate the deployment by using Terraform to deploy the cluster and then use Helm to deploy Jenkins&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html" rel="noopener noreferrer"&gt;AWS CLI&lt;/a&gt;: We use this to interact with our AWS account&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/install-kubectl.html" rel="noopener noreferrer"&gt;kubectl&lt;/a&gt;: We use this to interact with the Kubernetes cluster&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://helm.sh/docs/intro/install/" rel="noopener noreferrer"&gt;Helm&lt;/a&gt;: We use helm to simplify the Kubernetes deployments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once the CLIs are ready, we can generate the Kubernetes infrastructure code and deploy it with Cluster.dev. We can use the below command to reuse a Cluster.dev &lt;a href="https://github.com/sidathasiri/cdev-eks" rel="noopener noreferrer"&gt;template&lt;/a&gt; that I have created previously and do the generation instantly.&lt;/p&gt;

&lt;p&gt;To do this, create a project folder and run the below Cluster.dev command inside it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cdev project create https://github.com/sidathasiri/cdev-eks.git - interactive
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will give you an interactive guide like the one below to configure the template with custom configurations.&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%2F8acq7712rc2l96luc1v4.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%2F8acq7712rc2l96luc1v4.png" alt="Cluster.dev interactive CLI to generate code&amp;lt;br&amp;gt;
" width="800" height="250"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, we get a project generated with the necessary configurations to deploy a Kubernetes cluster. Let’s extend it to deploy Jenkins with Helm. To do that, we need to update the &lt;code&gt;template.yaml&lt;/code&gt; file with additional units as follows. The first unit (kubeconfig) is a shell unit configuring the &lt;code&gt;kubectl&lt;/code&gt; CLI to interact with the Kubernetes cluster we create. The second unit (jenkins) is a Helm unit configured with the Jenkins Helm chart from the &lt;a href="https://charts.jenkins.io/" rel="noopener noreferrer"&gt;public Helm repository&lt;/a&gt;. To access the Jenkins service from the public internet, we need to create a Kubernetes service as a load balancer. We can provide this configuration with a &lt;code&gt;values.yaml&lt;/code&gt; file in &lt;code&gt;template/helm/values.yaml&lt;/code&gt; path. The second snippet below shows the content of that file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  - name: kubeconfig
      type: shell
      depends_on: this.eksCluster
      force_apply: true
      apply:
        commands:
          - aws eks update-kubeconfig --region {{ .variables.region }} --name {{ .variables.cluster_name }}
  - name: jenkins
    type: helm
    depends_on: this.kubeconfig
    kubeconfig: ~/.kube/config
    source:
      repository: 'https://charts.jenkins.io'
      chart: 'jenkins'
      version: '5.0.13'
    values:
        - file: ./helm/values.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;controller:
  serviceType: LoadBalancer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;You can find the full implementation of this from this &lt;a href="https://github.com/sidathasiri/cdev-eks-jenkins" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That’s all we need to do. Now, we can run the command below, and Cluster.dev will create the Kubernetes cluster and then deploy the Jenkins service within it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cdev apply - force
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the deployment is complete, we can see that a load balancer has been created. We can access the deployed Jenkins service using the DNS address of the load balancer on the port 8080.&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%2Fgbbd7ybu0hb1s5qps946.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%2Fgbbd7ybu0hb1s5qps946.png" alt=" " width="800" height="476"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;See how effortlessly we deployed an application on Kubernetes with minimal code, and even better, in just a few minutes! Say goodbye to the hassle of setting up Kubernetes — we’ve simplified it for you.&lt;/p&gt;

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

&lt;p&gt;In conclusion, leveraging Cluster.dev alongside Helm charts offers a streamlined approach to Kubernetes infrastructure creation and application deployment. By utilizing Cluster.dev templates, we can efficiently generate infrastructure components, reducing setup time and complexity. Helm charts further simplify the deployment process, allowing for seamless application deployment within minutes. This integration enhances productivity and eliminates tedious manual configuration tasks, making Kubernetes more accessible to developers and teams. Embracing these tools can significantly accelerate the development and deployment lifecycle, enabling focus on core objectives and innovation within Kubernetes environments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Check out my other articles on Cluster.dev series&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://medium.com/aws-in-plain-english/revolutionizing-infrastructure-management-with-cluster-dev-a-journey-into-effortless-orchestration-759b9379cebe" rel="noopener noreferrer"&gt;Revolutionizing Infrastructure Management with Cluster.dev: A Journey into Effortless Orchestration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.plainenglish.io/streamlining-sonarqube-on-aws-ecs-simplified-deployment-using-cluster-dev-0b988536fff0" rel="noopener noreferrer"&gt;Streamlining SonarQube on AWS ECS: Simplified Deployment Using Cluster.dev&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/getting-started-console.html" rel="noopener noreferrer"&gt;Getting started guide with EKS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.cluster.dev/" rel="noopener noreferrer"&gt;Cluster.dev documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://circleci.com/blog/what-is-helm/" rel="noopener noreferrer"&gt;What is Helm? A complete guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/tutorials/kubernetes-basics/" rel="noopener noreferrer"&gt;Learn Kube
rnetes Basics&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>kubernetes</category>
      <category>eks</category>
      <category>aws</category>
      <category>clusterdev</category>
    </item>
    <item>
      <title>Streamlining SonarQube on AWS ECS: Simplified Deployment Using Cluster.dev</title>
      <dc:creator>Sidath Munasinghe</dc:creator>
      <pubDate>Sat, 03 Feb 2024 07:04:51 +0000</pubDate>
      <link>https://dev.to/aws-builders/streamlining-sonarqube-on-aws-ecs-simplified-deployment-using-clusterdev-1418</link>
      <guid>https://dev.to/aws-builders/streamlining-sonarqube-on-aws-ecs-simplified-deployment-using-clusterdev-1418</guid>
      <description>&lt;p&gt;SonarQube, crafted by SonarSource, is an open-source platform designed to scrutinize code quality continuously. It proficiently identifies bugs and code smells across a spectrum of programming languages through automated reviews leveraging static code analysis.&lt;/p&gt;

&lt;p&gt;However, if you are going to self-host SonarQube, it takes significant effort to provision both a resilient database infrastructure and a scalable compute layer capable of accommodating fluctuating traffic demands. Let's use AWS RDS for the resilient database and AWS ECS for the scalable compute layer. To simplify the deployment, let's use Cluster.dev. If you are new to Cluster.dev, I recommend you read my previous post for a comprehensive introduction and understand its benefits.&lt;/p&gt;

&lt;p&gt;Below is the infrastructure setup we will build with Cluster.dev in this blog post.&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%2Fey2v3czd6ger95n4q3no.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%2Fey2v3czd6ger95n4q3no.png" alt="High-level architecture" width="622" height="576"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before jumping into the implementation, let's learn some basics about Cluster.dev first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cluster.dev Basics
&lt;/h2&gt;

&lt;p&gt;Below are the fundamental building blocks of a Cluster.dev project.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Unit:&lt;/strong&gt; A unit represents a unit of resource that we have in our infrastructure setup (ex. a load balancer). We can use a variety of technologies to implement a unit, such as Terraform modules, Helm charts, Kubernetes manifests, Terraform code, Bash scripts, etc. We need to provide specific inputs to a unit to configure it as we want, and it gives specific outputs to use as well as to refer to other units if required.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Stack Template:&lt;/strong&gt; A stack template contains a set of units to implement an infrastructure pattern we need to provision. In this scenario, it's our SonarQube deployment on ECS. We can get the benefit of a variety of technologies by using different units and connecting them to lay out a complex infrastructure pattern in the stack template.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Stack:&lt;/strong&gt; A stack is used to define different variables and configure the stack template as needed. This helps to tailor the defined infrastructure pattern in the stack template according to the use case.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Project:&lt;/strong&gt; A project can be used to orchestrate one or more stacks depending on the complexity of the infrastructure. Any global variables that can be used across stacks can be defined at the project level.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Backend:&lt;/strong&gt; This includes configuration of the location where Cluster.dev keeps track of its state of deployments.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The diagram below reveals how these building blocks are set up for SonarQube ECS deployment.&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%2Fb3j6flxs794epdealz8n.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%2Fb3j6flxs794epdealz8n.png" alt="The layout of the Cluster.dev components for ECS deployment&amp;lt;br&amp;gt;
" width="781" height="540"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Implementing the Infrastructure
&lt;/h2&gt;

&lt;p&gt;Before implementing any infrastructure pattern, we need to identify the resources we need to create for the infrastructure pattern as units and the technology we should use for each. For this setup, we will be using Terraform modules to create the AWS resources below.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ECS Cluster&lt;/li&gt;
&lt;li&gt;ECS Task Definition&lt;/li&gt;
&lt;li&gt;ECS Service&lt;/li&gt;
&lt;li&gt;Load Balancer&lt;/li&gt;
&lt;li&gt;Postgres RDS Database&lt;/li&gt;
&lt;li&gt;Security groups for Database, Load balancer &amp;amp; ECS service&lt;/li&gt;
&lt;li&gt;Necessary IAM roles&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's start with the &lt;a href="https://github.com/sidathasiri/cdev-sonarqube/blob/main/template/template.yaml" rel="noopener noreferrer"&gt;&lt;code&gt;template.yaml&lt;/code&gt;&lt;/a&gt; file to define the resources we need. The below YAML file contains all the AWS resources we need to create for this setup. Note how we have connected different terraform modules to provision the infrastructure we need. Also, we have used several variables to make the infrastructure pattern repeatable for diverse use cases. The syntax for using a variable is &lt;code&gt;{{ .variables.&amp;lt;variable_name&amp;gt; }}&lt;/code&gt;. Further, we can refer to the outputs of one unit in another using the &lt;code&gt;{{ remoteState "this.&amp;lt;unit_name&amp;gt;.&amp;lt;attribute&amp;gt;" }}&lt;/code&gt; syntax.&lt;/p&gt;

&lt;p&gt;Finally, we have a printer unit to output the DNS name of the load balancer to access the deployed SonarQube application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_p: &amp;amp;provider_aws
  - aws:
      region: {{ .variables.region }}

name: cdev-sonarqube
kind: StackTemplate
units:
  - name: WebSecurityGroup
    type: tfmodule
    providers: *provider_aws
    source: terraform-aws-modules/security-group/aws//modules/http-80
    inputs:
      name: 'WebSecurityGroup'
      vpc_id: {{ .variables.vpc_id }}
      ingress_cidr_blocks: ["0.0.0.0/0"]

  - name: DBSecurityGroup
    type: tfmodule
    providers: *provider_aws
    source: terraform-aws-modules/security-group/aws
    inputs:
      name: 'DBSecurityGroup'
      vpc_id: {{ .variables.vpc_id }}
      ingress_with_source_security_group_id:
        - rule: "postgresql-tcp"
          source_security_group_id: {{ remoteState "this.ECSSVCSecurityGroup.security_group_id" }}

  - name: ECSSVCSecurityGroup
    type: tfmodule
    providers: *provider_aws
    source: terraform-aws-modules/security-group/aws
    inputs:
      name: 'ECSSVCSecurityGroup'
      vpc_id: {{ .variables.vpc_id }}
      ingress_with_cidr_blocks:
        - from_port: 9000
          to_port: 9000
          protocol: "tcp"
          cidr_blocks: "0.0.0.0/0"
      egress_with_cidr_blocks:
        - from_port: 0
          to_port: 0
          protocol: "-1"
          cidr_blocks: "0.0.0.0/0"

  - name: Database
    type: tfmodule
    providers: *provider_aws
    source: terraform-aws-modules/rds/aws
    inputs:
      engine: 'postgres'
      engine_version: '14'
      family: 'postgres14' # DB parameter group
      major_engine_version: '14' # DB option group
      instance_class: 'db.t4g.large'
      identifier: 'sonar-database'
      db_name: 'sonarqube'
      username: 'sonar_user'
      password: 'password'
      publicly_accessible: true
      allocated_storage: 5
      manage_master_user_password: false
      vpc_security_group_ids: [{{ remoteState "this.DBSecurityGroup.security_group_id" }}]
      subnet_ids: [{{ .variables.subnet_1 }}, {{ .variables.subnet_2 }}]

  - name: ECSCluster
    type: tfmodule
    providers: *provider_aws
    source: terraform-aws-modules/ecs/aws
    inputs:
      cluster_name: 'sonar-cluster'

  - name: ECSTaskDefinition
    type: tfmodule
    providers: *provider_aws
    source: github.com/mongodb/terraform-aws-ecs-task-definition
    inputs:
      image: 'sonarqube:lts-community'
      family: 'sonar'
      name: 'sonar'
      portMappings:
        - containerPort: 9000
          hostPort: 9000
          protocol: 'tcp'
          appProtocol: 'http'
      command:
        - '-Dsonar.search.javaAdditionalOpts=-Dnode.store.allow_mmap=false'
      environment:
        - name: SONAR_JDBC_URL
          value: jdbc:postgresql://{{ remoteState "this.Database.db_instance_endpoint" }}/postgres
        - name: SONAR_JDBC_USERNAME
          value: sonar_user
        - name: SONAR_JDBC_PASSWORD
          value: password
      requires_compatibilities:
        - 'FARGATE'
      cpu: 1024
      memory: 3072
      network_mode: awsvpc

  - name: LoadBalancer
    type: tfmodule
    providers: *provider_aws
    source: terraform-aws-modules/alb/aws
    inputs:
      name: 'sonarqube'
      vpc_id: {{ .variables.vpc_id }}
      subnets: [{{ .variables.subnet_1 }}, {{ .variables.subnet_2 }}]
      enable_deletion_protection: false
      create_security_group: false
      security_groups: [{{ remoteState "this.WebSecurityGroup.security_group_id" }}]
      target_groups:
        ecsTarget:
          name_prefix: 'SQ-'
          protocol: 'HTTP'
          port: 80
          target_type: 'ip'
          create_attachment: false
      listeners:
        ecs-foward:
          port: 80
          protocol: 'HTTP'
          forward:
            target_group_key: 'ecsTarget'

  - name: ECSService
    type: tfmodule
    providers: *provider_aws
    source: terraform-aws-modules/ecs/aws//modules/service
    inputs:
      name: 'sonarqube'
      cluster_arn: {{ remoteState "this.ECSCluster.cluster_arn" }}
      cpu: 1024
      memory: 4096
      create_task_definition: false
      task_definition_arn: {{ remoteState "this.ECSTaskDefinition.arn" }}
      create_security_group: false
      create_task_exec_iam_role: true
      assign_public_ip: true
      subnet_ids: [{{ .variables.subnet_1 }}, {{ .variables.subnet_2 }}]
      security_group_ids: [{{ remoteState "this.ECSSVCSecurityGroup.security_group_id" }}]
      load_balancer:
        service:
          target_group_arn: {{ remoteState "this.LoadBalancer.target_groups.ecsTarget.arn" }}
          container_name: sonar
          container_port: 9000

  - name: outputs
    type: printer
    depends_on: this.LoadBalancer
    outputs:
      sonar_url: http://{{ remoteState "this.LoadBalancer.dns_name" }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that, the complex part is done 🙂&lt;/p&gt;

&lt;p&gt;Now, let's define the &lt;a href="https://github.com/sidathasiri/cdev-sonarqube/blob/main/stack.yaml" rel="noopener noreferrer"&gt;&lt;code&gt;stack.yaml&lt;/code&gt;&lt;/a&gt; file, including the variables to configure the stack template. Here, we have defined the below configurations as variables so that we can change them and use the existing AWS networking infrastructure.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;region:&lt;/strong&gt; AWS region&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;vpc_id:&lt;/strong&gt; ID of VPC we need to deploy&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;subnet_1:&lt;/strong&gt; ID of subnet 1&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;subnet_2:&lt;/strong&gt; ID of subnet 2&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can define more variables as needed to allow more flexibility to the stack template.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: cdev-sonarqube
template: ./template/
kind: Stack
backend: aws-backend
variables:
  region: {{ .project.variables.region }}
  vpc_id: {{ .project.variables.vpc_id }}
  subnet_1: {{ .project.variables.subnet_1 }}
  subnet_2: {{ .project.variables.subnet_2 }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's use a S3 bucket to store the backend state of Cluster.dev. We can define a &lt;a href="https://github.com/sidathasiri/cdev-sonarqube/blob/main/backend.yaml" rel="noopener noreferrer"&gt;&lt;code&gt;backend.yaml&lt;/code&gt;&lt;/a&gt; to configure this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: aws-backend
kind: Backend
provider: s3
spec:
  bucket: {{ .project.variables.state_bucket_name }}
  region: {{ .project.variables.region }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we are ready to define the &lt;a href="https://github.com/sidathasiri/cdev-sonarqube/blob/main/project.yaml" rel="noopener noreferrer"&gt;&lt;code&gt;project.yaml&lt;/code&gt;&lt;/a&gt; file to use this stack. For this infrastructure pattern, we are only a single stack. Here, we can define the global variables for the project as well.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: cdev-sonarqube
kind: Project
backend: aws-backend
variables:
  organization: &amp;lt;org-name&amp;gt;
  region: &amp;lt;aws-region&amp;gt;
  state_bucket_name: &amp;lt;state-bucket-name&amp;gt;
  vpc_id: &amp;lt;vpc-id&amp;gt;
  subnet_1: &amp;lt;subnet1-id&amp;gt;
  subnet_2: &amp;lt;subnet2-id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The full implementation of this can be found on this &lt;a href="https://github.com/sidathasiri/cdev-sonarqube" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Deploying the Infrastructure
&lt;/h2&gt;

&lt;p&gt;Now, we can use the Cluster.dev CLI to deploy the infrastructure with the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cdev apply
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we run this command, it gives us a summary of the resources that it is going to deploy, like below.&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%2F2050ef5xlx0ab6mi5l34.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%2F2050ef5xlx0ab6mi5l34.png" alt="Deploying AWS resources" width="554" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also, once the deployment is complete, the printer unit outputs the URL to access the deployed SonarQube application.&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%2Fxemi0qlsxsvwmldknw9j.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%2Fxemi0qlsxsvwmldknw9j.png" alt="Deployed SonarQube application" width="800" height="476"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also, you can notice that our deployment has auto-scaling enabled to scale out and scale in according to the incoming traffic.&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%2Frwzca3o8yv8ulzpi7fq6.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%2Frwzca3o8yv8ulzpi7fq6.png" alt="ECS Service auto-scaling policy" width="800" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As per the diagram above, we can see that it scales out when the CPU and memory reach certain thresholds to a max of 10 tasks. We can fine-tune these settings based on our requirements.&lt;/p&gt;

&lt;p&gt;And there you have it — the culmination of our efforts. With the templates prepared, you can configure them to suit the specific use case, enabling seamless and repeatable deployments. This streamlined approach ensures adaptability and efficiency, allowing for quick and hassle-free setup whenever needed.&lt;/p&gt;

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

&lt;p&gt;In conclusion, we've walked through the essential steps to deploy SonarQube on AWS ECS using Cluster.dev covering its key aspects. This guide provides a seamless and efficient approach, empowering users to set up SonarQube on AWS ECS effortlessly. By combining the capabilities of SonarQube with the simplicity of Cluster.dev, we've created a reliable and easily managed infrastructure for elevated code analysis and quality assurance practices.&lt;/p&gt;

</description>
      <category>clusterdev</category>
      <category>ecs</category>
      <category>iac</category>
      <category>sonarqube</category>
    </item>
    <item>
      <title>Revolutionizing Infrastructure Management with Cluster.dev: A Journey into Effortless Orchestration</title>
      <dc:creator>Sidath Munasinghe</dc:creator>
      <pubDate>Tue, 23 Jan 2024 09:01:02 +0000</pubDate>
      <link>https://dev.to/aws-builders/revolutionizing-infrastructure-management-with-clusterdev-a-journey-into-effortless-orchestration-3e3c</link>
      <guid>https://dev.to/aws-builders/revolutionizing-infrastructure-management-with-clusterdev-a-journey-into-effortless-orchestration-3e3c</guid>
      <description>&lt;p&gt;In the ever-evolving landscape of cloud computing and DevOps, the quest for streamlined and efficient infrastructure management remains a perpetual challenge. Enter Cluster.dev, a cutting-edge tool poised to redefine the way we approach Infrastructure as Code (IaC). This innovative solution addresses the pain points that have long plagued existing IaC tools, offering a refreshing perspective and a promise of enhanced simplicity and effectiveness.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is IaC, and Why is it Important?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjuffqf9vl85tj5ls4ivj.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%2Fjuffqf9vl85tj5ls4ivj.png" alt="Source: https://biplus.com.vn/infrastructure-as-code-tools/" width="400" height="275"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before we unravel the intricacies of Cluster.dev, let’s take a step back to understand the significance of Infrastructure as Code. IaC represents a paradigm shift in how we manage and provision infrastructure resources. Instead of relying on manual configuration and deployment processes, IaC allows developers and operations teams to define infrastructure components programmatically. This enhances repeatability and consistency, accelerates development cycles, and promotes team collaboration. In essence, IaC transforms infrastructure management into a code-centric, version-controlled, and automated process, aligning seamlessly with the principles of DevOps. Here are some popular IaC tools widely used in the industry,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Terraform&lt;/li&gt;
&lt;li&gt;AWS CloudFormation&lt;/li&gt;
&lt;li&gt;Ansible&lt;/li&gt;
&lt;li&gt;AWS CDK&lt;/li&gt;
&lt;li&gt;Pulumi&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Challenges in the Current IaC Tools
&lt;/h2&gt;

&lt;p&gt;Although there are well-adopted IaC tools, teams often find themselves caught in a web of diverse tools, each with its own set of advantages and limitations. Orchestrating different infrastructure tools under the same roof presents a formidable challenge, requiring teams to navigate a complex maze of configurations, syntaxes, and deployment strategies. This lack of cohesion can lead to inefficiencies and increased learning curves.&lt;br&gt;
Moreover, maintaining consistent usage of these tools across an organization presents another challenge — ensuring adherence to best practices for establishing a resilient and reliable infrastructure.&lt;/p&gt;
&lt;h2&gt;
  
  
  What Cluster.dev Brings to the Current IaC Landscape?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpctp1iwqg0s3nhu9npik.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%2Fpctp1iwqg0s3nhu9npik.png" alt="Source: https://medium.com/@cluster.dev" width="200" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cluster.dev is a tool that uses Terraform, Helm alongside other infrastructure as code tools as building blocks to lay out complex infrastructures. It’s not competing with other IaC tools. Instead, it provides a higher abstraction, fixing the mentioned challenges while bringing different infrastructure tools under the same roof. Below are some key benefits introduced by Cluster.dev.&lt;/p&gt;
&lt;h3&gt;
  
  
  Orchestrating Diverse Tools
&lt;/h3&gt;

&lt;p&gt;Cluster.dev acknowledges the diversity of tools in the IaC ecosystem and addresses the challenge of managing them cohesively. By providing a centralized platform that seamlessly integrates with various infrastructure tools, it enables teams to leverage the strengths of each tool without compromising on unity.&lt;/p&gt;
&lt;h3&gt;
  
  
  Templating for Consistency
&lt;/h3&gt;

&lt;p&gt;One of the standout features of Cluster.dev is its powerful templating system. Templating allows organizations to implement common infrastructure patterns with best practices across the board. This reduces the implementation effort and ensures a consistent and standardized approach to infrastructure management.&lt;/p&gt;
&lt;h3&gt;
  
  
  Multi-Cloud Deployments
&lt;/h3&gt;

&lt;p&gt;Cluster.dev breaks down the silos between cloud providers by allowing the deployment of the same infrastructure pattern across multiple platforms. This feature empowers organizations to embrace a multi-cloud strategy, mitigating vendor lock-in and optimizing resource utilization based on specific provider strengths.&lt;/p&gt;
&lt;h3&gt;
  
  
  Template Sharing and Customization
&lt;/h3&gt;

&lt;p&gt;In the collaborative landscape of modern development, time is of the essence. Cluster.dev enables teams to share templates and tailor them to specific requirements swiftly. This fosters collaboration and saves valuable time by capitalizing on pre-defined templates that align with industry best practices.&lt;/p&gt;
&lt;h3&gt;
  
  
  Simplifying SaaS Deployments
&lt;/h3&gt;

&lt;p&gt;For SaaS vendors, Cluster.dev opens new frontiers by allowing the seamless integration of infrastructure templates into their products. This means SaaS providers can ship infrastructure as part of their product, simplifying enterprise software deployment for end-users and ensuring a smoother onboarding experience.&lt;/p&gt;
&lt;h3&gt;
  
  
  Enforce Best Practices and Standards
&lt;/h3&gt;

&lt;p&gt;One of the most significant challenges in infrastructure management is the consistent application of best practices and standards across various projects within an organization. Cluster.dev offers a solution to this predicament as well by allowing templates to be crafted and overseen by a dedicated platform/DevOps team possessing IaC expertise. This helps organizations to seamlessly implement and propagate best practices and patterns for infrastructure across all projects. Further, this ensures that development teams effortlessly adhere to standardized practices, fostering a more streamlined and efficient workflow.&lt;/p&gt;
&lt;h2&gt;
  
  
  Creating a Serverless API with Cluster.dev
&lt;/h2&gt;

&lt;p&gt;Now, let’s see this in action to see how convenient it is to use Cluster.dev to provision infrastructure seamlessly. Suppose we are starting a new project, and we need to create a serverless API on the AWS cloud with an API Gateway backed by Lambda. Let’s use Cluster.dev to initialize the project with a template for this use case.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a S3 bucket to hold the Cluster.dev backend state to keep track the infrastructure changes. We can quickly do this with AWS CLI.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws s3 mb s3://&amp;lt;bucket-name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Crete a project folder and initialize it with the appropriate Cluster.dev template. When we run its interactive CLI command to create the project, it guides us in completing the needed configurations and preparing it for our new project.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Implementation of this template can be found on this &lt;a href="https://github.com/sidathasiri/cdev-serverless-api" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir cdev-serverless-api
cd cdev-serverless-api
cdev project create https://github.com/sidathasiri/cdev-serverless-api --interactive
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s see the Cluster.dev interactive CLI steps to understand how it guides us to complete the project setup.&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%2Fd64wmvboj0palh4789qb.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%2Fd64wmvboj0palh4789qb.png" alt="Select the generator." width="800" height="461"&gt;&lt;/a&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%2Fxcwskvklezqqp8c4je0d.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%2Fxcwskvklezqqp8c4je0d.png" alt="Check the guide and hit continue." width="800" height="460"&gt;&lt;/a&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%2F5uz37n9jj5fe7qor1doa.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%2F5uz37n9jj5fe7qor1doa.png" alt="Provide the necessary configurations for the template and finish setting up the project." width="800" height="456"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can see it’s generating all the necessary infrastructure code according to the configurations provided by us. With just a single command, the entire infrastructure code is at your disposal — a seamless and efficient process! 😎&lt;/li&gt;
&lt;li&gt;Now, let’s deploy the infrastructure with the below command
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cdev apply
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before starting the deployment, this will reveal the infrastructure resource changes that will be applied so that we can review them before deploying.&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%2F5x7rs2nzn520d73in6gm.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%2F5x7rs2nzn520d73in6gm.png" alt="Review the infrastructure resource changes that are going to apply" width="800" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can review them and hit continue to proceed with the deployment.&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%2Fgh000lq2fzw4wkhgao88.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%2Fgh000lq2fzw4wkhgao88.png" alt="Deployment completion &amp;amp; verification" width="800" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the deployment is complete, we can see it outputs the deployed API URL as well. We can verify that the deployment is complete by sending a request to the API using curl.&lt;/p&gt;

&lt;p&gt;With Cluster.dev handling the complete infrastructure setup following the best practices, the development team can now direct their attention solely to implementing the core functionalities of the service. This seamless division of responsibilities streamlines the development process, allowing for a more focused and efficient approach to building the service functionalities.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Use Cluster.dev?
&lt;/h2&gt;

&lt;p&gt;We saw how convenient it is to use Cluster.dev to manage our infrastructure effortlessly. Here are several scenarios where Cluster.dev truly excels, bringing numerous benefits to your organization.&lt;/p&gt;

&lt;h3&gt;
  
  
  When your development teams lack knowledge in IaC
&lt;/h3&gt;

&lt;p&gt;Managing infrastructure can be a daunting task, especially when your development teams may not be well-versed in IaC. Cluster.dev comes to the rescue by providing a user-friendly interface for defining templates abstracting the complexities of infrastructure setup. This empowers development teams to work on their code efficiently without the need for extensive IaC expertise.&lt;/p&gt;

&lt;h3&gt;
  
  
  When you want to standardize your infrastructure
&lt;/h3&gt;

&lt;p&gt;Achieving consistency and adherence to best practices across diverse projects becomes effortless with Cluster.dev. By enabling the creation and ownership of templates by a dedicated platform or DevOps team, organizations can standardize infrastructure configurations. This ensures a unified and standardized approach, facilitating easier maintenance and reducing the risk of inconsistencies across different projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  When you are in a multi-cloud environment
&lt;/h3&gt;

&lt;p&gt;Managing infrastructure across multiple cloud providers can be challenging. Cluster.dev simplifies the orchestration of resources in a multi-cloud environment, offering a unified solution for deploying and managing infrastructure across various cloud platforms. This enhances flexibility and minimizes vendor lock-in while allowing organizations to make the most of the advantages offered by different cloud providers.&lt;/p&gt;

&lt;h3&gt;
  
  
  When you are on a microservices architecture
&lt;/h3&gt;

&lt;p&gt;In a microservices architecture, the complexity of managing numerous services and their associated infrastructure can be overwhelming. Cluster.dev aligns perfectly with this paradigm by allowing the definition of templates for each microservice, promoting scalability, flexibility, and efficient management of microservices-based infrastructures.&lt;/p&gt;

&lt;h3&gt;
  
  
  When you want to deploy repeatable complex infrastructure
&lt;/h3&gt;

&lt;p&gt;Deploying complex infrastructure consistently is a challenge, but Cluster.dev excels in this scenario. By defining templates that encapsulate intricate configurations, organizations can deploy repeatable and complex infrastructures seamlessly. This ensures reliability and reduces the likelihood of errors in the deployment process.&lt;/p&gt;

&lt;h3&gt;
  
  
  When you want to benefit from several IaC tools
&lt;/h3&gt;

&lt;p&gt;Cluster.dev acts as a bridge to various Infrastructure as Code tools, enabling organizations to leverage the strengths of different tools based on their requirements. Whether it’s Terraform, Helm, or other IaC tools, Cluster.dev provides a cohesive platform, allowing users to harness the benefits of multiple tools within a unified and streamlined workflow.&lt;/p&gt;

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

&lt;p&gt;Infrastructure as Code (IaC) has become a cornerstone in modern development practices, and Cluster.dev is at the forefront of revolutionizing this space. We’ve explored the significance of IaC, identified challenges in existing tools, and witnessed how Cluster.dev brings a fresh perspective to infrastructure orchestration. Whether simplifying serverless API creation or addressing broader infrastructure challenges, Cluster.dev emerges as a dynamic solution. With its versatility and adaptability, Cluster.dev beckons organizations to embrace a more efficient, standardized, and future-ready approach to infrastructure management.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>serverless</category>
      <category>devops</category>
      <category>iac</category>
    </item>
    <item>
      <title>Harnessing Feature Flags on AWS AppConfig for Seamless Software Evolution</title>
      <dc:creator>Sidath Munasinghe</dc:creator>
      <pubDate>Mon, 18 Dec 2023 04:26:37 +0000</pubDate>
      <link>https://dev.to/aws-builders/harnessing-feature-flags-on-aws-appconfig-for-seamless-software-evolution-46cj</link>
      <guid>https://dev.to/aws-builders/harnessing-feature-flags-on-aws-appconfig-for-seamless-software-evolution-46cj</guid>
      <description>&lt;p&gt;In the fast-paced realm of software development, agility and adaptability are not just a virtue but a necessity. Feature flagging is a versatile technique that offers a strategic approach for releasing features to end users, enabling rapid software development while giving more control to teams to evolve products.&lt;/p&gt;

&lt;p&gt;Feature flags decouple feature deployment from code deployment, allowing teams to release features incrementally and independently. Due to this, teams can do frequent code deployments darkly, although the entire feature development is incomplete. Once the entire feature development is complete and ready to enable users, it can be released on demand as needed. This promotes a continuous deployment approach, enabling faster time-to-market without disrupting the entire application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advantages of Feature Flags
&lt;/h2&gt;

&lt;p&gt;Incorporating feature flags introduces a lot of advantages to the software development process as well as to the software releases.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Risk Mitigation:&lt;/strong&gt; Feature flags can act as safety nets since they enable teams to turn off features in production if there are any issues without needing additional code deployments. This helps teams to troubleshoot issues and apply the fixes while keeping the production environment healthy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Personalization and Experimentation:&lt;/strong&gt; Feature flags provide the capability to enable features for specific users or user segments. This provides the canary feature enablement to roll out new features gradually. Further, this extends to conducting A/B testing and experimentation, where teams can gather valuable user feedback and data to make informed decisions about feature improvements.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unblock Dependencies:&lt;/strong&gt; It’s common in software development that teams get blocked due to dependencies with other teams. With feature flags, teams can work independently based on the design/contract and deploy even the partially completed implementation to production behind a feature flag. Once all teams have completed the implementation and everything is tested, it can be enabled for end users.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Graceful Degradation:&lt;/strong&gt; There are situations where systems receive excessive traffic, putting them under stress and leading to performance issues. In those scenarios, teams can use feature flags to turn off non-critical features and let the core features perform as expected.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  AppConfig Feature Flags
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj8bsqi1j34qb6ysrx8hn.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%2Fj8bsqi1j34qb6ysrx8hn.png" alt="Source: https://gallery.ecr.aws/aws-appconfig/aws-appconfig-agent" width="400" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;AWS AppConfig is a service that facilitates deploying and managing application configurations on the AWS cloud, including feature flags. It allows teams to create, manage, and deploy configurations seamlessly with several additional capabilities.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Rollout strategies:&lt;/strong&gt; AWS AppConfig supports different rollout strategies to enable feature activation in a controlled manner. This helps to identify potential issues, gather user feedback in a controlled manner, and react accordingly to keep rolling out or revert.&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%2Fkz5efaiiu9y2x4gfuqvb.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%2Fkz5efaiiu9y2x4gfuqvb.png" alt="Different rollout options in AppConfig feature flags" width="720" height="201"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Versioning:&lt;/strong&gt; The service supports automatic versioning of configurations, allowing teams to track the entire history of the configuration changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rollback:&lt;/strong&gt; When there is a need to change the flag status, AppConfig provides a built-in capability to rollback configuration to previous versions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manage Environments:&lt;/strong&gt; AppConfig has a concept called environment, which can be used to control feature flag values per each product environment. This helps to test the feature flag capabilities in non-prod environments first and then use them in production as needed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Data Retrieval in AppConfig Feature Flags
&lt;/h2&gt;

&lt;p&gt;The real magic behind the feature flags is we don’t need to redeploy applications to get the latest configuration changes. When we update the configuration settings, all the applications will get the latest changes automatically. Applications can get this capability by establishing a configuration session with the AppConfig server and polling for configuration changes. The sequence diagram below summarizes the overall communication flow.&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%2F976wsk6liuyygurgpnfl.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%2F976wsk6liuyygurgpnfl.png" alt="Sequence diagram for fetching feature flag configurations" width="411" height="301"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a configuration session using the application name, configuration profile, and environment we must connect to. In response, it will return a token to get the latest configuration in the next poll request.&lt;/li&gt;
&lt;li&gt;Once the application gets that token, it can be used to get the latest configuration by calling the GetLatestConfiguration API. In response, it will return the latest configuration settings and a new token for the next poll.&lt;/li&gt;
&lt;li&gt;The application can periodically call the GetLatestConfiguration API using the token that was retrieved previously.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here, the important thing is that the token can be used only once. So, the application needs to keep track of the latest token it received and use it in the subsequent request.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integration Options
&lt;/h2&gt;

&lt;p&gt;Since implementing this polling mechanism to get the flag status/configuration is not as straightforward, AWS has provided simplified integration options for common compute services.&lt;/p&gt;

&lt;h3&gt;
  
  
  AWS Lambda
&lt;/h3&gt;

&lt;p&gt;AWS Lambda can be easily integrated with AppConfig feature flags with &lt;strong&gt;AWS AppConfig Agent Lambda extension&lt;/strong&gt; as a layer to the lambda function. The lambda extension layer handles the polling implementation, and developers can benefit from feature flags. Further, the lambda layer will fetch and store the flag's statuses in a local cache, including the necessary tokens for subsequence API calls.&lt;/p&gt;

&lt;p&gt;To access its configuration data, the function can call the AWS AppConfig extension at an HTTP endpoint running on &lt;code&gt;localhost:2772&lt;/code&gt;. The following diagram shows how it works.&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%2Fg0osh3m00nccfb0b20li.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%2Fg0osh3m00nccfb0b20li.png" alt="Source: https://docs.aws.amazon.com/appconfig/latest/userguide/appconfig-integration-lambda-extensions.html" width="715" height="530"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Amazon EC2
&lt;/h3&gt;

&lt;p&gt;Like the lambda extension, an &lt;strong&gt;AWS AppConfig Agent&lt;/strong&gt; can be installed on the instance to interact with AppConfig and fetch and cache the flag configuration data on your behalf. As we saw earlier, the retrieved configurations can be accessed from &lt;code&gt;localhost:2772&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It is important to note that the agent is available for Linux operating systems running kernel version 4.15 or greater, and the agent can be installed via the &lt;strong&gt;yum&lt;/strong&gt; command-line package-management utility.&lt;/p&gt;

&lt;h3&gt;
  
  
  Amazon ECS and Amazon EKS
&lt;/h3&gt;

&lt;p&gt;AWS AppConfig can be integrated with AWS ECS and EKS using &lt;strong&gt;AWS AppConfig Agent&lt;/strong&gt;. The agent functions as a sidecar container running alongside the main container application. The agent will manage all the interactions with AppConfig, and the fetched configurations can be accessed from &lt;code&gt;localhost:2772&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrating into AWS Lambda
&lt;/h2&gt;

&lt;p&gt;Now, let’s walk through how to implement this for AWS Lambda, a common serverless computing service. We will use AWS CDK for the infrastructure code to automate the infrastructure provisioning.&lt;/p&gt;

&lt;p&gt;To implement this setup, we need to create the below resources on AWS.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AppConfig Application&lt;/li&gt;
&lt;li&gt;AppConfig Environment&lt;/li&gt;
&lt;li&gt;AppConfig Configuration Profile&lt;/li&gt;
&lt;li&gt;AppConfig Configuration Version&lt;/li&gt;
&lt;li&gt;Lambda Function&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s see each component and how to implement them with CDK constructs.&lt;/p&gt;

&lt;h3&gt;
  
  
  AppConfig Application
&lt;/h3&gt;

&lt;p&gt;An AppConfig Application refers to a logical entity that utilizes AWS AppConfig for managing its configuration settings. This could be any software application or service that benefits from dynamic and centralized configuration management.&lt;/p&gt;

&lt;p&gt;We can create an application with CDK using the code snippet below by providing a meaningful name for the use case.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const application = new CfnApplication(scope, `AppConfig Application`, 
  name: 'e-commerce-app',
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  AppConfig Environment
&lt;/h3&gt;

&lt;p&gt;An AppConfig Environment is a deployment environment within an AWS AppConfig application where the configurations are managed independently from each other. Environments provide a way to separate configurations for different stages of development, testing, and production, allowing for controlled and efficient management of configurations across different deployment scenarios.&lt;/p&gt;

&lt;p&gt;We can create an environment using the snippet below. Since we are creating an environment under an application, we need to provide a reference to the application we created earlier in addition to the environment name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const environment = new CfnEnvironment(scope, `AppConfig Environment`, {
  applicationId: application.ref,
  name: 'DEV',
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  AppConfig Configuration Profile
&lt;/h3&gt;

&lt;p&gt;A configuration profile helps to define what kind of configuration (feature flag/freeform) will be created and optionally defines any validators to ensure the configuration data is syntactically and semantically correct.&lt;/p&gt;

&lt;p&gt;The code snippet below creates a &lt;strong&gt;feature flag type&lt;/strong&gt; configuration profile called login. When we use the feature flag type, the location URI has to be set with &lt;strong&gt;hosted&lt;/strong&gt;. Further, we need to specify the application for this configuration profile.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const configurationProfile = new CfnConfigurationProfile(
  scope,
  `AppConfig ConfigurationProfile`,
  {
    applicationId: application.ref,
    locationUri: 'hosted',
    name: 'login',
    type: 'AWS.AppConfig.FeatureFlags',
   }
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  AppConfig Configuration Version
&lt;/h3&gt;

&lt;p&gt;An AppConfig Configuration Version represents a specific snapshot or version of a configuration. As configurations may evolve over time, different versions allow for tracking and managing changes. Each version is associated with a unique identifier.&lt;/p&gt;

&lt;p&gt;Using the code snippet below, we create a configuration version for a feature flag called &lt;strong&gt;sso_enabled&lt;/strong&gt;, which the value has set to &lt;strong&gt;true&lt;/strong&gt;. Similar to the previous constructs, we need to connect this with the application and the configuration profile we need to use.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const configurationVersion = new CfnHostedConfigurationVersion(
  scope,
  `AppConfig ConfigurationProfileVersion`,
  {
    applicationId: application.ref,
    configurationProfileId: configurationProfile.ref,
    contentType: 'application/json',
    content: JSON.stringify({
      flags: {
        flagkey: {
          name: 'sso_enabled',
        },
      },
      values: {
        flagkey: {
          enabled: true,
        },
      },
       version: '1',
    })
  }
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Lambda Function
&lt;/h3&gt;

&lt;p&gt;Now, we can create the lambda function and attach the lambda layer to integrate it with AppConfig. The lambda function must be configured with proper environment variables so the agent can connect with the required AppConfig application, environment and configuration profile, as shown in the code snippet below. Further, we must grant permissions via IAM to the lambda function to access AppConfig and fetch the configurations.&lt;/p&gt;

&lt;p&gt;Below is the CDK infrastructure code for the lambda function, including the lambda layer integration and permission granting to AppConfig.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const lambdaFunction = new NodejsFunction(this, 'my-lambda-fn', {
      entry: join(__dirname, '../src/lambdaHandler.ts'),
      runtime: Runtime.NODEJS_18_X,
      handler: 'handler',
      timeout: Duration.seconds(5),
      environment: {
        APPCONFIG_APPLICATION_ID: application.ref,
        APPCONFIG_ENVIRONMENT: environment.name,
        APPCONFIG_CONFIGURATION_ID: configurationProfile.ref
      },
});

lambdaFunction.addLayers(
  LayerVersion.fromLayerVersionArn(
    this,
    'AppConfigExtension',
    'arn:aws:lambda:us-east-1:027255383542:layer:AWS-AppConfig-Extension:128'
  )
);

lambdaFunction.role?.attachInlinePolicy(
  new Policy(this, 'PermissionsForAppConfig', {
    statements: [
      new PolicyStatement({
        actions: [
          'appconfig:StartConfigurationSession',
          'appconfig:GetLatestConfiguration',
        ],
        resources: ['*'],
      }),
    ],
  })
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we should be able to access &lt;code&gt;localhost:2772&lt;/code&gt; from the lambda handler function and get the configuration of the feature flag. The code snippet below shows a very basic implementation. In the request URL, we need to specify the AppConfig configurations we exposed as the environment variables to fetch the configuration from the correct application, configuration profile and the environment we want.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Handler } from 'aws-cdk-lib/aws-lambda';

export const handler: Handler = async (event: any) =&amp;gt; {
  const applicationId = process.env.APPCONFIG_APPLICATION_ID;
  const environment = process.env.APPCONFIG_ENVIRONMENT;
  const configurationId = process.env.APPCONFIG_CONFIGURATION_ID;

  const url = `http://localhost:2772/applications/${applicationId}/environments/${environment}/configurations/${configurationId}`;

  try {
    const response = await fetch(url);
    const responseData = await response.json();

    console.log('data:', JSON.stringify(responseData));
  } catch (error) {
    console.log(console.error);
  }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, when we test the lambda function from the AWS console, we can see that the AppConfig agent has started and the configuration values have fetched successfully from the CloudWatch logs.&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%2Fkbholjgwq4gy96rzlat3.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%2Fkbholjgwq4gy96rzlat3.png" alt=" " width="800" height="99"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The full implementation of this can be found on this &lt;a href="https://github.com/sidathasiri/appconfig-feature-flags" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;In conclusion, adopting feature flags, particularly through AWS AppConfig, empowers software teams to achieve a smooth and adaptive software evolution. The advantages of feature flags, such as controlled rollout, risk mitigation, and dynamic configuration, are effectively harnessed using AppConfig, offering real-time control and seamless integration with AWS services.&lt;/p&gt;

&lt;p&gt;Different integration options underscore AppConfig’s flexibility in catering to diverse development environments. Altogether, leveraging feature flags on AWS AppConfig enhances development agility, allowing teams to respond dynamically to evolving requirements and user feedback, ultimately fostering a resilient and user-centric software evolution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/appconfig/latest/userguide/appconfig-integration-lambda-extensions.html" rel="noopener noreferrer"&gt;Retrieving configuration data using the AWS AppConfig Agent Lambda extension&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/appconfig/latest/userguide/appconfig-integration-ec2.html" rel="noopener noreferrer"&gt;Retrieving configuration data from Amazon EC2 instances&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/appconfig/latest/userguide/appconfig-integration-containers-agent.html" rel="noopener noreferrer"&gt;Retrieving configuration data from Amazon ECS and Amazon EKS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sidathasiri/appconfig-feature-flags" rel="noopener noreferrer"&gt;Sample implementation with Node SDK&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>appconfig</category>
      <category>featureflag</category>
      <category>featurereleases</category>
    </item>
    <item>
      <title>Building WebSocket APIs with AWS API Gateway and CDK</title>
      <dc:creator>Sidath Munasinghe</dc:creator>
      <pubDate>Sat, 21 Oct 2023 12:18:30 +0000</pubDate>
      <link>https://dev.to/aws-builders/building-websocket-apis-with-aws-api-gateway-and-cdk-1i27</link>
      <guid>https://dev.to/aws-builders/building-websocket-apis-with-aws-api-gateway-and-cdk-1i27</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In the continuously evolving landscape of web applications, real-time communication has become the gold standard for creating engaging and interactive user experiences. Whether you’re building a chat application, a collaborative online game, or a live dashboard, WebSocket technology has emerged as the enchanting solution that makes real-time magic happen. And when it comes to unleashing the full potential of WebSockets in a serverless and scalable manner, Amazon Web Services (AWS) has a spell of its own — AWS API Gateway.&lt;/p&gt;

&lt;p&gt;In this article, we will go through the fundamental concepts of WebSocket API in Amazon API Gateway and create a small application to evaluate its capabilities using the AWS Cloud Development Kit (CDK).&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding WebSocket APIs
&lt;/h2&gt;

&lt;p&gt;WebSocket is a protocol that allows full duplex communication between a client and server using a persistent connection for continuous communication. Since the WebSocket connection is persistent, it allows extremely fast data transmission.&lt;/p&gt;

&lt;p&gt;Unlike the short-lived stateless connections in HTTP, WebSocket leverages long-lived opened connections to exchange messages with each other independently. This feature allows WebSocket connections to go beyond the traditional request and response model, making it the ideal solution for use cases like chat applications, live broadcasts, and extremely fast data synchronization.&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%2F6oxb3vsp705jcfdbm34q.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%2F6oxb3vsp705jcfdbm34q.png" alt="WebSockets vs HTTP" width="800" height="658"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, when implementing a WebSockets API, some of the crucial areas that we need to pay extra attention to are,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;connection management:&lt;/strong&gt; manage incoming connections appropriately when clients connect and disconnect&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;security:&lt;/strong&gt; ensure protection of data in transit&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;message routing:&lt;/strong&gt; determine how WebSocket messages will be routed to the appropriate handlers on the server side&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;monitoring and logging:&lt;/strong&gt; set up monitoring and logging to keep track of WebSocket connection status, performance, and potential issues&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  AWS API Gateway for WebSocket APIs
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbyjz25vqut1blrlpjzfl.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%2Fbyjz25vqut1blrlpjzfl.png" alt="AWS API Gateway" width="300" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Amazon API Gateway is a fully managed service that makes it easy for developers to create, publish, maintain, monitor, and secure APIs at any scale. Apart from the HTTP-based restful APIs, it allows creating and managing WebSocket APIs as well by simplifying the areas we discussed above while allowing developers to focus on the core functionality of the real-time applications. Here are the key benefits of using AWS API Gateway for building your next WebSocket API.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Abstracts out the protocol understanding:&lt;/strong&gt; AWS API Gateway abstracts much of the WebSocket protocol details, making it easier to use. It manages the handshaking process and connection handling, allowing you to focus on application logic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplified infrastructure management:&lt;/strong&gt; It takes care of the WebSocket server setup and configuration, eliminating the need for you to manage the WebSocket server infrastructure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration options:&lt;/strong&gt; API Gateway can be integrated with multiple backend sources such as lambda functions, DynamoDB tables, or HTTP endpoints to implement any logic based on the content of the messages it receives from the client.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security:&lt;/strong&gt; Access can be controlled by AWS IAM or lambda authorizers to implement your authorization logic. Further, it supports WSS (WebSocket Secure) to have encrypted connections for enhanced security, like protecting against man-in-the-middle attacks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easy message routing:&lt;/strong&gt; AWS API Gateway permits you to define routes for WebSocket messages and map them to specific AWS Lambda functions, enabling you to handle them as required.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring and Logging:&lt;/strong&gt; AWS CloudWatch Logs and Metrics monitors the WebSocket APIs created with AWS API Gateway, allowing us to monitor its statuses and get alerts when it needs our attention to investigate any critical issue.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Basics of AWS API Gateway for WebSocket APIs
&lt;/h2&gt;

&lt;p&gt;AWS API Gateway service utilizes its fundamental concepts, such as models, authorizers, and stages for WebSocket APIs as well. Below are the additional concepts we need to know when using WebSocket APIs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Routes
&lt;/h3&gt;

&lt;p&gt;In a WebSocket API, incoming JSON messages are directed to backend integrations based on routes you configure, similar to the endpoints in RestFul APIs. API Gateway provides three predefined routes as below.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;$connect:&lt;/strong&gt; Triggers when a persistent connection between the client and a WebSocket API is initiated.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;$disconnect:&lt;/strong&gt; Triggers when the client or the server disconnects from the API.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;$default:&lt;/strong&gt; Triggers if the route selection expression cannot be evaluated against the message or if no matching route is found. This is useful for handling invalid messages gracefully.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can also create custom routes to cater to the business requirements and functionalities. To handle incoming requests, these routes must be connected with available backend integrations, such as Lambda functions, DynamoDB tables, etc.&lt;/p&gt;

&lt;p&gt;In WebSocket-based communications, connection IDs are very important since they need to be presented to exchange messages. The creation of connection IDs is handled by API Gateway for us, but implementing the logic to handle those events is up to us. For example, we can integrate a lambda function to the &lt;code&gt;$connect&lt;/code&gt; route to implement some logic to store the newly created connection ID in a datastore for functionality like broadcasting an event. Also, we will need to delete those entries by implementing some logic behind the &lt;code&gt;$disconnet&lt;/code&gt; route.&lt;/p&gt;

&lt;h3&gt;
  
  
  One-way/Two-way Communication
&lt;/h3&gt;

&lt;p&gt;WebSockets are bidirectional by nature. However, AWS API Gateway allows us to configure one-way or two-way communication routes. If configured for one-way, there won’t be any response after completing the message processing. When two-way communication is enabled, we can implement some logic to receive acknowledgements after complete processing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Route Selection Expression
&lt;/h3&gt;

&lt;p&gt;API Gateway uses the route selection expression to determine which route to invoke when a client sends a message. When creating a WebSocket API, we must provide the route selection expression. Therefore, before creating the API, we must decide what the message structure looks like. For example, we can use an attribute called action in the message to specify the route like below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
   "action": "createTodo",
   "data": {
      "name": "Create WebSocket API",
      "completed": false
   }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this scenario, we can use &lt;code&gt;$request.body.action&lt;/code&gt; as the route selection expression. Here &lt;code&gt;$request.body&lt;/code&gt; refers to the message payload. We can choose an appropriate attribute we want based on the message structure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Building the WebSocket API with CDK&lt;/strong&gt;&lt;br&gt;
Now let’s create a very simple WebSocket API using AWS CDK with Typescript to define and deploy the infrastructure and apply the concept we just learned. We will also add a custom route to send a message to a connection so that we can play around and test it. Below are the main steps we have to follow.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create three lambda functions to handle new WebSocket connections/disconnections and send a message to a connection.&lt;/li&gt;
&lt;li&gt;Create a WebSocket API&lt;/li&gt;
&lt;li&gt;Create a custom route for sending a message&lt;/li&gt;
&lt;li&gt;Integrate lambda functions to routes&lt;/li&gt;
&lt;li&gt;Grant any required permissions&lt;/li&gt;
&lt;li&gt;Test the API&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Lambda functions
&lt;/h3&gt;

&lt;p&gt;Let’s first create the three lambda functions so we can directly integrate them when creating the WebSockets API routes. The below code snippet shows how to create the mentioned Lambda functions using the NodejsFunction construct in CDK.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Lambda function to handle new connections
const wsConnectLambda = new NodejsFunction(this, 'ws-connect-lambda', {
      entry: join(__dirname, '../src/connect/index.ts'),
      handler: 'handler',
      functionName: 'connect-lambda',
      runtime: Runtime.NODEJS_18_X,
});

// Lambda function to handle disconnections
const wsDisconnectLambda = new NodejsFunction(
      this,
      'ws-disconnect-lambda',
      {
        entry: join(__dirname, '../src/disconnect/index.ts'),
        handler: 'handler',
        functionName: 'disconnect-lambda',
        runtime: Runtime.NODEJS_18_X,
      }
);

// Lambda function to handle sending messages
const sendMessageLambda = new NodejsFunction(this, 'send-message-lambda', {
      entry: join(__dirname, '../src/send-message/index.ts'),
      runtime: Runtime.NODEJS_18_X,
      functionName: 'send-message',
      handler: 'handler',
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let’s review the handler function implementations for each function. The below code snippet shows the implementation of the connection handler function.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connection Handler Function
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const handler = async (event: APIGatewayProxyEvent) =&amp;gt; {
  const connectionId = event.requestContext.connectionId;
  console.log('connection created:', connectionId);
  return { statusCode: 200, body: 'Connected.' };
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We only log the generated connection ID when a new client connects with the API to keep this as simple as possible. If you have any sophisticated logic, we can implement them here.&lt;/p&gt;

&lt;h3&gt;
  
  
  Disconnection Handler Function
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const handler = async (event: APIGatewayProxyEvent) =&amp;gt; {
  const connectionId = event.requestContext.connectionId;
  console.log('Disconnected:', connectionId);
  return { statusCode: 200, body: 'Disconnected.' };
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also only log the connection ID when a connection terminates for simplicity. We can extend this implementation to match the business requirements.&lt;/p&gt;

&lt;h3&gt;
  
  
  Send Message Handler Function
&lt;/h3&gt;

&lt;p&gt;We use this function to send messages to another connection. Below is the structure of the message format we are going to use.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
   "action":"sendMessage",
   "connectionId":"&amp;lt;receiver's connection id&amp;gt;",
   "message":"&amp;lt;message content&amp;gt;"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Below is the definition of these attributes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;action:&lt;/strong&gt; Acts as the route selection attribute&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;connectionId:&lt;/strong&gt; Contains the receiver’s connection ID&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;message:&lt;/strong&gt; Message content&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this information, we can implement the below logic inside this lambda function to handle this requirement.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const handler = async (event: APIGatewayProxyEvent) =&amp;gt; {
  const apigwManagementApi = new ApiGatewayManagementApi({
    apiVersion: '2018-11-29',
    endpoint:
      event.requestContext.domainName + '/' + event.requestContext.stage,
  });

  const eventBody = JSON.parse(event.body ?? '');
  const connectionId = eventBody.connectionId;
  const message = eventBody.message;

  console.log('Payload:', { ConnectionId: connectionId, Data: message });

  try {
    await apigwManagementApi
      .postToConnection({ ConnectionId: connectionId, Data: message })
      .promise();
  } catch (error) {
    console.error('Error sending message:', error);
  }
  return { statusCode: 200, body: 'Message sent' };
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we get the connectionId and the message from the event body and then use AWS API Gateway Management API to post the received message to the received connection.&lt;/p&gt;

&lt;h3&gt;
  
  
  WebSocket API
&lt;/h3&gt;

&lt;p&gt;Since the lambda functions are ready now, let’s create the WebSockets API. The below code snippet demonstrates how to create it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Create WebSocket API with connection/disconnection route integrations
const webSocketApi = new apigw2.WebSocketApi(
      this,
      'my-first-websocket-api',
      {
        connectRouteOptions: {
          integration: new WebSocketLambdaIntegration(
            'ws-connect-integration',
            wsConnectLambda
          ),
        },
        disconnectRouteOptions: {
          integration: new WebSocketLambdaIntegration(
            'ws-disconnect-integration',
            wsDisconnectLambda
          ),
        },
      }
);

// Create API stage
const apiStage = new apigw2.WebSocketStage(this, 'dev', {
      webSocketApi,
      stageName: 'dev',
      autoDeploy: true,
});

// Add the custom sendMessage route
webSocketApi.addRoute('sendMessage', {
      integration: new WebSocketLambdaIntegration(
        'send-message-integration',
        sendMessageLambda
      ),
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We first create the WebSocket API using the WebSocketApi CDK construct in the above code. Since our connection/disconnection lambda functions are ready, we have also integrated those while creating the API. Then, we defined a dev stage for the API as usual in a typical API in AWS API Gateway. Finally, we have added our custom route for the message-sending purpose. Note that since we are using sendMessage as the action in the message payload, we need to mention the same here as well when adding the route. Further, we don’t need to mention the route selection expression here, since we can use the default value ($request.body.action) provided by CDK construct.&lt;/p&gt;

&lt;p&gt;There is one last thing missing in this setup. Our send message lambda function needs permission to post messages to connections. So we need to add the below code segment as well to grant those permissions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Get the resource ARN of the created WebSocket API
const connectionsArns = this.formatArn({
      service: 'execute-api',
      resourceName: `${apiStage.stageName}/POST/*`,
      resource: webSocketApi.apiId,
});

// Attach the required policy to the relavant lambda function
sendMessageLambda.addToRolePolicy(
      new PolicyStatement({
        actions: ['execute-api:ManageConnections'],
        resources: [connectionsArns],
      })
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now everything is complete, and we can deploy the infrastructure to AWS using the &lt;code&gt;cdk deploy&lt;/code&gt; command.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing
&lt;/h3&gt;

&lt;p&gt;Once the deployment is complete, we can get the API’s WebSocket URL with wssprotocol from the API Gateway console. For testing purposes, we can use any WebSocket testing tool like &lt;a href="https://www.piesocket.com/websocket-tester" rel="noopener noreferrer"&gt;piesocket&lt;/a&gt; to connect and send messages.&lt;/p&gt;

&lt;p&gt;We can give our WebSocket API URL to this tool to test the connection creation. We should be able to see the connection ID in the Cloudwatch logs of connection handling lambda. We can connect with as many clients as we want and track their connection IDs to send messages.&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%2Ftxba973daa29n95ipt58.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%2Ftxba973daa29n95ipt58.png" alt="Log of different connection IDs in Cloudwatch" width="800" height="178"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, we can use these connection IDs to send messages to each other using the custom route we created.&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%2Fovr5zrpwsklhr0707nal.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%2Fovr5zrpwsklhr0707nal.png" alt="Message history of connection 1" width="800" height="396"&gt;&lt;/a&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%2Fl5a9tbbds65s17q13oxe.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%2Fl5a9tbbds65s17q13oxe.png" alt="Message history of connection 2" width="800" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since the message sending is working as expected, now we can try the disconnection handler’s functionality. When a client disconnects, we should be able to see the appropriate log as well.&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%2F29qe2fbs5zdhchwtdvn7.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%2F29qe2fbs5zdhchwtdvn7.png" alt="Appropriate logs for disconnected connections" width="800" height="184"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So everything is working as expected, and it takes very little time to implement using the capabilities of AWS API Gateway. We can enhance the security of the API by introducing authorizers and access control mechanisms. Further, you can use CloudWatch to monitor the service status using different metrics, such as the connection count.&lt;/p&gt;

&lt;p&gt;The full source code for this example application can be found in this &lt;a href="https://github.com/sidath-munasinghe/apigateway-websocket-api" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;From the introduction to the basics of WebSocket APIs, we’ve navigated through the realm of real-time web development. AWS API Gateway stood as our gateway to real-time magic, simplifying the complexities and providing security and scalability. Armed with this knowledge, your journey into real-time web development begins, where you can create captivating applications with the help of AWS CDK. Embrace the magic, and let your applications come alive in the world of real-time experiences!&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api-overview.html" rel="noopener noreferrer"&gt;About WebSocket APIs in API Gateway&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/websocket-api-chat-app.html" rel="noopener noreferrer"&gt;Tutorial: Building a serverless chat app with a WebSocket API, Lambda and DynamoDB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/wesleycheek/deploy-a-cognito-secured-websocket-api-with-aws-cdk-jei"&gt;Deploy a Cognito Secured WebSocket API with AWS CDK&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>apigateway</category>
      <category>aws</category>
      <category>serverless</category>
      <category>websockets</category>
    </item>
  </channel>
</rss>
