<?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>Forem: Sakshi Agarwal</title>
    <description>The latest articles on Forem by Sakshi Agarwal (@sakshi360).</description>
    <link>https://forem.com/sakshi360</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%2F1016235%2Fbd4b46a9-ef1f-4d5c-8bdf-9d924e65ee9d.png</url>
      <title>Forem: Sakshi Agarwal</title>
      <link>https://forem.com/sakshi360</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/sakshi360"/>
    <language>en</language>
    <item>
      <title>SOLID Principles: Building Robust Systems, Brick by Brick</title>
      <dc:creator>Sakshi Agarwal</dc:creator>
      <pubDate>Wed, 26 Mar 2025 07:40:28 +0000</pubDate>
      <link>https://forem.com/sakshi360/solid-principles-building-robust-systems-brick-by-brick-1b5h</link>
      <guid>https://forem.com/sakshi360/solid-principles-building-robust-systems-brick-by-brick-1b5h</guid>
      <description>&lt;p&gt;System design can feel like building a complex structure. Without a strong foundation, your system can become brittle, difficult to maintain, and prone to collapse under pressure. That's where the SOLID principles come in. These five principles, when applied correctly, act as the sturdy foundation for building robust, scalable, and maintainable software systems.&lt;/p&gt;

&lt;p&gt;Let's break them down in the easiest way possible:&lt;br&gt;
Think of building a house. You want it to be strong, easy to fix, and easy to add to later. That’s what SOLID principles do for software.&lt;/p&gt;
&lt;h2&gt;
  
  
  1. One Thing Per Room-Single Responsibility Principle (SRP)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it means:&lt;/strong&gt; &lt;br&gt;
Each room in your house has one main job. The kitchen is for cooking, the bedroom is for sleeping, etc.&lt;br&gt;
&lt;strong&gt;In code:&lt;/strong&gt;&lt;br&gt;
Each “part” of your software should do one thing well. Don’t try to make your kitchen also be the garage.&lt;br&gt;
&lt;strong&gt;Why it's good:&lt;/strong&gt;&lt;br&gt;
 If the kitchen sink breaks, you don't have to rebuild the whole house. You just fix the kitchen.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# House Analogy: Kitchen does cooking, bedroom does sleeping.
# Code Example:

class Kitchen:
    def cook_meal(self, meal):
        print(f"Cooking {meal} in the kitchen.")

class Bedroom:
    def sleep(self):
        print("Sleeping in the bedroom.")

# Bad Example (mixing responsibilities):
# class MultiPurposeRoom:
#     def cook_meal(self, meal):
#         # ...
#     def sleep(self):
#         # ...

my_kitchen = Kitchen()
my_bedroom = Bedroom()

my_kitchen.cook_meal("dinner")
my_bedroom.sleep()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Adding Rooms Without Tearing Down Walls (Open/Closed Principle)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it means:&lt;/strong&gt;&lt;br&gt;
You should be able to add a new room (like a sunroom) without having to knock down existing walls.&lt;br&gt;
&lt;strong&gt;In code:&lt;/strong&gt;&lt;br&gt;
 You should be able to add new features to your software without changing the old code.&lt;br&gt;
&lt;strong&gt;Why it's good:&lt;/strong&gt;&lt;br&gt;
You don't accidentally break the living room while building the sunroom.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class HouseRoom:
    def area(self):
        pass  # Base room, can't calculate area alone

class Bedroom(HouseRoom):
    def __init__(self, length, width):
        self.length = length
        self.width = width

    def area(self):
        return self.length * self.width

class Sunroom(HouseRoom):
    def __init__(self, length, width):
        self.length = length
        self.width = width

    def area(self):
        return self.length * self.width

def calculate_room_area(room):
    print(f"Room area: {room.area()}")

my_bedroom = Bedroom(10, 12)
my_sunroom = Sunroom(8, 8)
calculate_room_area(my_bedroom)
calculate_room_area(my_sunroom)

# Bad Example (modifying existing code to add new room types):
# def calculate_room_area(room, room_type):
#     if room_type == "bedroom":
#         print(f"Bedroom area: {room.length * room.width}")
#     elif room_type == "sunroom":
#         print(f"Sunroom area: {room.length * room.width}")
#     # ... (would need to modify this function for every new room type)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3.Using Interchangeable Parts (Liskov Substitution Principle)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it means:&lt;/strong&gt;&lt;br&gt;
 Think of standard sized building materials. If you design a door frame for a "standard door," you should be able to put in any door that fits that standard size, whether it's a wooden door, a metal door, or a glass door. All these doors should "fit" where a "standard door" is expected&lt;br&gt;
&lt;strong&gt;In code:&lt;/strong&gt; &lt;br&gt;
If you have a general "shape" for something (like a "door"), all the specific types of that thing (like "wooden door," "metal door") should work in the same way wherever you use the general "shape."&lt;br&gt;
&lt;strong&gt;Why it's good:&lt;/strong&gt;&lt;br&gt;
It means you can easily swap out parts without having to rebuild the whole structure. If you need a more secure door, you can just replace the wooden one with a metal one, and it should still fit the same frame.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Door:
    def fit(self, frame_width, frame_height):
        pass

class WoodenDoor(Door):
    def fit(self, frame_width, frame_height):
        print(f"Wooden door fitting in {frame_width}x{frame_height} frame.")

class MetalDoor(Door):
    def fit(self, frame_width, frame_height):
        print(f"Metal door fitting in {frame_width}x{frame_height} frame.")

def install_door(door, frame_width, frame_height):
    door.fit(frame_width, frame_height)

my_wooden_door = WoodenDoor()
my_metal_door = MetalDoor()

install_door(my_wooden_door, 36, 80)
install_door(my_metal_door, 36, 80)

# Bad Example (violating LSP):
# class Wall:
#     def fit(self, frame_width, frame_height):
#         raise Exception("Walls do not fit in door frames.") # Wall doesnt work where door is expected.
#
# my_wall = Wall()
# install_door(my_wall, 36, 80) # This would fail.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Only the Tools You Need (Interface Segregation)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it means:&lt;/strong&gt;&lt;br&gt;
If you’re building a house, you don’t carry around every tool. You bring the hammer for nails, the saw for wood.&lt;br&gt;
&lt;strong&gt;In code:&lt;/strong&gt;&lt;br&gt;
 If a part of your software only needs a few abilities, don’t give it all the abilities. Give it just the ones it needs.&lt;br&gt;
&lt;strong&gt;Why it's good:&lt;/strong&gt; &lt;br&gt;
It keeps things simple. The hammer doesn’t get in the way when you’re using the saw.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class HammerTool:
    def hammer_nails(self):
        print("Hammering nails.")

class SawTool:
    def cut_wood(self):
        print("Cutting wood.")

class SimpleBuilder:
    def use_hammer(self, hammer):
        hammer.hammer_nails()

class Carpenter:
    def use_hammer(self, hammer):
        hammer.hammer_nails()
    def use_saw(self, saw):
        saw.cut_wood()

my_hammer = HammerTool()
my_saw = SawTool()

builder = SimpleBuilder()
builder.use_hammer(my_hammer)

carpenter = Carpenter()
carpenter.use_hammer(my_hammer)
carpenter.use_saw(my_saw)

# Bad Example (large interface, not all builders need all tools):
# class BuilderTool:
#     def hammer_nails(self):
#         pass
#     def cut_wood(self):
#         pass
#
# class SimpleBuilder:
#     def use_tool(self, tool: BuilderTool):
#         tool.hammer_nails()
#
# class Carpenter:
#     def use_tool(self, tool: BuilderTool):
#         tool.hammer_nails()
#         tool.cut_wood()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. Don’t Care Who Made the Pipes, Just That They Work (Dependency Inversion)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it means:&lt;/strong&gt;&lt;br&gt;
You don’t care who made the pipes in your house, just that they carry water.&lt;br&gt;
&lt;strong&gt;In code:&lt;/strong&gt;&lt;br&gt;
 Your software shouldn’t depend on specific “parts.” It should depend on general “ways of doing things.”&lt;br&gt;
