Event Driven Web Application
          
          
Before you Begin
Capture the following parameters from the launched CloudFormation template as you will use it in the demo.
- RedshiftDataApiWebSocketEndpoint
- RedshiftDataApiRestApiEndpoint
Challenge
In 2015, the company has accumlated New York Taxi data (public) and recently, a separate business department wants to gain additional insights. The data analyst Miguel has created analytical queries to help with the analysis. However, business is unsure who would need to perform analysis at what time. Business would also like to avoid onboarding every individual to the AWS console whenever that user wants to query NYC Taxi data from Redshift. Miguel reached out to Marie to see if she can build an application to meet this criteria.
To solve this challenge, Marie decides to build an Event Driven Web Application by leveraging API Gateway Websockets and REST API and Redshift Data API. If Marie does not use Websockets and only API Gateway REST implementation, optimal performance will not be reached to a number of reasons:
- Unnecessary chattiness and cost due to polling for result sets
- Delayed data arrival due to polling schedule
- User request deadlocks can hamper application performance
- HTTP default timeouts across browsers may result in inconsistent client experience
Here is the architecture of the workflow:

- The user will be given a website where he/she can query NYC Taxi data by month.
- The web page will hit a websocket URL endpoint generated by API Gateway.
- Once the API Gateway receives that request, it will direct the traffic to a Lambda Proxy, which will trigger the OnConnectLambda function.
- The Lambda function will read the user parameters and insert it into a SQL query (stored in S3 ) that Miguel developed.
- The OnConnectLambda function will use Redshift Data API to query the data - asynchronously.
- After the query has been submitted, the Lambda function will save the ConnectionId and StatementId (query Id) to a DynamoDB table
- Once the Redshift query is complete, an event notification via EventBridge will trigger SendMessageLambda function
- The SendMessageLambda function will retrieve the ConnectionId from DynamoDB based on the StatementId and notify the frontend
- Once the frontend has been notified that the query is complete, it will send a GetREST ajax call to API Gateway
- API Gatway will trigger GetResultsLambda function to retrieve the results from Redshift
- API Gatway will transfer the data back to the frontend (the user’s webpage).
- After the results appear on the user’s webpage, API Gateway will trigger a OnDisconnectLambda function to clean up the DynamoDB table.
Marie will do the following:
Create Request OnConnect Lambda Function
| Say | Do | Show | | Marie goes to the AWS Console to create the OnConnectLambda function with a NodeJS environment | The CloudFormation template has created a Lambda Function containing JavaScript code that has all the functions required to retrieve SSM parameters, run the SQL query that you previously uploaded, connect to Redshift via Data API, and insert connection details into DynamoDB. 
Click here to navigate to Lambda Functions on the AWS Console
Locate the function named XXXX-OnConnectFunction-XXXand open the JavaScript file calledindex.js | 
 | 
| Within the Lambda Function, Marie codes out the first 3 functions: 
getSSMParameter- retrieves the websocket endpoint URLrunSQLScriptFromS3- retrieves Miguel’s sql script that’s stored in S3executeRedshiftSql- uses Redshift Data API to query from the Redshift cluster | Scroll down to the executeRedshiftSqlfunction. Inspect the code and note how the query SQL script is retrieved fromrunSQLScriptFromS3and executed on Redshift Data API with the methodexecuteStatement.After calling the executeStatementfunction, a query Id (statementId) is then generated and used to keep track of the query status and response. You will see how it’s being utilized in subsequent steps. The ‘RedshiftData’ client in the aws-sdk library (line 49) is initialized to use Redshift Data API. |     | 
| Marie also codes out the logic to save the websocket connectionId to a DynamoDB table: putConnectionRecordDdb. | Scroll down to the putConnectionRecordDdbfunction. Once the connectionId,topicName, andstatementIdhas been retrieved and generated, they’re stored in a DynamoDB table. The topicNameis a dynamic parameter you can set in the frontend. If you were to create additional reports, you can leveragetopicNamefor the frontend to identify different reports. Later on, the SendMessageLambda function will use the data to send back the query results to the application frontend. |   | 
|  |  |  | 
Create Notification SendMessage Lambda Function
| Say | Do | Show | | Marie heads back to the AWS Lambda console landing page and creates another Lambda function called SendMessage. The SendMessageLambda function will retrieve the ConnectionId from the DynamoDB and notify the frontend that the query is complete through the API Gateway. | The CloudFormation template has created a Lambda Function containing JavaScript code that has all the functions required to retrieve data from a query ran on Redshift, get SSM parameters - in this case, the websocket endpoint, and notify the websocket endpoint that the query is complete. 
Click here to navigate to Lambda Functions on the AWS Console
Locate the function named XXXX-SendMessageFunction-XXXand open the JavaScript file calledindex.js | 
 | 
