DEV Community

Gurudev Prasad Teketi
Gurudev Prasad Teketi

Posted on

Hands-on Lab - Event Driven Architecture with Amazon API Gateway, Amazon EventBridge and AWS Lambda

Event-driven architecture

is a design pattern where events are utilized to trigger and facilitate communication between decoupled services, making it a common choice for modern applications built with microservices. Serverless architecture, on the other hand, provides a model for building and running applications and services without the need to provision or manage underlying infrastructure.

Objective of the Lab

  • Configure an HTTP API on API Gateway to redirect requests to EventBridge.
  • Create event bus rules that match incoming requests and route events to Lambda functions.
  • Process events with Lambda functions and send the processed events back to the event bus as new events.
  • Publish events to the event bus, triggering separate Lambda functions.
  • Lambda functions receive events and post them back to the client application via a WebSocket connection hosted on API Gateway.

High Level Architecture Diagram

Image description

Step 1

Implement five Lambda functions using below configurations and code and deploy each lambda

  • Function name, enter: make_pizza

    • For Runtime, select: Python 3.12
    • For Change default execution role, choose - lab_lambda_make_pizza
    • Environment variable: Key: EVENT_BUS, Value: lab_event_bus
  • Function name, enter: cook_pizza

    • For Runtime, select: Python 3.12
    • For Change default execution role, choose - lab_lambda_cook_pizza
    • Environment variable: Key: EVENT_BUS, Value: lab_event_bus
  • Function name, enter: deliver_pizza

    • For Runtime, select: Python 3.12
    • For Change default execution role,choose - lab_lambda_deliver_pizza
    • Environment variable: Key: EVENT_BUS, Value: lab_event_bus
  • Function name, enter: websocket_connect

    • For Runtime, select: Python 3.12
    • For Change default execution role,choose - lab_lambda_websocket_connection
    • Environment variable: Key: TABLENAME, Value: websocket_connections
  • Function name, enter: receive_events

    • For Runtime, select: Python 3.12
    • For Change default execution role,choose - lab_lambda_receive_events
    • Environment variable: Key: TABLENAME, Value: receive_events

Image description

Image description

Image description

Image description

Sample Lambda function code for Make Pizza:

import json
import boto3
import os
from botocore.exceptions import ClientError

client = boto3.client('events')

def lambda_handler(event, context):
  try:
    detail = event["detail"]
    detail["item"]["eventtype"]="cook_pizza"
    response = client.put_events(
      Entries=[
        {
          'DetailType': 'eventtype',
          'Detail': json.dumps(detail),
          'EventBusName': os.environ.get('EVENT_BUS'),
          'Source':"make_pizza"
        },
      ]
    )
    print(response)
  except ClientError as err:
    print(err)
Enter fullscreen mode Exit fullscreen mode

Sample Lambda function code for Cook Pizza:

import json
import boto3
import os
from botocore.exceptions import ClientError

client = boto3.client('events')

def lambda_handler(event, context):
  try:
    detail = event["detail"]
    detail["item"]["eventtype"]="deliver_pizza"
    response = client.put_events(
      Entries=[
        {
          'DetailType': 'eventtype',
          'Detail': json.dumps(detail),
          'EventBusName': os.environ.get('EVENT_BUS'),
          'Source':"cook_pizza"
        },
      ]
    )
    print(response)
  except ClientError as err:
    print(err)
Enter fullscreen mode Exit fullscreen mode

Sample Lambda function code for Deliver Pizza:

import json
import boto3
import os
from botocore.exceptions import ClientError

client = boto3.client('events')

def lambda_handler(event, context):
  try:
    detail = event["detail"]
    detail["item"]["eventtype"]="delivered"
    response = client.put_events(
      Entries=[
        {
          'DetailType': 'eventtype',
          'Detail': json.dumps(detail),
          'EventBusName': os.environ.get('EVENT_BUS'),
          'Source':"deliver_pizza"
        },
      ]
    )
  except ClientError as err:
    print(err)
Enter fullscreen mode Exit fullscreen mode

Sample Lambda function code for Websocket Connect:

import boto3
import json
import os
from botocore.exceptions import ClientError

dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table(os.environ.get('TABLENAME'))

def lambda_handler(event, context):
  try:
    order_id=event['queryStringParameters']['order_id']
    response = table.put_item(
      Item={
      'order_id': order_id,
      'connection_id': event["requestContext"]["connectionId"]
      })

    return {
      "statusCode": 200,
      "headers": {
      "Content-Type": "application/json"
    }
    }
  except ClientError as err:
    print(err)
Enter fullscreen mode Exit fullscreen mode

Sample Lambda function code for Receive Events:

import boto3
import json
import os
from botocore.exceptions import ClientError

dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table(os.environ.get('TABLENAME'))
management = boto3.client('apigatewaymanagementapi', endpoint_url=os.getenv('APIGW_ENDPOINT'))

def lambda_handler(event, context):
  try:
    response = table.get_item(
      Key={
      'order_id': event["detail"]['item']['order_id']
      }
    )
    management.post_to_connection(
      Data=json.dumps(event["detail"]),
      ConnectionId=response["Item"]["connection_id"]
    )
  except ClientError as err:
    print(err)
Enter fullscreen mode Exit fullscreen mode

Step 2
Configure EventBridge

  • Configure the rules with the following settings and select Next .
  • Build event pattern screen, under the Creation method section, select Custom pattern (JSON editor) for the Method.
  • Copy and paste the json object into the Event pattern editor,
  • On the Select target(s) page, from the Target 1 section under Target types, choose AWS service.
  • From the Select a target drop-down list, choose Lambda function.
  • From the Function drop-down list, choose make_pizza.
  • Choose the correspondoing role
  • Select Next and select Next again on the Configure tags - optional screen.
  • On the Review and create screen, select Create rule.

Configurations for each rule

Name: lab_make_pizza_rule
Event bus: lab_event_bus

{
  "detail": {
    "item": {
      "eventtype": ["make_pizza"]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Name: lab_cook_pizza_rule
Event bus: lab_event_bus

{
  "detail": {
    "item": {
      "eventtype": ["cook_pizza"]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Name: lab_deliver_pizza_rule
Event bus: lab_event_bus

{
  "detail": {
    "item": {
      "eventtype": ["deliver_pizza"]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Name: lab_receive_events_rule
Event bus: lab_event_bus

{
  "detail": {
    "item": {
      "eventtype": ["make_pizza","cook_pizza","deliver_pizza"]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Image description

Image description

Image description

Image description

Step 4
Configure API Gateway

  • In the console Choose API Gateway.
  • In the Choose an API type select Build from the HTTP API section.
  • In the API Name field, enter lab_http_api
  • Select Next until you get to the Review and Create screen, then choose Create.

  • Under the Develop section in the left-hand navigation pane, select Routes, then choose Create .

  • Select POST from the drop-down list, and select Create.

  • Under the Develop select Integrations, choose the POST route link and then select Create and attach an integration.

  • For Integration target, configure the following options.

  • Integration type: Amazon EventBridge

  • Integration action: PutEvents

  • EventBridge - PutEvents, configure the following options.

  • Detail: $request.body

  • Detail type: eventtype

  • Source: lab_http_api

  • Invocation role, copy the APIExecutionRoleARN

  • Expand Advanced settings, and configure the remaining fields. Select Create when you are finished.

  • For Event bus name - optional, enter the event bus ARN you saved in Task 2.

  • Region - optional.

  • From the left-hand navigation pane, select CORS and choose Configure in the top right corner.

  • Access-Control-Allow-Origin enter *.

  • Access-Control-Allow-Methods select, POST.

  • Access-Control-Allow-Headers, enter *.

  • Save.

  • From the navigation menu on the left-hand side of the screen, navigate to the endpoint details screen by selecting API: lab_http_api. Copy and save the Invoke URL from the Stages for lab_http_api section of the API: lab_api screen. The URL is needed in Task 4.

  • Now create the web socket API endpoint, which is used to send events back to the web application. Web socket connections are two-way persistent connections allowing bi-directional communication and are often used by chat applications.

  • At the top of the left-hand navigation pane, select APIs, then select Create API .

  • In the Choose an API type select **Build from the WebSocket API **section.

  • Configure the following fields and select Next .

  • API Name field: lab_websocket_api

  • Route selection expression: request.body.action

  • On the Add routes page choose Add $connect route and select Next .

  • The websocket_connect function invokes when the application establishes the connection. This function saves the connection ID to a DynamoDB table.

  • Integration type: Lambda.

  • Lambda function websocket_connect.

  • Select Next .

  • On the Add Stages page select Next, followed by Create and deploy .

  • Select Stages from the left-hand navigation page and choose the Production stage.

  • Copy and save the WebSocket URL, as it is needed shortly.

  • Copy the Connection URL up to, but do not include the @connections text.

  • Navigate back to the Lambda console and open the receive_events Lambda function.

  • On the configuration tab select Environment variables, choose Edit and select Add environment variable.

  • Configure the variable with the following settings, and select Save when you are finished.

  • Key: APIGW_ENDPOINT

  • Value: the copied Connection URL

Testing the ED Architecture

Image description

Top comments (0)