Introduction
This is the Week 1 Day 2 project of the 30-Day DevOps challenge that I am participating in. Learn more about the challenge and its creators, s/o to them, here.
Project Overview
This project creates a cloud based NBA game day alert system leveraging Python, AWS Lambda, Amazon EventBridge, Amazon SNS, and an NBA API. NBA fans can subscribe to this service to receive real-time notifications of game scores via email or text message.
Key Features
- Fetches NBA game scores using SportsDataIO's NBA API.
- Sends score updates to subscribers via email or text message using Amazon SNS.
- Automates sending of notifications using Amazon EventBridge.
- Follows principle of least privilege for IAM roles.
Technologies
- Cloud Provider: AWS
- Core Services: SNS, Lambda, EventBridge
- External API: NBA Game API (SportsData.io)
- Programming Language: Python 3.x
- IAM Security: Least privilege policies
NBA API
(The more I interact with, research, and write about APIs, the better I understand them. Have you heard the notion that you only really know something if you can explain in the simplest of terms? Well, I'm gradually feeling more confident in my ability to explain APIs and the HTTP request-response cycle and I am going to attempt to do so in a forthcoming post that I'll have linked here once its up.)
In this project, we make a request to the NBA API for data about games for the current day. The request looks something like this:
api_url = f"https://api.sportsdata.io/v3/nba/scores/json/GamesByDate/{todays_date}?key={your_api_key}"
try:
response = requests.get(api_url)
response.raise_for_status()
data = response.json()
print (json.dumps(data, indent=4))
except Exception as e:
print (f"An error occurred: {e}")
With the call wrapped in a try-except block, the NBA API responds to our request with either an error message or with the data I requested. The data comes through in a format that is hard to decipher so we decipher it by using methods, e.g. .json()
and json.dumps()
.
The formatted response looks something like this:
[
{
"GameID": 21678,
"Season": 2025,
"SeasonType": 1,
"Status": "Scheduled",
"Day": "2025-02-05T00:00:00",
"DateTime": "2025-02-05T19:00:00",
"AwayTeam": "MIL",
"HomeTeam": "CHA",
"AwayTeamID": 15,
"HomeTeamID": 2,
"StadiumID": 2,
"Channel": "FDSS",
"Attendance": null,
"AwayTeamScore": null,
"HomeTeamScore": null,
...
},
...
]
Note that each game's information is held in a dictionary. So I can extract what I want from that decoded data using the .get()
method. For example, I can extract the home team with a line like:
home_team = game.get("HomeTeam", "Unknown")
This creates a variable home_team
and sets it to the value associated with the key "HomeTeam" and if that key doesn't exist, home_team
is set to "Unknown".
Thanks NBA API!
Event driven architecture
Today I learned... about event driven architecture. This project is an example of event driven architecture as we set up a cron
job schedule in EventBridge that invokes the code we house in Lambda. The code in Lambda makes the API call, transforms the data, and sends it to SNS which then sends out the notifications. The event, the schedule we set in EventBridge, automatically kicks off the rest of the workflow.
EventBridge
EventBridge helps route events from different AWS services and custom applications. In this case, we use EventBridge to define a scheduled rule that triggers our Lambda function at specific intervals. This eliminates the need for manual execution and ensures the workflow runs consistently.
Lambda
Lambda runs the code we write to fetch data from the NBA API, process it, and send it out, in this case to an SNS topic.
SNS
SNS, Simple Notification Service, is a pub-sub service that sends notifications to its subscribers. People can subscribe to a topic and receive notifications by text and/or email.
Project Structure
game-day-notifications/
├── .env. # holds environment variables
├── policies/
│ └── gd_sns_policy.json # json for the sns policy
├── src/
│ ├── game_day_notifs.py # main logic
├── README.md # documentation
└── requirements.txt # dependencies
Set Up Instructions
Follow these steps to create the workflow for this app.
Clone the Repo
git clone https://github.com/LilLoveBytes/game-day-notifications.git
cd game-day-notifications
Create an SNS Topic
- Open the AWS management console.
- Navigate to the SNS service.
- Click Create Topic and select Standard as the topic type
- Name the topic (e.g. GameDay) and note the ARN.
- Click create topic.
Add Subscriptions to the SNS Topic
- After creating the topic, click on the topic name from the list.
- Navigate to the Subscriptions tab and click Create subscription
- Select a Protocol:
- Email: Choose Email and enter a valid email address
- SMS: Choose SMS and enter a valid phone number in international format (e.g. +1-213-555-5555)
- Click Create Subscription.
- Confirm the subscription
- Email: Check the inbox of this account and confirm the subscription by clicking the confirmation link.
- SMS: Subscription will be active after creation, no need to further confirm.
Create the SNS Publish Policy
- Open the IAM service in the AWS Management Console.
- Navigate to Policies -> Create Policy
- Click JSON and paste the JSON policy from the gd_sns_policy.json file in the repo
- Update the value of the "Resource" key to the ARN noted earlier.
- Click Next: Tags (you can skip adding tags).
- Click Next: Review
- Enter a name for the policy
- Review and click Create Policy.
Create an IAM Role for Lambda
- Open the IAM service in the AWS Management Console.
- Click Roles -> Create Role.
- Select AWS Service and choose Lambda.
- Attach the following policies
- SNS Publish Policy (created in the previous step).
- Lambda Basic Execution Role (AWSLambdaBasicExecutionRole) (an AWS managed policy).
- Click Next: Tags (you can skip adding tags).
- Click Next: Review
- Enter a name for the role
- Review and click Create Role.
- Copy and save the ARN of the role for use in the Lambda function.
Deploy the Lambda Function
- Open the AWS Management Console and navigate to the Lambda service.
- Click Create Function.
- Select Author from Scratch.
- Enter a function name
- Choose Python 3.x as the runtime.
- Assign the IAM role created earlier to the function.
- Under the Function Code section:
- Copy the content of the src/game_day_notifs.py file from the repository.
- Paste it into the inline code editor.
- Under the Environment Variables section, add the following:
- NBA_API_KEY: your NBA API key.
- SNS_TOPIC_ARN: the ARN of the SNS topic created earlier.
- Click Create Function
Set up Automation with EventBridge
- Navigate to the EventBridge service in the AWS Management Console.
- Go to Rules -> Create Rule.
- Select Rule Type: Schedule.
- Select Continue in EventBridge Scheduler.
- Name your schedule and select Recurring Schedule
- Set the cron schedule for when you want updates
- Under Targets, select the Lambda function you just created
- Select Create a new role and hit next.
Test the System
- Open the Lambda function in the AWS Management Console.
- Create a test event to simulate execution.
- Run the function and check CloudWatch Logs for errors.
- Verify that notifications are sent to the subscribed users.
Conclusions
Today I learned...
- what event driven architecture is
- what AWS Lambda, SNS, and EventBridge are.
- how to design a notification system with SNS and Lambda.
- how to use AWS services like EventBridge and Lambda to build automated workflows.
- how to secure AWS services with least privilege IAM policies.
- how to automate workflows using EventBridge.
- how to format a cron expression to define scheduled execution times.
- how to integrate an external API into a cloud-based workflow.
Future Enhancements
I am writing this after reaching the initial goal of this challenge: to create a simple notification system that fetches NBA game data from an API, formats the data, and sends it to subscribers.
If I have the capacity I will enhance this app by creating a webpage/ user interface for user interaction and data visualization. I could also add logic to include NFL game data notifications.
And if you've made it this far, thanks for reading! Feel free to checkout my Github. I'd love to connect on Linkedin.
Top comments (0)