&lt;strong&gt;Why it's good:&lt;/strong&gt;&lt;br&gt;
If the pipe company goes out of business, you can easily switch to another brand of pipes. The water still flows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class WaterSource:
    def supply_water(self):
        pass

class Pipe:
    def __init__(self, source: WaterSource):
        self.source = source

    def deliver_water(self):
        self.source.supply_water()
        print("Water delivered through pipe.")

class CityWater(WaterSource):
    def supply_water(self):
        print("City water supply.")

class WellWater(WaterSource):
    def supply_water(self):
        print("Well water supply.")

city_water = CityWater()
well_water = WellWater()

my_pipe = Pipe(city_water)
my_pipe.deliver_water()

my_pipe = Pipe(well_water)
my_pipe.deliver_water()

# Bad Example (depending on concrete implementations):
# class Pipe:
#     def __init__(self, city_water): # Hard dependency on CityWater
#         self.city_water = city_water
#
#     def deliver_water(self):
#         self.city_water.supply_water()
#         print("Water delivered through pipe.")
#
# my_pipe = Pipe(CityWater()) # Would break if we needed to use WellWater.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;In Simple Words:&lt;/strong&gt;&lt;br&gt;
SOLID helps you build software that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is easy to understand.&lt;/li&gt;
&lt;li&gt;Is easy to change.&lt;/li&gt;
&lt;li&gt;Is less likely to break when you change it.&lt;/li&gt;
&lt;li&gt;Is easy to reuse parts of.&lt;/li&gt;
&lt;li&gt;It's like building a house that’s well-organized, easy to fix, and easy to add to later. You would never build a house where changing the kitchen broke the bathroom, and neither should you build software that way.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>systemdesign</category>
      <category>solidprinciples</category>
      <category>programming</category>
    </item>
    <item>
      <title>Efficiently Deleting Multiple Lakhs of Records from DynamoDB Using Lambda: A Comprehensive Guide</title>
      <dc:creator>Sakshi Agarwal</dc:creator>
      <pubDate>Sun, 29 Sep 2024 17:39:02 +0000</pubDate>
      <link>https://forem.com/sakshi360/efficiently-deleting-multiple-lakhs-of-records-from-dynamodb-using-lambda-a-comprehensive-guide-1hnl</link>
      <guid>https://forem.com/sakshi360/efficiently-deleting-multiple-lakhs-of-records-from-dynamodb-using-lambda-a-comprehensive-guide-1hnl</guid>
      <description>&lt;p&gt;DynamoDB, a highly scalable NoSQL database service offered by AWS, is designed for high throughput and low latency. However, deleting a massive number of records at once can be a performance-intensive operation. This blog post will guide you through the process of efficiently deleting multiple lakhs of records from DynamoDB using a Lambda function, incorporating best practices and addressing common challenges.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Considerations&lt;/strong&gt;&lt;br&gt;
Before diving into the code, it's essential to consider the following:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Partition Key&lt;/strong&gt;: DynamoDB uses a partition key to distribute data across partitions. Ensure that the partition key values are evenly distributed to avoid hot partitions.&lt;br&gt;
&lt;strong&gt;Batch Write Operations&lt;/strong&gt;: DynamoDB supports batch write operations, which can significantly improve performance by allowing you to delete multiple items in a single request.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Throttling&lt;/strong&gt;: Be mindful of DynamoDB's throttling limits. Exceeding these limits can result in errors and delays.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consistency&lt;/strong&gt;: If consistency is crucial, consider using DynamoDB's strong consistency mode. However, this may impact performance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Filter Expression&lt;/strong&gt;: Use a filter expression to selectively delete records based on specific criteria, reducing the number of items to be processed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lambda Function Code&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here's a Python Lambda function that demonstrates how to efficiently delete multiple lakhs of records from DynamoDB using batch write operations, filter expressions, and last evaluated key handling:&lt;br&gt;
&lt;/p&gt;

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

dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('your_table_name')

def delete_records(records, last_evaluated_key):
    with table.batch_writer() as batch:
        for record in records:
            batch.delete_item(Key={'partition_key': record['partition_key'], 'sort_key': record['sort_key']})

    return batch.response.get('LastEvaluatedKey')

