Infrastructure can be intimidating. There’s a reason AWS is the most popular cloud platform in the world – it’s complex. That complexity is what allows AWS to be so powerful, but it can also be a huge barrier for people who aren’t already working with similar tools. We’ve talked a lot about the value of knowing the AWS platform, but knowing where to start is a problem of its own. In this guide, I want to go back to the basics of web development and talk about how to use a microservice hosted on AWS. To do this, we’ll create a simple web page that uses a serverless contact form that allows your users to send you emails.
Who is this guide for?
When we talk about learning AWS, we often talk about how you can use it to launch a new career in systems administration or operations. Of course, the platform isn’t only for “backend” or “systems” work. Services like AWS Lambda need to be integrated into the front end, and because AWS is so widely used, it’s important for web developers to have some familiarity with how it works. This guide is for web developers who want to know more about microservice architecture, but aren’t ready to learn the whole AWS platform from the ground up.
The word microservice sounds complex, but you don’t need to be an expert to start working with them. However, you do need a few things to get started:
- An AWS account – You can create one for free here.
- A microservice to use – We previously posted a guide on creating a serverless contact form using AWS Lambda. That’s what we’ll be integrating into our page (and we recommend you follow that guide before this one), but the principles and concepts we talk about will apply to other microservices based on AWS Lambda and API Gateway as well.
What will we be making?
In this guide, we’ll be integrating an existing contact form microservice into a web page. Before getting started, make sure to follow our guide on creating a serverless contact form. That guide handles the “backend” setup on AWS, and this guide will explain how to integrate it into an existing site. When we’re done, you’ll have a contact form that calls an AWS Lambda function that allows your users to send you an email through a form on your site.
What is a microservice?
This question could take up a guide of its own, but it’s important to understand before we get started. Microservice architecture means that your infrastructure (the servers that host your app) is made up of small, mostly independent pieces that are each responsible for a specific task. When you write an application, you use functions to perform certain tasks and separate responsibilities within your codebase.
To use a rough analogy, microservices are to infrastructure as functions are to your code.
Let’s say your application crashes. If your codebase is large enough, it could take a ton of work to isolate and fix the issue – and you may not be able to bring your application back online until you do. With a microservice architecture – using separate infrastructure to handle different tasks – you can often leave the rest of the app running while you fix one particular issue. The problem is isolated and has little or no impact on the rest of your code.
You may have heard terms like serverless or functions as a service. Lambda is Amazon’s implementation of these concepts, and a microservice architecture is one way that it can be used to improve your site or application.
Integrating your first microservice
If you haven’t created your infrastructure in AWS, be sure to do that first. Our guide to setting up your serverless contact form can be found here. If you’re creating your first AWS account (or using one created in the last 12 months), all the services we use will be included in the free tier, so it won’t cost you anything to follow along and try it out.
The AWS infrastructure serves as your “backend,” but you also need a form to allow users to input information. Here’s a simple web page that we’ll use to illustrate how to make it work:
If you’d like to follow along, paste the code above into a text editor open it in your browser. You’ll see something like this:
Now let’s break down each part of the script, step by step. This isn’t meant to be the most efficient implementation, but I wrote out the code to explicitly show all of the component parts. There are frameworks that can do the same thing, but the goal here is to illustrate what’s going on with a series of easy-to-follow steps. We won’t go over the HTML structure of the page, since that part will be up to you when designing your application.
First, we need to enable to form to do something when it gets submitted:
This will probably look familiar – we’re just adding an event listener onto the form. When it gets submitted, the sendDataToLambda function will be called. Further down in the code, we define that function. You can ignore the e.preventDefault() line at the beginning of the function – it prevents the page from reloading on submission, which makes testing easier – and continue down to the first three variables we create:
This part should also look familiar. When the form is submitted, one of the first things we need to do is grab the values of each input field. Because of the way we created our Lambda function, it expects three values: the user’s email address, the subject of the email, and the body of the message.
Up until now we’ve been dealing with concepts you’ve probably seen before, but next, we’ll begin to see how Lambda comes into play.
This line defines our endpoint. If you’ve done much web development, you’ve probably used an API before (Google Maps or Yelp, for example). Our serverless contact form works in a very similar way. When we created our Lambda function, we set the API Gateway service to be its trigger. You can think of API Gateway as a managed API service. It listens for HTTP(S) requests, and does something when it receives them. In this case, it invokes our Lambda function to send an email.
To find your endpoint, navigate to API Gateway in the AWS web console. In the menu on the left, select the “contact” API we created, and click Stages. Select the “prod” stage, and copy the Invoke URL shown in the blue box at the top of the page. That’s the base of your URL – you’ll also need to add a resource. If you followed along in our initial guide, we named this “/ContactFormLambda” but you can find it in the Resources section under your “contact” API if you called it something else.
To summarize, your endpoint is made up of both the invoke URL and the resource name. If you try to run your function from the browser and get a “Missing Authentication Token” error, this is a good place to check first.
Next, we’ll construct an object:
This object is what we’ll use as the body of our HTTP request to the API Gateway. We’re using the three required fields that our Lambda function expects to receive, along with the values we got from our user input fields earlier.
The next step instantiates (creates) our request. This might look unfamiliar, so let’s break down why we’re doing it this way:
This is a Request object, and it’s specific to the Fetch browser API. If you are familiar with AJAX, you may have used jQuery’s .ajax() method or the browser’s native XMLHttpRequest (XHR) object to make server requests. Fetch does most of the same things, but it’s a little more modern and, in my opinion, easier to use.
We’re creating a new instance of Request, which takes two parameters. First, the endpoint where the request will be made (our API Gateway route), and second, an object containing some information about the request. Since we’re sending data to our endpoint, we’re using the “POST” method. We also need to convert the body of our request to a string so that Lambda can understand it (our Lambda function expects a string, but will parse it as JSON when it gets called – see the Lambda code for details on how this happens).
The other setting we’re using, “no-cors” mode, is for local development. It allows us test our code while avoiding some default security features of the Fetch API. We’ll talk more about what this means in the next section.
Finally, we put everything together into a Fetch call:
And that’s it! With this code in place, you can enter some test data in the form, and submit it.
Once you’ve done that, check the email account you verified with AWS, and you should see a new message with the information you provided:
A couple final notes – you will need to enter a valid email address in the email field. SES does validate this section, and you’ll receive an error if it doesn’t detect a valid format. You’ll also notice that, after submitting your form, the response data that is supposed to logged to the console is incomplete. For example, you’ll see a “status” property of 0, rather than the actual HTTP status code (200 or 5xx). This is due to the “no-cors” mode we set on the request, which we’ll address next.
Deploying to production
This setup is fine for testing, or if you just want to see how things work. If you’re ready to start using a serverless contact form on your own site, however, you’ll need to take a couple more steps.
First of all, remove mode: ‘no-cors’ from your Request object. Normally, you can’t make cross-origin requests from your local computer since its origin is set to ‘null.’ Adding this option to the request allows us to test locally, but it’s not necessary to make calls from your own site. In fact, leaving it in production may prevent you from being able to accurately handle errors in the Fetch response – it will cause you to get an opaque (empty) response, and you won’t have access to things like HTTP status codes or error messages.
Finally, change the “Access-Control-Allow-Origin” header in API Gateway to your domain name. To find this setting, open your “/ContactFormLambda” resource in the API Gateway console, click the Actions menu at the top of the page, and select Enable CORS. The last field on this page will allow you to set this header to the domain name of the site on which you’ll use your contact form:
So why does this matter?
We talked about the benefits of microservice architecture a little bit before – it separates your services so that if one fails, your entire application doesn’t go down. For example, you might create another microservice that reads from your database, in addition to your contact form. If one of these services crash, the other can continue to run without requiring you to log into your server and restart your app.
Another benefit is development speed. A “normal” architecture requires more testing to ensure that new code doesn’t interfere with the existing application. With microservices, a contact email and a database read, for example, are totally independent. You can make changes to one service, test that service, and deploy it immediately. New services can be added at any point without stressing about whether they’ll cause a breaking change.
Microservices, like the contact form we created, are also easy to integrate into static sites. Over the last few years, static site generators have become incredibly popular, and for good reason – they’re fast, maintainable, and make it relatively easy to create a nice-looking site without much code. Microservices allow you to run a backend without all the maintenance that can scare people away from unmanaged hosting. They also provide a nice middle ground when creating your site – maybe you don’t need a full PHP or Rails application, but a static site just doesn’t quite do enough. Microservices with AWS Lambda allow you to handle traditional “server-side” operations by creating scripts like the one above and embedding them into your static pages.
The connection between web development and a complex platform like AWS isn’t always immediately clear. AWS is often thought of as a service for administrators, but with a little bit of knowledge, it’s not too difficult to get started using it in your own projects.
I want to clarify something – what we’ve created here is not a full microservice architecture. It’s just an example of how you might build one and only shows one component. But with AWS Lambda, creating more services like our contact form submission is easier than ever. Because Lambda offers functions as a service, you can focus more on the code and less on the infrastructure that runs it. You can follow our guide on creating a serverless contact form and modify it to perform other tasks for you – sending text messages with AWS Simple Notification Service (SNS) might be a good next step. AWS offers dozens of services, so if you look around, you’re sure to find something interesting to play with.
The best way to learn is by doing. You can read all the documentation in the world, but until you get your hands dirty, it’s difficult to truly develop your skills. If this guide got you excited about the power of AWS, there are plenty of projects you can try out at little or no cost. The microservice we created here is covered under the AWS free tier – which applies to new AWS accounts for 12 months from the date they’re created. AWS also published a static web hosting guide that covers a $0.50 (yes, that’s cents) per month setup. What’s important is getting in there and using the services – the knowledge and skills will come with experience.
Of course, if you want a more formal training program, that’s what we’re here for. Our mission is to help people of all skill levels learn cloud computing through real-world scenarios and hands-on training. Let us know in the comments if you have questions, or better yet, sign up for a free community account and find out where your cloud learning journey will take you.
While the scope of this guide was meant to be limited to microservice implementation, we used a few web technologies and concepts that might warrant some extra research. Here are a couple links to get a more in-depth look than we provided here:
That’s So Fetch (credit to Jake Archibald)
AWS Lambda Deep Dive