Monitoring platform for keeping systems up and running at all times.
Full stack visibility across the entire stack.
Detect and resolve any incident in record time.
Conform to industry best practices.
Creating a website on serverless is easy, so easy in fact that you can launch a site in under 15 minutes. I won’t bore you with the details but I will however share a link for those that want to start small and move up slowly.
Read part 1 of creating your first serverless website.
I was conflicted trying to figure out what is the one thing that every website has that would work great on serverless and after careful consideration, I realized that contact forms are found on about 99% of the websites I’ve visited in the past years.
Before serverless, you’d have to use PHP to send emails, at least that was the most popular way of creating a form that sends a message. The code that sends out the form looks something like this:
<?php $to = 'nobody@example.com'; $subject = 'the subject'; $message = 'hello'; $headers = 'From: webmaster@example.com' . "\r\n" . 'Reply-To: webmaster@example.com' . "\r\n" . 'X-Mailer: PHP/' . phpversion(); mail($to, $subject, $message, $headers); ?>
It seems straightforward, right? On paper it does, but with the PHP mail() method you’ll inevitably run into problems so you’ll be stuck debugging and looking at logs for an uncomfortably long time. Even after you got it to work the first time, there’s a number of factors that are almost always out of your control that will cause your form to not work, things like ports closing or changing, the host might limit or disable the email system, etc.
Serverless solves these issues with ports and avoids any hosting issues by having everything work from the “almighty” cloud.
I’ll assume you already have node installed. Let’s open your terminal and install a simple boilerplate template: serverless create –template aws-nodejs
Next up we get all the packages we need to be installed. First, we generate our package.json with npm init -y and then we install our dependencies with npm i -s body-parser cors express serverless-http aws sdk
Once that completes you’ll have to load your project in an editor and open your handler.js file and invoke the SES – Simple Email Service from AWS. Invoking SES is simple enough and looks something like this: ses.sendEmail(params,function(err,data){}). Check out their documentation to learn more.
ses.sendEmail(params,function(err,data){})
What we’ll need to do is sign up for AWS SES and you do that by going to AWS Console, click on SES (you can use the search bar to search for SES), go to the left sidebar and click on the email address. Add your email and verify it. It’s a two-minute process.
Now let’s gets back to coding the contact form. In your project folder create a new folder called “form”. In that folder, we’ll create our form assets. Create a file called script.js and style.css. We’ll go over each of them individually.
Our script.js looks like this:
let name = document.querySelector("#name"); let email = document.querySelector("#email"); let message = document.querySelector("#message"); let error = document.querySelector(".error"); let btn = document.querySelector("button"); let success = document.querySelector(".success"); btn.addEventListener("click", submit); function submit(e) { e.preventDefault(); var xhr = new XMLHttpRequest(); xhr.open("POST", "remeberThisEndpoint", true); xhr.setRequestHeader("Content-type", "application/json"); xhr.onreadystatechange = function() { if (xhr.readyState == XMLHttpRequest.DONE && xhr.status == 200) { } }; var data = { name: name.value, email: email.value, message: message.value }; if (name.value && email.value && message.value) { success.style.display = "block"; success.innerHTML = "Thanks for submitting"; document.querySelector(".all").style.display = "none"; xhr.send(JSON.stringify(data)); } else { error.style.display = "block"; error.innerHTML = "Please Fill All Details"; } }
You’ll probably see familiar things in here, as you should. There’s no Lambda “black magic” in here. We are defining the parameters that we’ll use in the form, create the submit function that will call our endpoint. Yes, the endpoint(line 14) is where the magic is. Make a note of that because we’ll get back to it in a second.
Since we are here let’s create the .css too, just to get it out of the way.
*{ box-sizing: border-box; padding: 0; margin: 0 } body{ font-family: sans-serif; } .items{ display: flex; flex-direction: column; justify-content: center; align-items: center; margin: 2rem; font-size: 1.1rem; padding: 1rem; } input{ padding: 1rem; margin: .8rem; width: 25rem; height: 3rem; font-size: 1.1rem; border: 3px solid rgb(31, 121, 255); outline: none; } textarea{ width: 25rem; height: 10rem; padding: 1rem; display: flex; justify-content: center; outline: none; border: 3px solid rgb(31, 121, 255); font-size: 1.1rem; } .area{ display: flex; } .area-label{ margin-left:-2rem; } .txt{ margin-left:.6rem; } button{ padding: 1rem; width: 10rem; margin-top: 2rem; text-align: center; background-color: rgb(75, 224, 75); font-size: 1.3rem; color: rgb(2, 2, 15); box-shadow: 0 .2rem .2rem black; } .success{ background-color: rgb(75, 214, 224); font-size: 1.2rem; text-transform: capitalize; text-align: center; margin-top: 10rem; padding: 2rem; box-shadow: 0 .2rem .2rem rgb(0, 0, 0); display: none; } .error{ display: none; animation: move .2s ease-in ; } @keyframes move{ 0%{ opacity: 0; transform: translateY(-80%); } 50%{ opacity: .6; transform: translate(-20%); } 70%{ opacity: .7; transform: translate(20%); } 100%{ opacity: 1; transform: translate(0); } }
I’m not going to insist on the .css file but if you think I need to explain anything please leave a comment.
Now that we have our form assets created let’s load them in html. Go to the root of your project and create a new file named index.html. Since the code is straight forward just paste the following and you are all set.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name= "viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Contact us</title> <link rel="stylesheet" href="form/style.css"> </head> <body> <div class="all"> <form action="" class="items"> <h1>Contact Us</h1> <div class="error-items"> <p style="color:red" class="error"></p> </div> <div> <label for="name">Name</label> <input type="text" id="name" required placeholder="Enter Your Name" class="name" /> </div> <div> <label for="email">Email</label> <input type="email" required placeholder="Your Email" id="email" class="normal" /> </div> <div class="area"> <label for="message" class="area-label">Message</label> <textarea type="text" placeholder="Message" required id="message" class="txt"></textarea> </div> <button>Send</button> </form> </div> <p class="success"></p> <script src="./form/script.js"></script> </body> </html>
I know you got bored following the article up until now, nothing cool has happened. Well, hold on to your seat because we are going to write our serverless code up next.
We’ll have to first address the handler.js file. Open it from the root of your project and paste in the following code:
const serverless = require("serverless-http"); const AWS = require("aws-sdk"); const express = require("express"); const cors = require("cors"); const bodyParser = require("body-parser"); const app = express(); if (!AWS.config.region) { AWS.config.update({ region: "us-east-1" }); } const ses = new AWS.SES(); app.use(cors()); app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.json()); app.post("/", (req, res) => { const name = req.body.name; const email = req.body.email; const message = req.body.message; const emailParams = { Source: "yourname@mail.com", // Your Verified Email Destination: { ToAddresses: ["yourname@mail.com"] // Your verfied Email }, ReplyToAddresses: [req.body.email], Message: { Body: { Text: { Charset: "UTF-8", Data: `${message} from ${req.body.email}` } }, Subject: { Charset: "UTF-8", Data: "You Received a Message from www.domainname.com" } } }; ses.sendEmail(emailParams, (err, data) => { if (err) { res.status(402).send(`${err} ${err.stack}`); } if (data) { res.send(data); } }); }); module.exports.form = serverless(app);
What we just did is to create the method that calls SES and sends the message. Pretty straightforward stuff.
Next up we are going to have a look at the serverless yml. This is where we are just going to select what region we’ll be using, defining the actual function that the Lambda will execute and the action, which is ses:SendEmail.
service: contact-form provider: name: aws runtime: nodejs8.10 region: us-east-1 iamRoleStatements: - Effect: "Allow" Action: - "ses:SendEmail" Resource: "*" functions: app: handler: handler.form events: - http: ANY / - http: 'ANY {proxy+}'
Next stop: deployment. Sounds complicated but it’s actually a simple task. All you do is open your terminal and run: sls deploy.
You’ll see the log on the screen and when it’s done you’ll have to copy the endpoint and paste it into your script.js file I mentioned earlier. Open script.js and on line 14 replace the word “remeberThisEndpoint” with the endpoint supplied. That’s it! Open your html and test out your contact form.
Before I let you go, I’ve got to tell you about monitoring your app which is very important when working with serverless. You’ll want to keep an eye out for health problems, invocations time, and any errors you might have. Not keeping tabs on your serverless app might cost a lot and it’s not something startups can afford. Or even if they could afford the cost what they simply can’t do is have their service interrupted because a Lambda is taking too long to execute creating a bad experience for their customers.
You can check on your app via the AWS Console but this is not something that can be quickly and easily observed and understood or through a third party like Dashbird, a service that monitors your AWS Lambda providing insights on what happens behind the scenes.
Today we are announcing a new, updated pricing model and the end of free tier for Dashbird.
In this article, we’re covering 4 tips for AWS Lambda optimization for production. Covering error handling, memory provisioning, monitoring, performance, and more.
In this article we’ll go through the ins and outs of AWS Lambda pricing model, how it works, what additional charges you might be looking at and what’s in the fine print.
Dashbird was born out of our own need for an enhanced serverless debugging and monitoring tool, and we take pride in being developers.
Dashbird gives us a simple and easy to use tool to have peace of mind and know that all of our Serverless functions are running correctly. We are instantly aware now if there’s a problem. We love the fact that we have enough information in the Slack notification itself to take appropriate action immediately and know exactly where the issue occurred.
Thanks to Dashbird the time to discover the occurrence of an issue reduced from 2-4 hours to a matter of seconds or minutes. It also means that hundreds of dollars are saved every month.
Great onboarding: it takes just a couple of minutes to connect an AWS account to an organization in Dashbird. The UI is clean and gives a good overview of what is happening with the Lambdas and API Gateways in the account.
I mean, it is just extremely time-saving. It’s so efficient! I don’t think it’s an exaggeration or dramatic to say that Dashbird has been a lifesaver for us.
Dashbird provides an easier interface to monitor and debug problems with our Lambdas. Relevant logs are simple to find and view. Dashbird’s support has been good, and they take product suggestions with grace.
Great UI. Easy to navigate through CloudWatch logs. Simple setup.
Dashbird helped us refine the size of our Lambdas, resulting in significantly reduced costs. We have Dashbird alert us in seconds via email when any of our functions behaves abnormally. Their app immediately makes the cause and severity of errors obvious.