Using AWS CDK to trigger an SMS notification when a Lambda function identifies updates in a URL

I am working on a CDK application that utilizes a Lambda function to monitor changes in the content of a website. My goal is to trigger an SMS notification to a mobile number whenever a change is detected.

Within my AWS CDK project, I have set up a stack that includes the creation of the Lambda function and SNS.

File: lib/lambda_query_website_aws_cdk-stack.ts

import * as cdk from '@aws-cdk/core';
import events = require('@aws-cdk/aws-events');
import targets = require('@aws-cdk/aws-events-targets');
import lambda = require('@aws-cdk/aws-lambda');
import * as sns from '@aws-cdk/aws-sns';
import * as subscriptions from '@aws-cdk/aws-sns-subscriptions';

import fs = require('fs')

export class LambdaQueryWebsiteAwsCdkStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const lambdaFn = new lambda.Function(this, 'Singleton', {
      code: new lambda.InlineCode(fs.readFileSync('lambda-handler.py', { encoding: 'utf-8' })),
      handler: 'index.main',
      timeout: cdk.Duration.seconds(300),
      runtime: lambda.Runtime.PYTHON_3_6,
      environment: {
        'PREV_RESPONSE': ''
      }

    });

    // Runs every 30 minutes from 6:00 to 23:00
    // See https://docs.aws.amazon.com/lambda/latest/dg/tutorial-scheduled-events-schedule-expressions.html
    const rule = new events.Rule(this, 'Rule', {
      schedule: events.Schedule.expression('cron(0/30 6-23 * * ? *)')
    });
    
    rule.addTarget(new targets.LambdaFunction(lambdaFn));

    // Create an SNS Topic.
    // The producer or publisher is the lambda function ??
    //The subscriber or consumer is the sms phone number +15551231234
    const myTopic = new sns.Topic(this, 'MyTopic');
    myTopic.addSubscription(new subscriptions.SmsSubscription('+15551231234'));

  }
}

Below is the code for the lambda function:

File: lambda-handler.py

import os
import urllib.request

url= "https://mywebsite.com"

def main(event, context):
    print("I'm running!")
    response = urllib.request.urlopen(url)
    response_text = response.read()
    html = response_text.decode('utf-8')

    if os.getenv('PREV_RESPONSE',default="HTML_BODY") != html:
        print("There was a change on the web site")
        os.environ['PREV_RESPONSE'] = HTML
        # TODO:
        # Send the SMS notifying about the change

My question is, how can I inform the SNS service to send out the message when needed?

Best regards,

Answer №1

Consider implementing the following solution:

export class LambdaQueryWebsiteAwsCdkStack extends cdk.Stack {
    constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
      super(scope, id, props);
  
      const myTopic = new sns.Topic(this, 'MyTopic');
      myTopic.addSubscription(new subscriptions.SmsSubscription('+15551231234'));

      const lambdaFn = new lambda.Function(this, 'Singleton', {
        code: new lambda.InlineCode(fs.readFileSync('lambda-handler.py', { encoding: 'utf-8' })),
        handler: 'index.main',
        timeout: cdk.Duration.seconds(300),
        runtime: lambda.Runtime.PYTHON_3_6,
        environment: {
          'PREV_RESPONSE': '',
          'SNS_TOPIC_ARN': myTopic.topicArn  // Include topic ARN as environment variable
        }
      });
      
      myTopic.grantPublish(lambdaFn.role)  // Grant lambda function permission to publish to topic
  
      // Runs every 30 minutes from 6:00 to 23:00
      // See https://docs.aws.amazon.com/lambda/latest/dg/tutorial-scheduled-events-schedule-expressions.html
      const rule = new events.Rule(this, 'Rule', {
        schedule: events.Schedule.expression('cron(0/30 6-23 * * ? *)')
      });

      rule.addTarget(new targets.LambdaFunction(lambdaFn));
    }
  }

Additionally, in your python implementation:

import os
import boto3
import urllib.request

url= "https://mywebsite.com"
client = boto3.client("sns")

SNS_TOPIC_ARN = os.getenv("SNS_TOPIC_ARN")

def main(event, context):
    print("I'm running!")
    response = urllib.request.urlopen(url)
    response_text = response.read()
    html = response_text.decode('utf-8')

    if os.getenv('PREV_RESPONSE',default="HTML_BODY") != html:
        os.environ['PREV_RESPONSE'] = html

        response = client.publish(
            TopicArn=SNS_TOPIC_ARN,
            Message='There was a change on the web site',
            Subject='Some change!'
        )

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What steps should I take to securely store my WordPress form submission data in a JSON file?

I recently set up a form on my AWS Wordpress site using NinjaForms and I'm looking for a way to save the data collected into a JSON file. The form functions correctly, but I need a plugin that can assist with this task. If anyone could point me in th ...

TypeScript abstract class generics: `Class<?>` type