def handler(event, context):
    filter_expression = "attribute_name = :value"
    expression_attribute_values = {':value': "your_filter_value"}

    response = table.scan(
        FilterExpression=filter_expression,
        ExpressionAttributeValues=expression_attribute_values
    )

    records = response['Items']
    last_evaluated_key = response.get('LastEvaluatedKey')

    while last_evaluated_key:
        response = table.scan(
            FilterExpression=filter_expression,
            ExpressionAttributeValues=expression_attribute_values,
            ExclusiveStartKey=last_evaluated_key   

        )

        records.extend(response['Items'])
        last_evaluated_key = response.get('LastEvaluatedKey')

    # Divide the records into batches to avoid throttling
    batch_size = 25
    batches = [records[i:i+batch_size] for i in range(0, len(records), batch_size)]

    for batch in batches:
        last_evaluated_key = delete_records(batch, last_evaluated_key)
        # Introduce a delay to avoid throttling
        time.sleep(1)

    return {'statusCode': 200, 'body': 'Records deleted successfully'}

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Explanation:
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Filter Expression:&lt;/strong&gt; The filter_expression and expression_attribute_values parameters allow you to selectively delete records based on specific criteria, reducing the number of items to be processed.&lt;br&gt;
&lt;strong&gt;Last Evaluated Key:&lt;/strong&gt; The last_evaluated_key is used to efficiently handle large datasets by retrieving items in batches and continuing from the last processed item.&lt;br&gt;
&lt;strong&gt;Batch Processing&lt;/strong&gt;: The records are divided into batches to avoid throttling and improve performance. The delete_records function now returns the LastEvaluatedKey to be used in subsequent scans.&lt;br&gt;
&lt;strong&gt;Looping&lt;/strong&gt;: The code uses a loop to continue scanning and deleting records until there are no more items to process.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Additional Considerations&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Error Handling:&lt;/strong&gt; Implement proper error handling mechanisms to catch exceptions and log errors for troubleshooting.&lt;br&gt;
&lt;strong&gt;Performance Optimization:&lt;/strong&gt; If you're dealing with an extremely large number of records, consider using DynamoDB's global secondary indexes or partitioning strategies to improve performance.&lt;br&gt;
&lt;strong&gt;Parallel Processing&lt;/strong&gt;: For even faster deletion, explore using multiple Lambda functions or a distributed system to process the records in parallel.&lt;br&gt;
&lt;strong&gt;Cost Optimization:&lt;/strong&gt; If cost is a concern, carefully evaluate the number of Lambda invocations and the amount of data transferred to optimize your costs.&lt;br&gt;
By following these guidelines and customizing the code to your specific use case, you can effectively delete multiple lakhs of records from DynamoDB using a Lambda function, ensuring efficient, scalable, and cost-effective operations.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>dynamodb</category>
    </item>
    <item>
      <title>Building Scalable GraphQL APIs with AWS AppSync: A Deep Dive into Operations</title>
      <dc:creator>Sakshi Agarwal</dc:creator>
      <pubDate>Tue, 12 Sep 2023 10:21:59 +0000</pubDate>
      <link>https://forem.com/sakshi360/building-scalable-graphql-apis-with-aws-appsync-a-deep-dive-into-operations-47bm</link>
      <guid>https://forem.com/sakshi360/building-scalable-graphql-apis-with-aws-appsync-a-deep-dive-into-operations-47bm</guid>
      <description>&lt;p&gt;Before moving on to App Sync and its core operations, let's understand GraphQL in simpler terms.&lt;br&gt;
          GraphQL is a modern API query language that enables clients to request specific data from a server, eliminating over-fetching and under-fetching of information. It uses a schema to define data types and operations, giving clients control over the data they receive. This flexibility and efficiency make it a powerful alternative to traditional REST APIs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is AWS AppSync?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AWS AppSync is a managed service that allows you to easily develop GraphQL APIs by connecting to various data sources. It abstracts the complexities of managing the infrastructure and provides real-time data synchronization and offline access to your applications. &lt;/p&gt;

&lt;p&gt;In this technical blog post, we'll delve into AWS AppSync and explore its core operations: &lt;em&gt;Query, Mutation, and Subscription.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Operation 1: Query&lt;/strong&gt;&lt;br&gt;
Purpose: Query operations are used for fetching data from your GraphQL API. Think of them as read-only operations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;query {
  getTodo(id: "123") {
    id
    title
    completed
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;In this query, we're requesting specific fields (id, title, and completed) for a todo item with the ID "123". AWS AppSync retrieves this data from your data source, and the response contains the requested information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Operation 2: Mutation&lt;/strong&gt;&lt;br&gt;
Purpose: Mutation operations modify data in your GraphQL API. You can use mutations to create, update, or delete records.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mutation {
  createTodo(input: {
    title: "Buy groceries",
    completed: false
  }) {
    id
    title
    completed
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;This mutation creates a new todo item with the specified title ("Buy groceries") and completion status (false). The response provides details about the newly created todo item, including its ID, title, and completion status.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Operation 3: Subscription&lt;/strong&gt;&lt;br&gt;
Purpose: Subscription operations enable real-time updates. Clients can subscribe to specific events, and the server pushes updates to subscribed clients when those events occur.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;subscription {
  onTodoUpdated {
    id
    title
    completed
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;This operation allows clients to receive real-time updates when todo items are updated. It listens for changes to the specified fields (id, title, and completed) and sends immediate updates to subscribed clients. This feature is crucial for building responsive applications with live data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Advantages of AWS AppSync Operations&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Simplicity&lt;/strong&gt;: AWS AppSync abstracts the complex setup of GraphQL servers, making it easy to get started with API development.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real-Time Data&lt;/strong&gt;: Subscriptions in AWS AppSync simplify the implementation of real-time features, such as chat applications, live dashboards, and collaborative editing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security&lt;/strong&gt;: AWS AppSync seamlessly integrates with AWS Cognito and other authentication providers, ensuring secure access control to your data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flexibility&lt;/strong&gt;: With AppSync, you can connect to various data sources, including databases like DynamoDB and RESTful APIs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scalability&lt;/strong&gt;: AWS AppSync automatically scales to handle high loads, eliminating the need for manual infrastructure provisioning.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In Conclusion&lt;/strong&gt;&lt;br&gt;
AWS AppSync's operations make building GraphQL APIs straightforward. Use Queries for reading data, Mutations for modifying data, and Subscriptions for real-time updates. Simplify API development, focus on user experiences, and leverage AWS AppSync for your next project.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>graphql</category>
    </item>
    <item>
      <title>Building a Serverless User Details Fetching API with AWS Lambda, DynamoDB, OOP Principles and Powertools</title>
      <dc:creator>Sakshi Agarwal</dc:creator>
      <pubDate>Thu, 25 May 2023 07:06:13 +0000</pubDate>
      <link>https://forem.com/sakshi360/building-a-serverless-user-details-fetching-api-with-aws-lambda-dynamodb-oop-principles-and-powertools-nfb</link>
      <guid>https://forem.com/sakshi360/building-a-serverless-user-details-fetching-api-with-aws-lambda-dynamodb-oop-principles-and-powertools-nfb</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
In the world of serverless computing, AWS Lambda has gained popularity for its scalability and cost efficiency. In this blog post, we will explore how to build a Lambda function that fetches user details from DynamoDB using object-oriented programming (OOP) principles. To enhance our function with advanced observability and operational best practices, we will leverage the power of the AWS Lambda Powertools library.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites:&lt;/strong&gt;&lt;br&gt;
To follow along with this tutorial, you should have a basic understanding of AWS Lambda, DynamoDB, and Python programming. You should also have an AWS account and the necessary permissions to create Lambda functions and access DynamoDB.&lt;/p&gt;

&lt;p&gt;Here's an example of a Lambda function written using object-oriented programming (OOP) principles to fetch user details from DynamoDB:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from aws_lambda_powertools import Logger, Tracer, Validator
from aws_lambda_powertools.utilities.data_classes import APIGatewayProxyEvent

import boto3

logger = Logger()
tracer = Tracer()
validator = Validator()

class UserFetcher:
    def __init__(self, table_name):
        self.dynamodb = boto3.resource('dynamodb')
        self.table = self.dynamodb.Table(table_name)

    def fetch_user_details(self, user_id):
        response = self.table.get_item(Key={'user_id': user_id})
        user_details = response.get('Item')
        return user_details

@tracer.capture_lambda_handler
@logger.inject_lambda_context
def lambda_handler(event: APIGatewayProxyEvent, context):
    # Validate input using powertools.Validator
    validator.validate(event, "user_id")
    user_id = event.path_parameters.get('user_id')

    # Initialize UserFetcher object
    user_fetcher = UserFetcher('UserTable')

    try:
        # Fetch user details from DynamoDB
        user_details = user_fetcher.fetch_user_details(user_id)
        logger.info(f"Fetched user details: {user_details}")

        return {
            "statusCode": 200,
            "body": user_details
        }
    except Exception as e:
        logger.error(f"Error fetching user details: {str(e)}")
        return {
            "statusCode": 500,
            "body": "Error fetching user details"
        }

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 1: Setting Up the Environment&lt;/strong&gt;&lt;br&gt;
Before we begin writing code, let's set up our environment. Create a new Lambda function using the AWS Management Console or the AWS CLI. Choose a Python runtime, and configure the function with appropriate permissions to access DynamoDB. Install the AWS Lambda Powertools library by adding it to your function's deployment package.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Writing the UserFetcher Class&lt;/strong&gt;&lt;br&gt;
To encapsulate the logic for fetching user details from DynamoDB, we will create a UserFetcher class using OOP principles. This class will have a constructor (init) method to initialize the DynamoDB resource and table, and a fetch_user_details method that takes a user_id as input and retrieves the corresponding user details from DynamoDB using the get_item API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Implementing Input Validation and Logging with Powertools&lt;/strong&gt;&lt;br&gt;
To enhance our function's robustness and visibility, we will use the AWS Lambda Powertools library. Within the lambda_handler function, we will use the powertools.utilities.validator module to validate the input and raise an exception if it's missing. Additionally, we will leverage powertools.Logger to log informative messages and handle any exceptions that occur during the execution of our Lambda function.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4: Testing and Deploying the Lambda Function&lt;/strong&gt;&lt;br&gt;
Once we have written the code for our Lambda function, we can test it locally using a tool like the AWS SAM CLI or by creating a test event in the AWS Lambda console. Ensure that your DynamoDB table exists and has the required user data. Deploy the Lambda function to your AWS account using the deployment mechanism of your choice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion:&lt;/strong&gt;&lt;br&gt;
In this blog post, we learned how to build a serverless API using AWS Lambda, DynamoDB, and OOP principles. We enhanced our Lambda function with input validation and logging using the AWS Lambda Powertools library. By following the step-by-step guide and leveraging Powertools, we created a robust and observable solution for fetching user details. This approach allows us to build scalable and reliable serverless applications while adhering to best practices and leveraging advanced tools.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>oops</category>
      <category>lambda</category>
      <category>dynamodb</category>
    </item>
    <item>
      <title>JSON Web Tokens(JWT) For Authentication and Authorization in AWS</title>
      <dc:creator>Sakshi Agarwal</dc:creator>
      <pubDate>Mon, 17 Apr 2023 16:30:43 +0000</pubDate>
      <link>https://forem.com/sakshi360/json-web-tokensjwt-for-authentication-and-authorization-in-aws-1c29</link>
      <guid>https://forem.com/sakshi360/json-web-tokensjwt-for-authentication-and-authorization-in-aws-1c29</guid>
      <description>&lt;p&gt;&lt;strong&gt;JSON Web Tokens&lt;/strong&gt; (JWTs) are a compact type of access token that is used to securely transmit information between parties. In the context of authentication, a JWT can be used as a secure and stateless way to authenticate users and authorize access to resources. It can be verified locally by the client without the need to call the third-party service (such as an OAuth provider) every time the client wants to access a protected resource.&lt;/p&gt;

&lt;p&gt;JWTs can be verified locally because they are self-contained and contain all the necessary information to verify their authenticity. A JWT consists of three parts: &lt;strong&gt;a header, a payload, and a signature.&lt;/strong&gt;&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;The header contains information about the type of token and the algorithm used to sign it.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt; &lt;em&gt;The payload contains the claims or assertions about the user or entity that the token represents.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt; &lt;em&gt;The signature is created by combining the header, payload, and a secret key that is only known to the server. The signature can be used to verify the authenticity of the JWT.&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When a client sends a JWT to a server, the server can verify the authenticity of the token by decoding the token, checking the signature using the secret key, and verifying that the claims in the payload are valid. Since the secret key is only known to the server, this process ensures that only tokens issued by the server are accepted, and that the claims in the token have not been tampered with.&lt;/p&gt;

&lt;p&gt;In contrast to OAuth, which relies on a centralized authorization server to manage access tokens, &lt;strong&gt;JWTs can be verified locally without the need for a third-party service&lt;/strong&gt;. This makes JWTs a good option for applications that need to authenticate and authorize users without relying on external services.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here's how you can use JWTs for authentication and authorization:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;em&gt;The client (such as a web or mobile app) sends a request to your server with a username and password.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;- &lt;em&gt;Your server authenticates the user and generates a JWT that includes the user's ID and any relevant permissions or roles.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;- &lt;em&gt;Your server sends the JWT back to the client in the response.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;- &lt;em&gt;The client stores the JWT (usually in local storage or a cookie) and sends it in the Authorization header of subsequent requests to your server&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;- &lt;em&gt;Your server verifies the JWT by checking the signature and decoding the claims (such as the user ID and permissions).&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;- &lt;em&gt;If the JWT is valid, your server allows the request and returns the requested resource or performs the requested action.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;- &lt;em&gt;If the JWT is invalid or expired, your server returns an error response.&lt;/em&gt;
_&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  To use JWT (JSON Web Token) in AWS using Python, you can follow these steps:
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.Create a JWT token using PyJWT:&lt;/strong&gt;&lt;/p&gt;

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

import jwt

def lambda_handler(event, context):
    # Generate a JWT with a payload containing the user's data
    token = jwt.encode({'username': 'johndoe', 'role': 'admin'}, 'my-secret-key', algorithm='HS256')

    return {
        'statusCode': 200,
        'body': token,
    }




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

&lt;/div&gt;

&lt;p&gt;In this example, the payload is a dictionary that includes the user ID and permissions. The secret key is a string that is used to sign the JWT. The jwt.encode() function encodes the payload and signs it with the secret key using the HS256 algorithm.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.- Verify the JWT in API Gateway:&lt;/strong&gt;&lt;br&gt;
Make an API request to an AWS service (e.g., AWS Lambda) and include the JWT token in the request headers:&lt;/p&gt;

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

import requests

url = 'https://your-lambda-function-endpoint.amazonaws.com'
headers = {'Authorization': f'Bearer {token.decode()}'}

response = requests.get(url, headers=headers)



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

&lt;/div&gt;

&lt;p&gt;In the above example, we make an HTTP GET request to an AWS Lambda function using the requests library. We include the JWT token in the request headers using the Authorization field with the Bearer prefix.&lt;/p&gt;

&lt;p&gt;Note that the token variable needs to be decoded to a string before it can be included in the headers.&lt;/p&gt;

&lt;p&gt;That's it! You should now be able to use JWT in AWS using Python.&lt;/p&gt;

</description>
      <category>python</category>
      <category>jwt</category>
      <category>aws</category>
    </item>
    <item>
      <title>AWS SES with Lambda</title>
      <dc:creator>Sakshi Agarwal</dc:creator>
      <pubDate>Wed, 15 Mar 2023 10:55:27 +0000</pubDate>
      <link>https://forem.com/sakshi360/aws-ses-with-lambda-51g4</link>
      <guid>https://forem.com/sakshi360/aws-ses-with-lambda-51g4</guid>
      <description>&lt;p&gt;Amazon SES (Simple Email Service) is a simple service that can be used by small and large industries to send marketing, transaction and notification emails as the cost is less and it is reliable. SES can be easily integrated to an existing application with the help of SMTP or AWS SDK.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why SES ?
&lt;/h2&gt;

&lt;p&gt;• Building an in house email solutions is a complex and expensive challenge for a business due to the infrastructure demands, network assembly and security involved. Also some proper third-&lt;br&gt;
party email solutions require huge up-front prices. SES eliminates these complexities.&lt;br&gt;
• It have the benefit of a refined email infrastructure that amazon has used for its large consumer base.&lt;br&gt;
• With SES there are not any direct prices and no minimum commitments. If we use SES in an Amazon EC2 instance, the first 62,000 emails sent are free and a very low price for emails sent&lt;br&gt;
thereafter.&lt;br&gt;
• Also SES can be integrated with other AWS services to provide seamless email solutions to the end users. You pay as you go, and you pay just for what you utilize.&lt;/p&gt;

&lt;h2&gt;
  
  
  SES Configuration
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;SES can be configured to be used in two ways.&lt;/strong&gt;&lt;br&gt;
• Use SES as outbound email server&lt;br&gt;
• Using existing server and configure it to send the mails through Amazon SES.&lt;/p&gt;

&lt;h2&gt;
  
  
  SES with AWS Lambda
&lt;/h2&gt;

&lt;p&gt;To send Emails from a Lambda function using SES we need to configure the following.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;• Required IAM Lambda permissions for the API call.&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;ses:SendEmail&lt;/strong&gt; – &lt;em&gt;Email is immediately queued for sending after composing&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ses:SendRawEmail&lt;/strong&gt; – &lt;em&gt;This is suitable in cases where we need to add attachments or HTML content.&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These policies can be attached to an IAM role that would be assigned to our Lambda function.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;• Verified SES identity.&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;em&gt;To use SES it is required to verify sender email addresses to confirm that the sender owns them and to prevent unauthorized use.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;We must verify each identity that we use. From, Source, Sender and Return address&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Email addresses are case sensitive&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;If both email address and the domain the mail ID belongs is verified, the email address settings override the domain settings.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Verification status is different for each region. If we want to send mails from the same
identity from different regions it has to be verified in all regions.&lt;/em&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Following is a simple Lambda example function using SES.
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import boto3
client = boto3.client(
    'ses',
    region_name=region,
    aws_access_key_id='aws_access_key_string',
    aws_secret_access_key='aws_secret_key_string'
)
response = client.send_email(
    Destination={
        'ToAddresses': ['recipient1@domain.com', 'recipient2@domain.com'],
    },
    Message={
        'Body': {
            'Text': {
                'Charset': 'UTF-8',
                'Data': 'email body string',
            },
        },
        'Subject': {
            'Charset': 'UTF-8',
            'Data': 'email subject string',
        },
    },
    Source='sender.email@domain.com',
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Benefits of SES
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;High Deliverability&lt;/strong&gt;:&lt;br&gt;
Features like content filtering and reputation dashboard ensure high number of emails are delivered. Higher the sender’s reputation more the number of emails sent from that address.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost-Effective&lt;/strong&gt;:&lt;br&gt;
No upfront or fixed costs and the cost depends on our monthly usage of this service.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configurable&lt;/strong&gt;:&lt;br&gt;
SES can be configured with other AWS services like EC2, ECS and Cloudwatch to get detailed analysis of the mail metrics and also get notifications using SNS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Cases
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Transactional&lt;/strong&gt;:&lt;br&gt;
&lt;em&gt;SES can be used to send automated mails for order confirmation, delivery, and subscription related information.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Notifications&lt;/strong&gt;:&lt;br&gt;
&lt;em&gt;Notifications on application health and metrics and send user notifications when an event is triggered.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Incoming Mails&lt;/strong&gt;:&lt;br&gt;
&lt;em&gt;SES can be used to receive mails and programmatically route the same to a S3 bucket.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Marketing&lt;/strong&gt;:&lt;br&gt;
&lt;em&gt;Promotions, offers and new product details can be sent in high quality emails using SES.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>serverless</category>
      <category>awscommunitybuilders</category>
      <category>ses</category>
    </item>
  </channel>
</rss>