| Mari codes out the following functions: 
getConnectionIdTopicName- gets the connectionId and topicName from the DynamoDB table that was previously saved from theOnConnectLambda function.getSSMParameter- retrieves the websocket URL endpoint. Marie will use the websocket URL endpoint (along with the connectionId) to tell API Gateway the route to send back the results from the SQL query | Scroll down to the getSSMParameterfunction and inspect how the code is retrieving the websocket endpoint from SSM. Scroll down to the getConnectionIdTopicNamefunction and inspect how the code is retrieving theconnectionIdandtopicNamebased on the statementId. The statementIdis generated by Redshift Data API when you executed the query statement in OnConnect Lambda function. TheconnectionIdis associated with the websocket endpoint. |   
 | 
| Marie programs the final function postMessage, which will take the connectionId, statementId, topicName, and websocket URL endpoint and send it back to API Gatway to deliver it to the frontend. | After the connectionIdandtopicNameis retrieved from DynamoDB and the results are retrieved from Redshift Data API, we send aPOSTto the websocket endpoint via API Gateway. The application’s frontend will pick this up and perform a GET (via REST API) to retrieve the query result | 
 | 
Create Response GetResults Lambda Function
| Say | Do | Show | | Marie heads back to the AWS Lambda console landing page and creates another Lambda function called GetResults. The GetResultsLambda function will retrieve the results from Redshift. Based on the statementId, theGetResultsLambda function will send back the data results to API Gateway. | The CloudFormation template has created a Lambda Function containing JavaScript code that will get the query results from Redshift . 
Click here to navigate to Lambda Functions on the AWS Console
Locate the function named XXXX-GetResults-XXXand open the JavaScript file calledindex.js |   | 
| Marie programs the getResultsfunction, which will retrieve the results from the SQL query and format it appropriately. After formatting it into rows and columns in a JSON structure, the frontend will be able to efficiently display it. | Scroll down to the getResultsfunction and inspect how the code is retrieving the query response from Redshift Data API.Notice how the query Id (statementId) is used to get the data through Redshift Data API command:getStatementResult. | 
 | 
Connect Lambda Functions with Redshift and EventBridge
| Say | Do | Show | | Marie wants Redshift to automtically send an event after a query is complete. She learns about the withEvent=trueparameter when calling the Redshift Data API. She realizes the event is sent to EventBridge. | As mentioned before, when you activate the OnConnectLambda function, it will run the query SQL script using Redshift Data API - viaexecuteStatement(...). executeStatement(...)has a boolean parameter calledwithEvent. OncewithEventis set totrue, the Redshift Data API will trigger an event to EventBridge after the query is complete.
 | 
 | 
| Marie wants to trigger the SendMessageLambda function whenever a query is complete. She heads over to EventBridge to create aRule. | The CloudFormation template has generated an EventBridge rule that connects the OnConnectLambda function with theSendMessageLambda function.Go to the EventBridge console and click on the EventBridge rule with X-EventBridgeRedshiftEventRule-Xand inspect the event trigger pattern and the target. | 
 | 