When working with TypeScript, I often utilize a Java-like type called Class: interface Class<T = void> { new(...args: any[]): T; } Unfortunately, this type doesn't seem to be compatible with abstract classes: abstract class Bar {} class ...

Using TypeScript import statements instead of the <reference path...> in an ASP.NET Core web application: A step-by-step guide

Understanding the Setup I initially had a functional TypeScript Hello World in my ASP.NET Core Web application. To compile TypeScript, I used the NuGet package "Microsoft.TypeScript.MSBuild" Version="4.4.2" along with a tsconfig.json f ...

Ways to delete a class in typescript

There's a menu on my website with li tags containing an a element for navigation. Everything is working fine, but I'm facing an issue where I need to remove all elements with the class seleccionado and only add it to the clicked li. I tried using ...

Share your base64 encoded image on imgur platform

I am encountering an issue while attempting to upload a base64 encoded image from https://pastebin.com/1ereVVqh to imgur. The error message I keep receiving is as follows: HttpErrorResponse {headers: HttpHeaders, status: 400, statusText: "OK", url: "https ...

"Is there a way to extract a value from a JSON object using

I have an object with the following key-value pairs: { 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier': '918312asdasc812', 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name': 'Login1&a ...

A Typescript type that verifies whether a provided key, when used in an object, resolves to an array

I have a theoretical question regarding creating an input type that checks if a specific enum key, when passed as a key to an object, resolves to an array. Allow me to illustrate this with an example: enum FormKeys { x = "x", y = "y&q ...

Unraveling the Mystery of the Undefined Parameter in Angular Observables

I am facing an issue with the Observable parameter in my code. I have a consultService that contains the functions consult() and response as a parameter. The function sendConsultRequest() is called before using the response parameter. Although the sendCons ...

Is it true that "Conditional types" are not compatible with actual functions?

Checking out https://www.typescriptlang.org/docs/handbook/2/conditional-types.html I'm curious as to why this code is not functioning properly? interface IdLabel { id: number } interface NameLabel { name: string } type NameOrId<T extends num ...

The supabase signup function keeps showing me the message "Anonymous sign-ins are disabled." Can anyone help me understand why this is happening?

I'm currently in the process of setting up authentication in Next.js with supabase, but encountering an issue when attempting to execute the signUp function. The error message I'm seeing is: Anonymous sign-ins are disabled Below is the snippet o ...

Can you provide details on the capabilities of Appium for webviews on Android devices?

I attempted to utilize the following capabilities { maxInstances: 1, browserName: '', appiumVersion: '1.18.2', platformName: 'android', platformVersion: '10.0', deviceName: 'd ...

What steps should I take to resolve the ChunkLoadError related to signalr?

Recently, I encountered an issue while running my nx site locally. It seems that any federated app using signalR is now throwing a ChunkLoadError. I attempted various solutions such as changing the version of signalR, reloading the page, clearing cache, a ...

Using TypeScript to define parameter types to update an object's key and value

I need assistance in creating a function that can update an object's value based on the provided key and new value while ensuring type safety. type GroceryStore = { isOpen: boolean; offers: string[]; name: string; }; const myGroceryStore: ...

Ionic storage is unable to assign a number as a string

My goal is to store all numbers retrieved from the function getWarrentsNumber() in ionic storage, but I encountered an error. Error: The argument of type "number" cannot be assigned to type 'string'. this.storage.set(this.NumberOfAssignedWarren ...

Creating a new component when a click event occurs in React

Currently diving into the world of React while working on a project that involves mapbox-gl. I'm facing an issue where I can successfully log the coordinates and description to the console upon hover, but I can't seem to get the popup to display ...

The error thrown is: "TypeError: device.devices.map is not a valid function

I encountered an error after adding products to the page and I'm having trouble identifying the cause. const {device} = useContext(Context) 91 | </div> > 92 | <div className="inner-display-collection"> | ^ ...

unable to find user in passport js deserialize function due to undefined variable

I've encountered an issue while working on the backend for a web application, specifically with passport. Currently, I can successfully register a user and log them in, but I'm facing a problem where I cannot log in twice in a row. Each time dese ...

Encountered an issue with locating the module 'webpack-cli/bin/config-yargs' while attempting to run webpack-dev

Encountering an error while trying to start the webpack dev server with the command provided below. Despite suggestions that it could be due to outdated webpack versions, I am confident that all components are up to date: [email protected] [email ...

"Encountering an 'Unassignable' error while attempting to generate a reusable Button component, despite supplying a custom enum for type

I'm currently in the process of developing a customized Button element within a React and TypeScript project. However, when I define the Props type, I encounter the following error: Type 'DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonEle ...

Avoiding the use of destructuring for undefined values in JavaScript can be achieved by implementing

Upon receiving the response registryReportSettings from the server: this.getRegistrySettings(registry.Id).subscribe((registryReportSettings: { extended: ReportPropertiesRequest }) => { const { objectProperties, reportProperties, textProperties } = reg ...