Master AWS with a Weather Alert Project

šŸ’» GitHub Repo: Check out the full source code here

Let’s Get Started

Let’s build something meaningful and scalable together—a production-grade serverless weather alert system on AWS. This isn’t just a ā€œfollow the stepsā€ tutorial—it’s us walking through smart decisions at every layer of this cloud-native solution. From ingestion to alerts, transformations to dashboards, we’ll explore every architectural building block in a way that’s fun and real.

This system is built using AWS best practices, keeping in mind the Well-Architected Framework, and it’s all fully reproducible using infrastructure as code.

šŸŒ What Are We Building?

We’re building a system where visitors can subscribe to get weather updates via email—daily forecasts and instant alerts for any severe conditions. Instead of asking users to manually select their country, we’ll use geolocation via ip-api.com based on their IP during signup. Our emails will be easy to unsubscribe from, thanks to secure tokenized links.

šŸ’Œ Let’s Handle Subscriptions

Our journey begins with a WordPress-embedded form. When someone subscribes, their details are sent to an API Gateway endpoint, which then triggers a Lambda function. This function extracts the email and automatically determines the user’s country using ip-api.com. All this info is then saved securely in a DynamoDB table.

🧩 CDK Snippet:

const subscriptionLambda = new lambda.Function(this, 'SubscriptionLambda', {
  runtime: lambda.Runtime.PYTHON_3_11,
  handler: 'subscription.handler',
  code: lambda.Code.fromAsset(path.join(__dirname, '../lambda/subscription')),
  environment: {
    DDB_TABLE_NAME: table.tableName,
    SENDER_EMAIL: senderEmail,
  },
});

We chose DynamoDB over RDS and Aurora Serverless because:

  • It’s serverless and auto-scales
  • It has built-in high availability
  • It’s great for key-based lookups like checking if a user is subscribed

šŸ•’ Fetching Weather Data

The naive choice might be to use Kinesis for streaming—but we’re just polling a single public API (Open-Meteo) every 5 minutes. Kinesis would’ve added unnecessary complexity and cost.

Instead, we scheduled a Lambda using EventBridge to hit the API, parse the data, and store it as a raw JSON file in an S3 bucket.

🧩 CDK Snippet:

new events.Rule(this, 'WeatherFetchRule', {
  schedule: events.Schedule.rate(Duration.minutes(5)),
  targets: [new targets.LambdaFunction(weatherFetcherLambda)],
});

🧹 Processing Data with Glue

Now that we have raw JSON in S3, we transform it using AWS Glue. Our hourly Glue job:

  • Reads raw JSON
  • Converts it to partitioned Parquet
  • Writes output to a processed S3 bucket

🧩 CDK Snippet:

const glueJob = new glue.CfnJob(this, 'WeatherGlueJob', {
  name: 'weather-transform-job',
  role: glueJobRole.roleArn,
  command: {
    name: 'glueetl',
    pythonVersion: '3',
    scriptLocation: glueScriptAsset.s3ObjectUrl,
  },
  defaultArguments: {
    '--enable-glue-datacatalog': 'true',
    '--job-bookmark-option': 'job-bookmark-enable',
    '--TempDir': `s3://${glueTempBucket.bucketName}/temp/`,
  },
  glueVersion: '4.0',
  maxRetries: 1,
  timeout: 10,
});

šŸ” Querying with Athena

Athena lets us query S3 like it’s a database. With Parquet files and partitioned data, Athena becomes incredibly efficient. The Glue job creates a schema in Glue Catalog that Athena uses.

🧩 CDK Snippet:

new glue.CfnDatabase(this, 'AthenaDatabase', {
  catalogId: this.account,
  databaseInput: { name: 'weather_data' },
});

šŸ“Š Visualizing with QuickSight

For dashboards, we connected Amazon QuickSight directly to Athena to display insights on:

  • Temperature
  • Precipitation
  • Alerts

We configured QuickSight via console since embedding requires domain validation and dashboard sharing configuration.

šŸ“¢ Let’s Send Some Alerts

We created two Lambda functions:

  • Daily digest
  • Severe weather alert

Each Lambda uses SES to send templated emails with unsubscribe links.

🧩 CDK Snippet:

const dailyAlertLambda = new lambda.Function(this, 'DailyAlertLambda', {
  runtime: lambda.Runtime.PYTHON_3_11,
  handler: 'daily.handler',
  code: lambda.Code.fromAsset(path.join(__dirname, '../lambda/daily-alert')),
  environment: {
    SENDER_EMAIL: senderEmail,
    DDB_TABLE_NAME: table.tableName,
  },
});

šŸ” Security & IAM

  • IAM Roles for Lambda & Glue
  • VPC endpoints for S3
  • SES verification via CDK

🧩 CDK Snippet:

new ses.EmailIdentity(this, 'EmailIdentity', {
  identity: ses.Identity.email(senderEmail),
});

šŸ—ļø Infrastructure with CDK + CI/CD

Everything is defined in CDK and deployed via GitHub Actions.

🧩 GitHub Actions Sample:

- name: Deploy to AWS
  run: |
    npm ci
    npm run build
    npx cdk deploy --require-approval never

šŸ“ˆ Monitoring & Logging

We used CloudWatch for logging and metrics, with Lambda and Glue emitting events for errors or retries.

āœ… Wrapping It Up

With CDK and the AWS ecosystem, we built a fully serverless system together—from data ingestion to user communication. Clone the full code and start building your version of this:

šŸ”— GitHub Repo

Happy coding! ā˜ļø

Leave a comment