| In the EventBridge Rule, she sets the OnConnectLambda function as the source of the event and theSendMessageLambda function as the target. Now the statementId (generated by the SQL query) can be retrieved in theSendMessageLambda function. | Note that the source of the event rule is from the OnConnectLambda function and the target is theSendMessageLambda function. This logic will allow SendMessageLambda function to be triggered once the query is complete. The event will contain thestatementId. |   | 
Create Delete OnDisconnect Lambda Function
| Say | Do | Show | | Marie creates the third Lambda function, which will clean up the DynamoDB table. | The CloudFormation template has created a Lambda Function containing JavaScript code that will delete the connectionIdfrom the DynamoDB. 
Click here to navigate to Lambda Functions on the AWS Console
Locate the function named XXXX-OnDisconnectFunction-XXXand open the JavaScript file calledindex.js |   | 
| Marie programs the delete entry from DynamoDB table logic. | Inspect the code to see how the connectionId,topicNameandstatementIdis deleted from the DynamoDB table. | 
 | 
Create Websockets and REST API with API Gateway and integrate with Lambda Functions
| Say | Do | Show | | Marie needs to create a Websocket API and REST API in API Gateway. | The CloudFormation template has both an API Gateway Websocket and REST API feature. The websocket and REST API contains an API endpoint that you can input into your frontend application. For websockets, API Gateway will establish a bidirectional communication between the frontend and the OnConnectLambda function. Let’s first dive into the websocket portion. Go to the API Gateway Console and click on the ApplicationWebSocket |   | 
| Marie creates an API called ApplicationWebsocket and creates two routes: $connectand$disconnect | Under the API Category, click on Routes. |   | 
| Under each route, she creates a Lambda proxy and connects it to the appropriate Lambda. $connect- OnConnect Lambda function$disconnect- OnDisconnect Lambda function
 | Feel free to browse through the two routes that were generated by the CloudFormation template. Click on $connectand inspect the logic. On the far right, you will notice the route request is sent to a Lambda proxy and routed to theOnConnectLambda function. The $disconnectroute has a similar logic to it as well. Please take the time to go through it. |   | 
| Marie then creates another API of type REST API. Under resources she creates a method of type GETand integrates it with theGetResultsLambda function. | Under resources click on Create Methodand in the dropdown selectGET. Choose Lambda Function as the destination and check the box that says Lambda Proxy. Afterwards, type in the GetResultsLambda function that you want to integrate it with. |   | 
Create Frontend and connect to API Gateway
| Say | Do | Show | | Marie creates the frontend webpage. | Download the webpage contents from here. Open the file in your browser and you should be able to view the HTML file as displayed on the right.
 |   | 
| In the HMTL file that she developed, Marie heads over back to the API Gateway and copies the production websocket URL endpoint and paste it in the HTML file. | Open the HTML file in your favourite code editor. Replace the wsEndpointvariable with the websocket URL generated from your API Gateway console or from CloudFormation output:RedshiftDataApiWebSocketEndpoint. |   
 | 
| In the HMTL file that she developed, Marie heads over back to the API Gateway and copies the production REST URL endpoint and paste it in the HTML file. | Replace the restEndpointvariable with the REST URL generated from your API Gateway console or from CloudFormation output:RedshiftDataApiRestApiEndpoint. |   
 | 
| Say | Do | Show | | Marie wants to test out if the event driven web application. She queries June 2015 NYC Taxi Data. | Open/Refresh the modified HTML file in your browser that contains the websocket URL Select a date range within 2015 |   
 | 
| She programmed the webpage to automatically update with results without having to refresh the page. | Click Submitand aFetching Results from Server...message should appear DO NOT REFRESH THE HTML PAGE |   | 
| During the query progress, she checks whether the connectId is inserted into the DynamoDB table. | As the results are being fetched, remember that the OnConnectLambda function is inserting theconnectionId,topicName, andstatementIdto a DynamoDB table? If you go back to the DynamoDB console under items –> Table: client_connections, you will be able to see the key-value pair present. You will only be able to view this during the ETL process because the onDeleteLambda function removes the data after the results have been fetched. |   | 
| Horray! Marie has just built an event driven web application! | The results are now available for analysis. Feel free to continue developing your Event Driven Web Application!
 | 
 |