DEV Community

Cover image for Amazon EventBridge Intro | Serverless
awedis for AWS Community Builders

Posted on • Edited on

Amazon EventBridge Intro | Serverless

Amazon EventBridge helps you to simplify your architecture, it is a serverless event bus service, you can use it to connect your applications with data from a variety of sources

The main parts of this article:

  1. Amazon EventBridge (Main components)
  2. About Event Bus
  3. Example

1. About Amazon EventBridge

EventBridge allows you to build event-driven architectures, which are loosely coupled and distributed. It enables you to be faster in building and innovating

Some Keynotes:

  • Decoupling- When using distributed architecture, EventBridge makes sure the application remains decoupled
  • Simplified event routing - Ensure services remain simple, only listening to events they care about, and only being responsible for creating events
  • Improved Availability - In synchronous APIs the availability of the entire system can be impacted from the failure of any single service. While in asynchronous infrastructure based on events allows more resilience, and with the right architecture design you can improve availability too
  • Third party integration - you can ingest data seamlessly in near real time using events

EventBridge main parts:

  • Event Buses - An event bus is a pipeline that receives events. Rules associated with the event bus evaluate events as they arrive. Each rule checks whether an event matches the rule’s criteria
  • Events - An event is a real-time change in a system, data, or environment. This change can be either in your application or in an AWS service or a SaaS partner service
  • Rules - A rule matches incoming events and sends them to targets for processing. A single rule can send an event to multiple targets, which then run in parallel. Rules are based either on an event pattern or a schedule
  • Targets - A target is a resource or endpoint that EventBridge sends an event when it matches the event pattern defined for a rule. The rule processes the event data and sends the pertinent information to the target

Image description

📋 Note: For more information and detailed documentation you can visit the official site through this link

2. What is Event Bus?

An event bus is a pipeline that receives events. Rules associated with the event bus evaluate events as they arrive. Each rule checks whether an event matches the rule's criteria. You associate a rule with a specific event bus, so the rule only applies to events received by that event bus

Event producer don't need any knowledge who is listening to the events and on the other hand services that consume events don't need to know about upstream changes

Event Bus provides an endpoint where the event producer can send events, the router manages directing and filtering those events to the appropriate downstream consumers, consumers can get the events reliably while the producers remain decoupled

3. Example

In this section we are going to build a scenario based example

Before starting in serverless.yml we need to add the permission, so that our lambda function is able to put the event into the EventBridge

  • serverless.yml:
provider:
  name: aws
  runtime: nodejs14.x
  stage: v1
  region: eu-west-1
  iamRoleStatements:
    - Effect: "Allow"
      Action:
        - "events:PutEvents"
      Resource: "*"
Enter fullscreen mode Exit fullscreen mode

Every time the user calls addProduct (λ) API, the lambda will add the item inside MySQL database and it will trigger an EventBridge that will trigger another Lambda Function to store the logs inside DynamoDB logProduct (λ)

  • Architecture:
    Image description

  • Code logic overview:

on API call:
  store in MySQL Database
  if stored successfully:
    putEvents [Source, DetailType, Detail]

when we receive the event:
  trigger target lambda:
    get the value from `event`
    put the data in DynamoDB
Enter fullscreen mode Exit fullscreen mode

Rules inside EventBridge use Event Pattern that are JSON objects, through the console we are going to create a Rule inside Amazon EventBridge that has the following Event Pattern

{
  "source": ["log.addProduct"]
}
Enter fullscreen mode Exit fullscreen mode

And then we specify which lambda function will be triggered in the targets section

The addProduct Lambda function: (provoked from API Gateway)

  • Route (routes.yml):
addProduct:
  handler: src/modules/Test/controller/test.addProduct
  events:
    - http:
        method: post
        path: product
        cors: true
Enter fullscreen mode Exit fullscreen mode
  • Body (sent from postman):
{
    "userId": "user-123",
    "name": "My First Book",
    "category": "Finance",
    "price": 100
}
Enter fullscreen mode Exit fullscreen mode

📋 Note: I am using mysql-serverless in order to be able to query MySQL Database

  • To stablish connection with my database:
const mysql = require('serverless-mysql')({
  config: {
    host: process.env.MYSQL_HOST,
    database: process.env.MYSQL_DATABASE,
    user: process.env.MYSQL_USER,
    password: process.env.MYSQL_PASSWORD,
  }
});

module.exports.mysql = mysql;
Enter fullscreen mode Exit fullscreen mode

📋 Note: In order to create my Products table in my database, we are going to use MySQL Workbench, and run this sql code below:

use products;

CREATE TABLE Products (
  ID int Not NULL AUTO_INCREMENT,
  UserID varchar(255),
  Name varchar(255),
  Category varchar(255),
  Price varchar(255),
  PRIMARY KEY (ID)
)
Enter fullscreen mode Exit fullscreen mode
  • The addProduct Lambda function code:
module.exports.addProduct = async (event) => {
  try {
    console.log('event =>', event);
    const body = JSON.parse(event.body);

    const {
      userId,
      name,
      category,
      price,
    } = body;
    const result = await mysql.query(`INSERT INTO Products (UserID, Name, Category, Price) VALUES (?, ?, ?, ?)`, [userId, name, category, price]);
    console.log('result =>', result);

    const putEventResult = await putEvent(body);
    console.log('putEventResult =>', putEventResult);

    return {
      statusCode: 200,
      body: JSON.stringify({message: 'This is EventBridge API'}, null, 2),
    };
  } catch (error) {
    console.log(error);
  }
};
Enter fullscreen mode Exit fullscreen mode
const AWS = require('aws-sdk');
const eventBridge = new AWS.EventBridge();

module.exports.putEvent = (body) => {
  var params = {
    Entries: [
      {
        Detail: JSON.stringify(body),
        DetailType: 'add-product',
        Source: 'log.addProduct'
      }
    ]
  };
  return eventBridge.putEvents(params).promise();
}
Enter fullscreen mode Exit fullscreen mode

If we can notice Source here is log.addProduct the value that we created previously from the console (Event Pattern)

The logProduct Lambda function code: (triggered from EventBridge)

  • Route:
logProduct:
  handler: src/modules/Test/controller/test.logProduct
Enter fullscreen mode Exit fullscreen mode
  • Code:
module.exports.logProduct = async (event) => {
  try {
    console.log('event =>', event);
    const {
      detail,
    } = event;

    const addResult = await putLog(detail);
    console.log('addResult =>', addResult);

  } catch (error) {
    console.log(error);
  }
};
Enter fullscreen mode Exit fullscreen mode
const dynamoose = require('dynamoose');
const { v4: uuidv4 } = require('uuid');
const { Log } = require('./log.schema');

dynamoose.aws.sdk.config.update({
  accessKeyId: process.env.access_key_id,
  secretAccessKey: process.env.secret_access_key,
  region: process.env.region,
});

module.exports.putLog = async (body) => {
  const {
    insertedId,
    userId: UserId,
    name: Name,
  } = body;

  return await Log.create({
    PK: `Log#${uuidv4()}`,
    SK: `Product#Log`,
    ProductId: insertedId,
    UserId,
    Name,
    Action: 'NEW_PRODUCT',
  });
}
Enter fullscreen mode Exit fullscreen mode
  • Dynamoose Log Schema:

📋 Note: Dynamoose is a modeling tool for Amazon DynamoDB

const dynamoose = require('dynamoose');

const string_required = {
  type: String,
  required: true,
};

const number_required = {
  type: Number,
  required: true,
};

const LogSchema = new dynamoose.Schema({
  PK: string_required,
  SK: string_required,
  ProductId: number_required,
  UserId: string_required,
  Name: string_required,
  Action: {
    type: String,
    required: true,
    enum: ["NEW_PRODUCT"],
  },
});

module.exports.Log = dynamoose.model('Log', LogSchema);
Enter fullscreen mode Exit fullscreen mode

The event output inside the CloudWatch for the logProduct lambda function:

2022-07-11T21:03:56.946Z    e8e89bb6-1341-4bb9-88c6-3840f5ca2298    INFO    event => {
  version: '0',
  id: '87dafa0a-9e87-9502-a032-c6b02b48a37a',
  'detail-type': 'add-product',
  source: 'log.addProduct',
  account: '260776636198',
  time: '2022-07-11T21:03:56Z',
  region: 'eu-west-1',
  resources: [],
  detail: {
    userId: 'user-123',
    name: 'My First Book',
    category: 'Finance',
    price: 100,
    insertedId: 1
  }
}
Enter fullscreen mode Exit fullscreen mode
  • Lambda Layers (Dependencies):
{
  "dependencies": {
    "aws-sdk": "^2.1185.0",
    "dynamoose": "^2.8.6",
    "serverless-mysql": "^1.5.4",
    "uuid": "^8.3.2"
  }
}
Enter fullscreen mode Exit fullscreen mode

Result:

  • Data stored in MySQL Database: Image description
  • Data stored in DynamoDB: Image description

📋 Note: To keep this blog simple I am using some of the parameters in the example above, in order to go deeper with AWS-SDK for Amazon EventBridge you can visit this link

4. Conclusion

In this article I tried to showcase how powerful the Amazon EventBridge is, and in case you are building distributed architecture it will help you a lot in decoupling your components

For more articles like this and to stay up-to-date, you can connect me on LinkedIn

This article is part of "Messaging with Serverless" series that I've been writing for a while, if you are interested to read other Serverless offerings from AWS, feel free to visit the links below

Top comments (0)