In this section you will create the files for the static website.
Start by creating a subfolder; make sure to create it under the folder in which you created the serverless project (for example, AwsServerlessDynamoDbLambdaS3).
Then, in the website folder create index.html
and modify it as follows:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>IoTPage</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="container">
<h1>Temperature Service</h1>
<button id="writeTemperatures">Write Temperatures</button>
<button id="getAverageTemperature">Get Average Temperature</button>
<div id="temperatureDisplay" class="display-box">Temperature will be displayed here</div>
</div>
<script src="index.js"></script>
</body>
</html>
This HTML code defines a simple web page titled IoTPage for interacting with the AWS Lambda Functions. The page includes a link to a stylesheet styles.css
for styling the page, two buttons with IDs writeTemperatures, and getAverageTemperature to allow users to interact with the temperature service. Also, the HTML includes a div with the ID temperatureDisplay
that serves as a placeholder to display the temperature results. Finally, the code includes an external JavaScript file, index.js
, at the end of the body to add interactive functionality to the page.
In the same folder as index.html
, create a styles.css
file, and add the content below:
body {
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #f0f0f0;
margin: 0;
}
.container {
text-align: center;
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
button {
background-color: #4CAF50;
color: white;
border: none;
padding: 10px 20px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
margin: 10px 0;
cursor: pointer;
border-radius: 5px;
}
button:hover {
background-color: #45a049;
}
.display-box {
margin-top: 20px;
padding: 15px;
border: 1px solid #ddd;
border-radius: 4px;
background-color: #fafafa;
}
This file declares the same styles as used in the Learning Path that shows you how to Use Amazon S3 for your IoT applications running Windows on Arm .
Finally, under the website folder, add the index.js
file, and add the content shown below:
const writeTemperaturesButton = document.getElementById('writeTemperatures');
const getAverageTemperatureButton = document.getElementById('getAverageTemperature');
// Placeholders for endpoints
const writeTemperaturesUrl = 'WRITE_TEMPERATURES_URL';
const getAverageTemperatureUrl = 'GET_AVERAGE_TEMPERATURE_URL';
writeTemperaturesButton.addEventListener('click', async () => {
try {
const response = await fetch(writeTemperaturesUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
});
const data = await response.json();
alert(data.message);
} catch (error) {
console.error('Error writing temperatures:', error);
alert('Failed to write temperatures.');
}
});
getAverageTemperatureButton.addEventListener('click', async () => {
try {
const response = await fetch(getAverageTemperatureUrl);
const data = await response.json();
const temperature = data.averageTemperature.toFixed(2);
document.getElementById('temperatureDisplay').innerText = `Average Temperature: ${temperature} °C`;
} catch (error) {
console.error('Error fetching average temperature:', error);
alert('Failed to get average temperature.');
}
});
This JavaScript code adds interactivity to a web page by enabling two buttons to trigger HTTP requests to specific API endpoints for managing temperature data. The code selects the two buttons from the HTML by their IDs: writeTemperaturesButton
and getAverageTemperatureButton
.
Two API endpoints, writeTemperaturesUrl
and getAverageTemperatureUrl
, are defined as placeholders for the actual API URLs that the buttons call. These placeholders are replaced by the values that the Serverless Framework outputs after the resource deployment.
The code then defines event listeners for the buttons:
writeTemperaturesButton
click event. When clicked, it sends a POST request to the writeTemperaturesUrl endpoint to write temperature data. If successful, it displays a message with the response data. If there’s an error, it logs the error and shows an alert.getAverageTemperatureButton
click event. When clicked, it sends a GET request to the getAverageTemperatureUrl endpoint to retrieve the average temperature. If successful, it displays the average temperature in a specific div on the web page. If there’s an error, it logs the error and shows an alert.This code interacts with a backend service composed of AWS Lambda functions to write new temperature data and fetch the average temperature, enhancing the functionality of the web page.
You will now add the JavaScript code that reads the outputs of the Serverless Framework, and use it to replace the writeTemperaturesUrl
and getAverageTemperatureUrl
placeholders in the index.js
.
To implement this functionality, create a new prepare.js
file, and save it in the same folder as serverless.yml
. Then, modify prepare.js
as follows:
import fs from 'fs';
import path from 'path';
import { execSync } from 'child_process';
// Fetch Serverless outputs using the 'serverless info --verbose' command
const output = execSync('serverless info --verbose', { encoding: 'utf8' });
// Extract the required endpoints from the output
const writeTemperaturesRegex = /WriteTemperaturesEndpoint:\s*(https:\/\/[^\s]+)/;
const getAverageTemperatureRegex = /GetAverageTemperatureEndpoint:\s*(https:\/\/[^\s]+)/;
const writeTemperaturesMatch = output.match(writeTemperaturesRegex);
const getAverageTemperatureMatch = output.match(getAverageTemperatureRegex);
const writeTemperaturesEndpoint = writeTemperaturesMatch ? writeTemperaturesMatch[1] : 'https://your-api-id.execute-api.us-east-1.amazonaws.com/dev/write-temperatures';
const getAverageTemperatureEndpoint = getAverageTemperatureMatch ? getAverageTemperatureMatch[1] : 'https://your-api-id.execute-api.us-east-1.amazonaws.com/dev/get-average-temperature';
// Path to the index.html file
const indexJsFileName = 'index.js';
const filePath = path.join('website', indexJsFileName);
// Read the HTML file and replace the placeholders with the actual endpoint URLs
fs.readFile(filePath, 'utf8', (err, data) => {
if (err) {
console.error(`Error reading ${indexJsFileName} file:`, err);
return;
}
// Replace placeholders with actual endpoints
const result = data
.replace('WRITE_TEMPERATURES_URL', writeTemperaturesEndpoint)
.replace('GET_AVERAGE_TEMPERATURE_URL', getAverageTemperatureEndpoint);
// Write the updated content back to the file
fs.writeFile(filePath, result, 'utf8', (err) => {
if (err) {
console.error(`Error writing ${indexJsFileName} file:`, err);
return;
}
console.log(`${indexJsFileName} updated with dynamic endpoints successfully.`);
});
});
This script automates the process of dynamically inserting the correct API endpoints into the index.js
file, which is essential for ensuring that the web application communicates correctly with the deployed backend services.
The code uses the following JavaScript modules:
fs
for file system operations.path
for handling file paths.execSync
from child_process
to execute shell commands synchronously.The code runs the serverless info --verbose
command to retrieve deployment details (for example, API endpoints) and stores the output in the output variable. Then, using regular expressions, it extracts the URLs for the writeTemperatures
and getAverageTemperature
API endpoints from the Serverless output. If the endpoints are not found, it assigns default placeholder URLs.
Subsequently, the code sets the path to index.js
by joining the directory (website) with the file name index.js
. Once this is done, the code reads the index.js
file content and replaces the placeholder strings (WRITE_TEMPERATURES_URL and GET_AVERAGE_TEMPERATURE_URL) with the actual API endpoint URLs.
Finally, the code writes the updated content back to index.js
and logs a success message if completed. If any errors occur during reading or writing, it logs the errors to the console.
Finally, add the package.json
file. Save it next to serverless.yml
, and modify it as follows:
{
"name": "aws-serverless-dynamodb-lambda-s3",
"version": "1.0.0",
"type": "module",
"scripts": {
"prepare": "node prepare.js"
},
"devDependencies": {
"serverless-plugin-scripts": "^1.0.0",
"serverless-s3-sync": "^3.0.0"
}
}
This is the package file for a Node.js
project that uses the Serverless Framework to deploy AWS resources, including DynamoDB, Lambda, and S3. The file specifies the name of the project (aws-serverless-dynamodb-lambda-s3), its version, and sets the type to module, which means the project uses ES module syntax (for example, import and export).
The file then defines a script named prepare that runs prepare.js
using Node.js to set up or configure resources before deployment - this script is used to dynamically update index.js.
Next, it lists the development dependencies required for the project: