AWS Tutorial: Intro to using Lambda with the Serverless framework

Use Serverless to create a REST API with Node.js and Lambda

Lately, I’ve been turning to AWS Lambda for building server-side logic — whether for client work, product development, or even personal projects. Lambda is a managed service, so there’s no need to patch or monitor servers. It’s pay-as-you-go, so you only get charged for usage, rather than uptime. And it’s elastic, so it scales up to handle enterprise level traffic, or shrinks to zero for those pet projects that never take off.

There’s usually a lot more to an app than just the Lambda function. API Gateway gives your Lambda a consumer-facing REST endpoint. And IAM policies grant your Lambda access to other AWS services. As your Lambda integrates with more AWS services, managing your app settings can become complicated and error-prone.

The Serverless framework simplifies the process of building and maintaining Lambda applications. Here are a few highlights:

Infrastructure as code: AWS settings are defined in a configuration file that can be versioned in source control.

Single point of change: App settings for Lambda, API Gateway, and IAM are consolidated into a single configuration file.

Simple deployment: Serverless packages and deploys your Lambda app to AWS with a single command.

There are other tools out there to help you manage your Lambda applications. For example, Chalice from AWS Labs supports Lambdas written in Python. This tutorial focuses on Serverless.

Note: The term “serverless architecture” refers to a way of building applications that run without having to manage infrastructure (like an always-on Linux box). The “Serverless framework” is a 3rd party tool that helps you manage and deploy your app to AWS Lambda and API Gateway.

Using Serverless, you’ll create a Node.js REST API that responds with a JSON array describing the contents of an S3 bucket. Your app architecture will end up looking like this:

What you need for this tutorial

All of the steps are performed on a Mac, so you may need to adapt them if you’re using Windows or Linux.

You’ll need an AWS account. If you don’t have one, you can sign up for the free tier.

1. Install Serverless using NPM

The Serverless framework is an NPM module. To install it, type the following command into Terminal:

$ npm install -g serverless

The -g flag installs Serverless globally, which gives you the convenience of running the serverless command from any directory.

Pro tip: You can install the NPM module local to your project, instead of globally.

$ npm install serverless --save-dev

The Serverless team likes to move fast and break things, so it might be a good idea to set your Serverless version in your package.json. This way, you can use the latest version of Serverless on new projects without impacting older ones.

The tradeoff is that you’ll have to drill down to a subfolder in order to reach the serverless executable:

$ ./node_modules/serverless/bin/serverless

2. Create a sample project

Serverless has commands, like create, deploy, and invoke. You’re going to start off with using the create command.

In an empty folder, type the following:

$ serverless create --template aws-nodejs

This creates a new serverless project using the built-in Node.js template.

Note: There’s also a template called aws-python for you python developers out there.

The create command generates two new files — one for code, and the other for configuration:

Note: The default YAML file has a lot of comments and whitespace, but you can see a cleaner version using this command:

$ sed '/^[#;].*$/d;/^$/d' serverless.yml

It’s in YAML format, which is like JSON but uses indentation instead of curly braces. You’ll be seeing a lot of the serverless.yml file throughout the tutorial. But for now, just pay attention to these lines:

runtime: You’re using the Node.js runtime. Here’s a list of other runtimes that Lambda supports.

hello: This is your function name.

handler: This is the file and path to your function.

Give your Lambda function a try by using the invoke command.:

$ sls invoke local -f hello

Even though it’s just a single line, there are a couple things going on here:

Using the Add user wizard, you begin the process of creating a service account named serverless. You also select Programmatic access, which generates access keys for you.

Continue with the next section of the Add User wizard.

On the Set permissions for serverless page, click Attach existing policies directly

Type AdministratorAccess in the search filter

Check the box next to the AdministratorAccess policy

Click the Next: Review button

On the Review page, click the Create user button

Click the Download .csv button

Click Close

You grant admin privileges to your service account by attaching the AdministratorAccess policy. Once the account is created, you download a CSV file containing the access keys. This is the only chance you get to download these keys.

Note: In a production environment, you should tailor down access to least privilege. This tutorial uses a blanket admin access policy to keep things simple. Be sure to detach this policy when you’re done.

4. Configure a local AWS profile

Now that you have a set of access keys, you can save them inside an AWS profile on your local Mac. Later, you will refer to this profile name in the Serverless configuration file.

Note: It’s a good practice to use AWS profiles so you don’t accidentally deploy infrastructure to the wrong AWS account.

Create a local AWS profile named serverless:

$ aws configure --profile serverless

You will be prompted with a series of questions. Refer to the downloaded CSV file when filling out the Access and Secret Access keys:

You should see an error message that says Access Denied. The problem is that your Lambda does not have permission to read from your S3 bucket. In the next section, you’ll fix this using IAM.

9. Grant access using IAM

Behind the scenes, Serverless generates an IAM role policy for you. But the only thing you get out of the box is the ability to write logs to CloudWatch. For anything beyond this, you need to explicitly grant access.