Lambda functions are one of the most powerful parts of the AWS ecosystem. You can use them to create serverless architecture, run microservices on static sites, and even help manage your existing infrastructure. In fact, with a bit of research, you can do pretty much whatever you want with a Lambda function.
As much fun as it is to work with Lambda, I’ve found it awkward to develop and deploy functions locally. When creating a simple function that consists of just one file, this was never a problem since Lambda comes with an inline editor. But as soon as you begin adding packages and libraries, things can get messy. In development, you need to ensure that your environment has the correct permissions, the right keys, and of course, you have to zip up your files before you can deploy (even for a test). Some of this is laziness on my part, but until recently, I felt that writing Lambda code wasn’t as smooth as it could be.
That’s when I remembered an announcement from this past year’s re:Invent conference – Cloud9. Cloud9 is a web-based IDE that integrates with Lambda and solves just about all the problems I was facing. You can use it to write, test, and deploy your code with pretty much no effort at all. A single click is all it takes to get your function and dependencies zipped up and into production. I’m clearly pretty excited about this new way of writing serverless code, but you don’t have to take my word for it – in this tutorial, we’ll use Cloud9 to build and deploy a Lambda function.
To follow along, check out the sample code on Github.
What Will We Deploy?
In this guide, we’ll make a function that sends a text message with tomorrow’s weather forecast.
I wrote this code to solve a real problem that I face – forgetting to check the weather. This sounds trivial, and it probably is, but I wake up around 6 AM each day, and I like to save time in the morning by setting my clothes out the night before. Being the optimist I am, if I don’t remember to check the weather first, I’ll assume the forecast is sunny and grab a t-shirt, only realizing the temperature dropped 30 degrees overnight when I step out the door. There are obviously many low tech solutions to this problem, but since Lambda deployment is so easy now, why not create a function that sends me a text each night to tell me what the weather will be the following day?
Before We Begin
We’ll need to do a few things before we can start setting up our function. First, make sure you have an Amazon Web Services account. The resources we use in this tutorial will all fall within the free tier, so it won’t cost you anything if you’re new to AWS. Next, you’ll need a Dark Sky API key (secret key), which you can get on their developers’ site. Dark Sky is a service that provides extremely precise weather data, and their free tier provides up to 1000 calls per day, so this won’t cost you anything either.
One more quick note – you’ll need to select a region that includes Lambda, Cloud9, and Simple Notification service. Depending on where you live, us-east-1 and us-west-2 may be good options.
Setting up Our Services
Before we get into the Lambda/Cloud9 integration, we’ll need to set up a few other services to allow it to work:
- First, log into your AWS account, click the services menu, and select Simple Notification Service, or SNS.
- From the SNS dashboard, click Create Topic:
- For the Topic name, enter something descriptive such as LambdaWeatherTopic. The description will show up in the text messages themselves, so enter something short to save characters (I used “weather” for my description).
- Once your Topic has been created, click Create Subscription.
- In the subscription creation form, leave the ARN as its default value, select SMS as the protocol, and enter your own phone number as the endpoint. The phone number must use E.164 format – if you’re not sure how your phone number needs to be entered, check out this guide.
- Once you’ve entered the required information, click Create subscription. Before you leave the SNS dashboard, be sure to copy your Topic ARN from the top of the page – we’ll need it in a later step.
- From the services menu, navigate to Identity and Access Management (IAM).
- Select Roles from the menu on the left side of the page, and click Create Role.
- On the first page, select Lambda as the service that will use the role:
- Click Next: Permissions.
- From the list, search for a policy called AWSLambdaBasicExecutionRole and select it by checking the corresponding box. This allows your Lambda function to log output and errors to CloudWatch in case you need to troubleshoot:
- Before moving on to the next screen, click Create policy at the top of the page to add a custom policy to the role. A new tab will open up, allowing you to define the permissions on your new policy. Click the JSON tab at the top of the editor and paste in the following policy. This allows your Lambda functions to publish to your new SNS topic:
- Click Review Policy and enter a name – this should be something descriptive like AllowSNSPublish. When you’re finished, click Create policy and return to the first tab where you began creating your role.
- Refresh the list of policies and search for the new policy you created. Select it by checking the corresponding box:
- Click Next and enter a name for your role. Make sure to use something descriptive, like LambdaWeatherRole, and click the Create role button.
After all that, we’re finally ready for the fun part…working with Cloud9!
Creating a Cloud9 environment
Cloud9 is an online IDE (Integrated Development Environment) that lets you edit, test, and debug code from your browser, without the hassle of setting up tools on your own machine. If you’ve ever taken Harvard’s online CS50 course, you may have already used it as a standalone service. However, they were acquired by Amazon a few years ago, and the new service was announced at re:Invent, 2017. The integrations it brings to other AWS services are incredibly powerful, so let’s get started!
- First, go to the Cloud9 service page and click Create environment.
- Enter a name for your environment – this can be whatever you like – and click Next step.
- On the settings page, leave the environment type as Create a new instance for environment (EC2). The instance type will be up to you. For this project, you can leave the default selection of t2.micro – this instance type is eligible for the free tier, but if you have bigger projects in mind, you can select a larger instance (keep in mind that these may charge your account!). Finally, notice the cost-saving setting. This is a built-in feature of Cloud9 that powers down your server after a certain period of inactivity to minimize cost. I recommend leaving this setting at 30 minutes – even if your instance powers down faster than you expect it to, it should only take about a minute to turn back on. When you’re finished on this page, click Next step.
- On the final page, review your settings and click Create environment.
Once you’re done, the new environment will take a few minutes to create and connect. Once it’s done, however, you’ll have access to a full-featured code editor in your browser. From here, we’re ready to start creating our Lambda function, but feel free to take a moment to customize your editor’s colors and theme if you like.
Creating our Lambda function
Now for the fun part…writing the code. I’ve already written the function code, actually, but we’ll go through together and see exactly how everything works so that you can make changes if you like. Start by cloning my function into your Cloud9 environment (Git comes preinstalled on the instance) and installing its dependencies by running the following commands in your environment’s terminal:
git clone https://github.com/pbzona/lambdaWeather.git cd lambdaWeather npm install
Once you have the project downloaded, take note of the included files. We’ll be focusing on just three of them: helper.js, template.yaml, and lambdaWeather/index.js.
The helper file is a script that you can run to get your geographic coordinates. This is not a standard part of Lambda, but it’s included here to help you easily figure out your location in the format our code expects. To use it, you can run
node helper.js "[your location]". Be sure to substitute [your location] for your actual location – this can be a city and state, zip code, or your full address. Its output will be the coordinates of the location you entered:
The template file is a specification that allows us to deploy our function from Cloud9. If you’ve used CloudFormation before, this file might look familiar. That’s because CloudFormation is used behind the scenes when we deploy.
We’ll need to make some changes to this file before we can use it, however. Our Lambda function uses environment variables to store some of its data. These are values that are picked up by the NodeJS process when the code is executed – to be more technical, they’re properties that can be accessed via Node’s process.env object. To set the correct values in your Lambda environment:
- Change the Role value to the ARN of the LambdaWeatherRole you created in the first section of this guide
- Change the API_KEY value to the secret key you obtained when you created your Dark Sky developer account
- Change the COORDS value to the coordinates you obtained when running the helper script with your location
- Change the TOPIC value to the ARN of the LambdaWeatherTopic SNS topic you created in the first section of this guide
After making these changes, make sure to save the file.
The last file we’ll look at is our index.js file, which is stored in a subdirectory of our project. This file contains the code our Lambda function will execute at runtime, so we’ll go through piece by piece so that you can see exactly what will happen:
First, we load in our dependencies. Since we need to access SNS to publish our message, we’ll create a new SNS client using the Amazon Web Services SDK. We’ll also use the axios library later on. This library is used for making Promise-based HTTP requests; we could do the same thing using native NodeJS modules, but I included a third party library to show the simplicity of deploying projects with dependencies. More on this later. We also define some variables using the environment variables we set up in our template; these will be used throughout our function for readability.
Next, we create our handler, which is the part of the code Lambda uses when it runs. For more information on the specifications used here, check out the AWS docs on function handlers. The first line within our handler is where we construct the URL for our request to the Dark Sky weather service. Notice that we’re using our API key and our geographic coordinates. This line is based on the Dark Sky forecast request format, which you can read about here.
When I thought about what information I’d like to receive, I chose the high and low temperatures for the day, as well as the likelihood of rain, so that’s what I defined here. Dark Sky provides a “summary” of the weather for a given day, which can be helpful as well. For example, the message I received last night said: “Partly cloudy throughout the day.” These were my preferred values, but you can customize these to your liking once you get a feel for the Dark Sky API format. Their documentation on different values you can use can be found here.
We’re beginning to wrap things up here by putting the data we’ve retrieved into something resembling the format we want. First, we create a template string using the weather forecast information from the last section. This is what will be sent via text message, so feel free to switch things up here if you like. One caveat to be aware of is that text messages (SMS) are limited to 140 characters, so be sure to keep your message fairly short. Once we build the message format, we create the params object that our SNS call requires. We use the message from before as the “Message” property, and we set our topic variable (defined as an environment variable in our template) as the “TopicArn” property.
Once all this data formatting has taken place, we can send our text message. To do this, we publish to our SNS topic using the parameters we specified in the last step. If an error occurs when calling the publish method, we’ll return an error. Otherwise, we use the handler’s callback to return a success message.
And with that, we’ve got a Lambda function to send us text message updates! Well…almost.
Testing in Cloud9
As you might have guessed, we can do this from within Cloud9. Be sure that your active tab is the index.js file (if it’s not, double-click that file from the file tree on the left). Next, click the Run button next to the page – you can find it next to the circular green button with the play symbol:
A new panel will open up next to your code allowing you to run your “local” Lambda function directly from Cloud9. The top section will allow you to test it with a payload. For example, if you wrote a serverless contact form, you might input your form data here to test it. However, since we aren’t accepting any inputs, we’ll leave our’s blank. When you’re ready to test, click the Run button within the smaller panel that appeared. If the function runs successfully, you’ll see some metadata about the SNS request below, but more importantly, you should receive a text message on your phone with tomorrow’s forecast!
Deploying Lambda Functions from Cloud9
If you’ve made it this far, deploying will be a breeze. On the far right side of the screen, look for a vertical list of actions including “Collaborate” and “Outline.” From this menu, click AWS Resources and a tab will expand, showing your local functions (the ones on your Cloud9 server) and “remote” functions (ones that have been deployed to Lambda).
From this menu, select your lambdaWeather function from the local menu, and click the upward pointing arrow above it to deploy:
Setting up the timer
Now that your function is deployed, the final step is to set up a trigger. For our purposes, we want the function to run regularly. To achieve this, we’ll use CloudWatch events. Navigate to your Lambda dashboard from the services menu and find the function you just deployed. Since it was deployed automatically, its name will be a long, randomized string similar to this: cloud9-lambdaWeather-lambdaWeather-T600J6N9INY. Your string will be slightly different but look for the name you used in your Cloud9 configuration.
Scroll down the page to the Designer panel, and select CloudWatch Events from the menu of triggers:
A Configure triggers panel will appear below. Select Create a new rule from the Rule drop-down menu and enter a Rule name of your choosing. For the Rule Type, select Schedule expression and enter
cron(15 2 * * ? *).
This last field may take some calculation, depending on when you want your text message to send. CloudWatch Events are based on UTC time, regardless of the region in which they’re deployed, so you’ll need to adjust the value for your time zone. For example, I live in the Central time zone in the US, where it’s currently daylight savings time. Therefore, my time zone is CDT, which is equivalent to UTC-05:00. I want to run the function each night at 9:15 PM CDT, so I set it to run at 2:15 AM UTC. The format used is cron notation, and if you’re not familiar with how it works, you can find a guide on it here.
This may sound complicated, but it all boils down to figuring out the difference between your time zone and UTC and writing out the corresponding time in cron notation.
Once you’ve configured your function, make sure that Enable trigger is selected and click Add.
That’s it! If you followed along, you should now get daily weather updates delivered to your phone to remind you to wear a jacket (or pack your sunscreen). Of course, the weather updates are not the point. The real power here is the ability to create Lambda functions in a tightly integrated environment and deploy them with a single click. Cloud9 does more than just make deployment easy, however. It also allows you to easily test your code before pushing it to production. You can even use Git version control with your code to allow rollbacks and easier collaboration.
Some steps you might want to take with this sample project might be to change the format of the text message or to display different information from what I included in the example. Once you’re comfortable with Lambda and Cloud9, you can even begin to incorporate new APIs, different ways of triggering your functions, and new ways to return the data you want. As with everything in cloud computing, the only limit is what you can imagine.