Getting Started with Serverless Computing on AWS
This chapter will cover the following topics:
- Getting started with the AWS platform
- Your first AWS Lambda
- Your first Lambda with AWS CLI
- Your first Lambda with Amazon CloudFormation
- Using AWS SDK, Amazon CloudFormation, and AWS CLI with Lambda
- Dev practices: dependency injection and unit testing
- Your first Lambda with Serverless framework
Introduction
Cloud computing introduced a pay-per-use model and abstracted physical servers with virtual machines and managed services. Cloud computing execution models include Infrastructure as a Service (IaaS), Platform as a service (PaaS), Software as a Service (SaaS), and Serverless computing (or Function as a Service (FaaS)).
IaaS provides services that form the basic building blocks of cloud computing, such as virtual machines, storage, network, and so on. PaaS provides platforms on which we can develop applications such as execution runtime, databases, web servers, and so on. Saas provides completed software that we can use for various needs such as Gmail's email service.
Serverless computing allows us to run functions (code) without worrying about servers and pay only for the time we execute code. Despite the name, servers are still present, however, the provider does all the server management including starting and stopping them to serve requests, patching and more. Serverless computing comes roughly in between PaaS and SaaS.
Getting started with the AWS platform
Amazon provides you with Free Tier to get started with AWS on production quality servers. Free Tier provides you with free access to many services and features with decent limits.
Getting ready
To work with AWS Free Tier, you need a decent computer, a reasonable internet connection, a working credit card, and basic knowledge of computers and the internet.
How to do it...
Let's get started on the AWS platform by creating a Free Tier account. We will then do some basic IAM settings as suggested by AWS. Finally, we will also create a billing alarm to keep track of any unexpected costs. If you already have a working account with basic setup done, you may skip this part of the recipe:
- Go to https://aws.amazon.com and create a new Free Tier account (if you do not already have one) as follows:
- Provide login credentials.
- Provide personal information such as address, phone number, and other required details, if you have selected Personal account, or Corporate information if you have selected company account.
- Provide credit card details.
- Proceed with telephonic verification.
- Select Basic plan for Free Tier account with community support (or select a paid plan if you want to).
After logging in for the first time, it is recommended that you complete the basic Identity and Access Management (IAM) security settings listed under the Security Status heading. If you have previously logged in, the options might not be displayed as shown next. If so, you need to manually go to IAM service from the Services dropdown.
- Click on Activate Multi-Factor Authentication (MFA) on your root account and do as follows:
- Click Manage.
- Select A Virtual MFA Device.
- Click Continue on the message for installing an MFA-compatible application (assuming you have installed Google Authenticator along with barcode scanner, or any similar applications).
- Scan the barcode shown on screen using Google Authenticator, and enter two consecutive codes for confirmation.
- Click on Create individual IAM users and do as follows:
- Enter Username.
- Select Access Type (Programmatic access and AWS Management Console access).
- Download the credentials .csv file to a secure area in your local machine. You will not be able to download it later, but you can regenerate it.
- Click on Use groups to assign permissions and assign some random permissions.
- Click on Apply an IAM password policy to set up a basic password policy.
IAM dashboard should now show all security status items as green:

- Create a billing alarm to have a check on accidental costs:
- Go to My Billing Dashboard (by clicking the drop-down arrow near to your name).
- Under Alerts and Notifications, click on Enable Now to Monitor your estimated charges.
- After going to Preferences, select Receive Billing Alerts and click on Manage Billing Alerts link within the contents, which will take you to CloudWatch.
- Click on Billing and create an alarm.
If you followed all previous steps successfully, you are ready to get started with further recipes in this book.
How it works...
Most of the steps in this recipe are self-explanatory and similar to registering for any other paid online service. The following are the important AWS services and concepts that were introduced in this recipe.
AWS Identity and Access Management (IAM)
IAM enables secure access to AWS resources. IAM supports standard security concepts such as users, groups, roles, and permissions. The user is an individual who wants to use AWS services. Users can be added to groups. Users and groups are assigned with permissions. Roles are used by a service (for example, Amazon Ec2) for accessing other services.
Amazon CloudWatch
Amazon CloudWatch is a service that helps in monitoring your applications, responding to changes (such as performance changes and billing alarms), optimizing resource utilization, and providing you a unified view of the health of services in your account. We will see more use cases of Amazon CloudWatch in later recipes.
Multi-Factor Authentication (MFA)
Multi-Factor Authentication provides additional levels of authentication. In addition to passwords, it also requires you to authenticate using a token generated by a virtual or physical authenticator. It is a good practice to set up MFA even for personal accounts, as the password is the same as the e-commerce portal and Prime Video.
There's more...
The following are some of the common AWS services that are used in building Serverless applications on the AWS:
- AWS Lambda lets you write code without configuring any server.
- Amazon API Gateway lets you create REST APIs without coding.
- Amazon Simple Storage Service (S3) is an object store that helps you store and retrieve data. S3 can also be used for hosting single-page applications (SPA) such as an angular or react application.
- Amazon DynamoDB is a scalable NoSQL database.
- Amazon CloudFront is a Content Delivery Network (CDN) service.
- Amazon CloudWatch is a service to monitor your applications and respond to changes.
- AWS CloudFormation templates written in JSON or YAML can be used to provision and model our infrastructure.
- AWS Identity and Access Management (IAM) provides access control for AWS resources.
- Amazon Cognito helps you build access control for your application with features such as user sign-up, sign-in, and more.
- Other services can be used alongside these services for advanced use cases, such as natural language processing (for example, Alexa Skills kit, and Lex), Analytics (Amazon Kinesis Streams), Machine Learning (Amazon Machine Learning), and so on.
Apart from using the AWS management console from a browser, we can also interact with AWS services from AWS CLI (command line) and AWS SDK (programmatic access). Except for the first few recipes, we will mostly focus on using Amazon CloudWatch with AWS CLI for modeling and provisioning our infrastructure.
See also
Your first AWS Lambda
AWS Lambda is the core service in AWS for building serverless applications. You can run code without provisioning servers. You pay only for the time you run your code, unlike EC2 where you pay for the time the server is up. Lambda also takes care of high availability. You can invoke Lambdas from other AWS services, console, or AWS CLI.
In this recipe, we will create a Lambda in Java and deploy it using the AWS management console. In the next recipe, we will also explore AWS CLI to deploy Lambda. In later recipes and chapters, we will see how we can automate most of the deployment tasks using Amazon CloudWatch templates similar to how most enterprise projects do.
Getting ready
To follow the example in this recipe, you need a working AWS account. You should also set up Java Development Kit (JDK) and Maven in your local machine. I am currently using Java 8 and Maven 3.5.4.
Example projects in this book uses a maven parent project, serverless-cookbook-parent-aws-java.The versions of libraries used within each Lambda project (for example, aws.sdk.version) are defined in the parent project POM file.
It is a good idea to create a folder within your operating system to manage the code files for this book. I will use a folder with the name serverless. You need to make sure that you can execute the following commands from this folder:
javac -version
mvn -version
You can set up the parent project inside our parent folder (serverless in my case) by executing the following commands from the command line:
- Clone our book's Github repository:
git clone https://github.com/PacktPublishing/Serverless-Programming-Cookbook.git
- Go inside the repository folder, go inside our project-specific parent project, and run mvn clean install:
cd Serverless-Programming-Cookbook
cd serverless-cookbook-parent-aws-java
mvn clean install
Code repository usage guidelines
Each chapter has a directory of its own (for example, Chapter 01). Inside the chapter's directory there will be sub-directories for each recipe. The recipe specific directory has names corresponding to the recipe's title. For example, the directory for this chapter, recipe titled Your first Lambda is your-first-lambda.
Inside the recipe's directory, there will be a directory for storing all resources including the AWS CLI commands called resources. Long AWS CLI commands are split into multiple lines for better readability using the \ symbol. If you are using a Windows machine you can use the ^ symbol instead of the \ symbol in the code files or make a single line command without the \ symbol.
The recipe's directory also contains a sub-directory for each Lambda project. You need to run mvn clean package for generating the Lambda JAR from within this directory. The Lambda JAR is generated within the target directory inside this directory. Every Lambda project inherits from the common Lambda parent project's directory serverless-cookbook-parent-aws-java and hence needs to be built before any Lambda project, following the steps outlined in the previous section.
How to do it...
We will create our first Lambda with Java as a Maven project. The javadoc comments and package-info.java files required for checkstyle checks from the parent are not shown here. We are also making use of the Maven shade plugin from the parent for generating the JAR files. You may refer to the code files for each recipe for the complete code:
- Create the Java project based on Maven.
Create a Java project based on Maven with our common parent, declared as shown next in the POM file:
<groupId>tech.heartin.books.serverless-cookbook</groupId>
<artifactId>helloworld-lambda</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>tech.heartin.books.serverlesscookbook</groupId>
<artifactId>serverless-cookbook-parent-aws-java</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
- Also, declare the only dependency we need for our hello world lambda project in the POM file:
<dependencies>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-core</artifactId>
<version>${aws.lambda.java.core.version}</version
</dependency>
</dependencies>
The dependency versions (for example, aws.lambda.java.core.version) are defined in the POM file for the parent project serverless-cookbook-parent-aws-java.
- Create the Lambda handler class and package it as a JAR.
Create a class, HelloWorldLambdaHandler, that implements the interface, RequestHandler:
package tech.heartin.books.serverlesscookbook;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
public final class HelloWorldLambdaHandler implements RequestHandler<String, String> {
public String handleRequest(final String s, final Context context) {
context.getLogger().log("input: " + s + "\n");
String greeting = "Hello " + s;
return greeting;
}
}
To package the Lambda as a JAR file, from the project root folder, run the following:
mvn clean package
Two JARS will be created: one with only class files (starting with original-) and an Uber JAR with dependencies (starting with serverless-). You can easily differentiate between one and the other looking at their sizes. We will use the JAR file that starts with original- and that has only the class files for this recipe.
- Deploy the Lambda handler to the AWS:
- Log in to the AWS console, and go to Lambda dashboard by clicking on Services and searching or selecting Lambda. Currently, it is under the compute category.
- Create a Lambda function as follows:
- Click on Create Function.
- Select Author From Scratch, which is the default.
- Give a name, such as myHelloWorldLambda.
- Select Java 8 as the runtime.
- Under Role, select Create new role from one or more templates.
- Give a role name, such as myHelloWorldLambda.
- Leave the field for specifying Policy templates blank.
- Click on Create Function. You should see a success message after a while.
- Upload the Lambda JAR:
Go to the Function code section and do the following:
-
- Select Code entry type as Upload a .zip or .jar file.
- Select Java 8 as the runtime.
- Specify the fully qualified class name with handler method name as the following: tech.heartin.books.serverlesscookbook.HelloWorldLambdaHandler::handleRequest.
- Click on Upload under Function package and select the JAR file. You can select the JAR whose name starts with original-.
- Click on Save to save with defaults for other fields.
- We can test the uploaded JAR:
- Select Configure test events from the Select a test event dropdown next to the Test button.
- Select Create new test event.
- Give a name for the event: MyHelloWorldTest.
- Within the JSON request content area, just specify your name, such as Heartin.
- Click on Create. If successful, it will take you to the myHelloWorldLambda function page.
- From the myHelloWorldLambda function page, select the test event, MyHelloWorldTest, next to the Test button, and click the Test button.
- You should see the message Hello Heartin after expanding the details of execution result.
- We can also check the logs printed using context.getLogger().log():
- Under the Log output section, you can see the log you printed.
- You can also see the log in the CloudWatch service. There should be a Click here link to view the CloudWatch log group. Click on the link, wait or refresh for a stream that matches your invocation time, and click on the stream link to see the log statement within CloudWatch.
How it works...
The following are the in detail information about the role and functionality of Lambda plays and concepts that were introduced in this recipe.
About the parent POM
Example projects in this book use the Maven parent project serverless-cookbook-parent-aws-java that defines the dependency versions for our examples. The actual dependencies are defined within each example project to help you understand the dependencies needed for each use case. All dependency definitions are shown within comments in the parent POM for quick reference.
Our parent project serverless-cookbook-parent-aws-java is also dependent on two open source projects: simple-starter-parent-java for the common Java dependencies, and simple-starter-build-tools for the common build file, such as the code style plugin definitions.
Lambda roles
In this recipe, we selected the Create new role from template(s) and did not select any policy. The basic permissions required (logging to CloudWatch) are added by default. We can also choose an existing role or create a custom role.
Lambda runtimes
AWS Lambda supports various runtimes, such as C# (.NET Core 1.0), C# (.NET Core 2.0), C# (.NET Core 2.1), Go 1.x, Java 8, Node.js 4.3, Node.js 6.10, Node.js 8.10, Python 2.7, and Python 3.6. Inline code editing is only allowed for Node.js and Python.
Extra dependencies
Our parent project, serverless-cookbook-parent-aws-java, defines a few more dependencies than I have. You can download them automatically through Maven (these projects are already available in Maven Central) or set these up manually in your local machine (to examine or modify) by executing the following commands from the command line.
- Go inside the parent folder (serverless in my case) and clone the simple-starter-build-tools project:
git clone https://github.com/heartin/simple-starter-build-tools.git
- Go inside the project folder and run mvn clean install, as follows:
cd simple-starter-build-tools
mvn clean install
- Go back to the parent folder (serverless in my case) and clone the simple-starter-parent-java project:
git clone https://github.com/heartin/simple-starter-parent-java.git
- Go inside the project folder and run mvn clean install:
cd simple-starter-parent-java
mvn clean install
There's more...
The following are the in detail information about the other ways to create Lambda and to deploy its functions:
Other ways to create Lambda functions from the management console
Apart from the Author from scratch option, we can create Lambdas using Blueprints and Serverless Application Repository. Blueprints allow you to choose a preconfigured template as a starting point. Currently, blueprints are available only for Node.js and Python. Serverless Application Repository allows you to find and deploy Serverless apps developed by developers, companies and partners on AWS.
Other ways to deploy code in a Lambda function
In this recipe, we developed our code outside AWS and uploaded it to our AWS Lambda function as a JAR file. You can also upload the file to Amazon S3 by selecting Code entry type as Upload a file from Amazon S3, and providing the S3 link. For some languages such as Node.js and Python, you can also write the code inline within the Lambda function.
Passing JSON to and from Lambda handler
In this recipe, we passed simple Strings to and from our Lambda handler. We can instead pass a JSON and get back a JSON. To do this, we need to create two POJOs that represent our input and output, and specify them as generic types within our Handler declaration. We will see this approach in the next recipe.
See also
- Read about the Programming Model for Authoring Lambda Functions in Java at https://docs.aws.amazon.com/lambda/latest/dg/java-programming-model.html
- Read about the Lambda permissions model at https://docs.aws.amazon.com/lambda/latest/dg/intro-permission-model.html
- If you find any issues while setting up and using AWS, you can visit this page for troubleshooting help: http://cloudmaterials.com/en/book/troubleshooting-aws-cloud-beginners
- If you are new to Java, Maven or Git you may read my notes on those from these links:
Your first Lambda with AWS CLI
The AWS Command Line Interface (CLI) is a command line tool provided by AWS to manage AWS services. You can save your credentials and config into profiles, and then specify a profile while executing a command. The more you get familiar with the CLI commands, the faster you can work with AWS services, making you more productive.
In this recipe, we will deploy an AWS Lambda using AWS CLI. We will use an updated hello world. In the last recipe, we had sent and received back simple text. In this recipe, we will demonstrate the use of POJOs for sending to and retrieving JSON data from the Lambda handler.
In most of the later recipes within this book, I will be including AWS CLI commands along with either Management Console or CloudFormation steps to provide an overview of various API usages in a programming language-independent way. You can follow these API usages along with any particular programming language SDK documentation to implement it in that language. The CLI commands also help us better understand the CloudFormation templates.
Getting ready
Following are the prerequisites for this recipe:
- Install and configure JDK, Maven and the parent project, serverless-cookbook-parent-aws-java, and read the section as outlined in
- Follow the Getting ready section of the recipe Your first AWS Lambda to install and configure JDK, Maven and the parent project, serverless-cookbook-parent-aws-java, and follow the notes given in that section for code usage guidelines
- Configure AWS CLI as given later in this section
- Create an S3 bucket
Configuring AWS CLI
We can use pip or pip3 to install AWS CLI.
You use pip or pip3 to install AWS CLI as:
pip install awscli --upgrade --user
Pip is a Python package management tool that can be installed along with Python. You may replace pip with pip3 if you have installed pip3. The --upgrade option upgrades any installed requirements. The --user option installs the program to a sub-directory of your user directory to avoid modifying libraries used by operating system.
We can configure our AWS credentials in our local machine by running aws configure. This will setup a default AWS profile. You can have more named profiles if you want.
Run the below command to configure AWS CLI for the default profile. If aws command is not recognized, you will need to add it to the path.
aws configure
Provide your AWS Access Key ID, AWS Secret Access Key, Default region name, and Default output format:

AWS Access Key ID and AWS Secret Access Key is generated by AWS when you create a user with programmatic access. We had created an user and generated these credentials in the recipe Getting started with the AWS platform. You can also regenerate them later if you forget or miss them following the below steps:
- Log in to AWS.
- Go to IAM service.
- Click on Users from the sidebar. This will show you the user summary page.
- From within the user summary page, click on Security Credentials tab.
- Click on Create access key to create a new key. You may make the old key inactive or delete it.
The AWS Access Key ID and AWS Secret Access Key entered is stored in a file, ~/.aws/credentials, and the region name and output format is stored in a file, ~/.aws/config.
Verify the configuration as given as follows:
cat ~/.aws/credentials

And next, run cat ~/.aws/config:

AWS documentation recommends creating a named profile for your admin user (for instance, a user with administrator access policy) and then using it with AWS CLI. You can add an additional profile in ~/.aws/credentials, as shown here:

You can add an additional profile by editing the file ~/.aws/config, as shown here:

Creating S3 bucket
We will be using Amazon Simple Storage Service (S3) to upload our JAR files. Therefore it would be good to do some reading on basic S3 concepts, such as S3 buckets and S3 keys.
You can create a bucket using the below command:
aws s3 mb s3://<bucket name> --profile admin
Replace the <bucket name> with your bucket's name. Remember that the S3 bucket name has to be unique across AWS.
Note for Windows users
If you are using a Windows machine the .aws folder should be present inside your user profile folder and may be found as dir %UserProfile%\.aws. You may also use the notepad command to edit files in a notepad instead of the cat command. Remember to save the notepad file if you are editing:

How to do it...
We will create our Lambda, similar to in the Your First AWS Lambda recipe, but using POJOs for input and output. We will not go deep into concepts discussed previously. If in doubt, please refer to the Your First AWS Lambda recipe.
- Create the Maven project with only the core dependency, aws-lambda-java-core:
<groupId>tech.heartin.books.serverless-cookbook</groupId>
<artifactId>lambda-handler-with-pojos</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>tech.heartin.books.serverlesscookbook</groupId>
<artifactId>serverless-cookbook-parent-aws-java</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-core</artifactId>
<version>${aws.lambda.java.core.version}</version>
</dependency>
</dependencies>
- Create POJO for input:
import lombok.Data;
@Data
public class HandlerRequest {
private String name;
}
- Create POJO for output:
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class HandlerResponse {
private String message;
}
- Create a Lambda handler with input and output POJOs:
public final class MyLambdaHandler implements RequestHandler<HandlerRequest, HandlerResponse> {
public HandlerResponse handleRequest(final HandlerRequest request,
final Context context) {
context.getLogger().log("Hello " + request.getName());
return new HandlerResponse("Hello " + request.getName());
}
}
- Package the JAR.
We can generate JARs by running mvn clean package. Two JARs are created: one with only class files (starting with original-) and an Uber JAR with dependencies (starting with serverless-). In this recipe, we will use the original JAR.
- Upload the JAR file to your S3 bucket using AWS CLI:
aws s3 cp target/original-serverless-cookbook-lambda-handler-with-pojos-0.0.1-SNAPSHOT.jar s3://serverless-cookbook/lambda-handler-with-pojos-0.0.1-SNAPSHOT.jar --profile admin
- Create a policy with the aws iam create-policy command:
aws iam create-policy \
--policy-name lambda_iam_policy_test \
--policy-document file://basic-lambda-permissions.txt \
--profile admin
Replace <account_id> with your account id. You can get your account number by going to the My Account page after clicking on your name on the top right of your AWS management console. The policy file is also available in the resources folder of the recipe. If successful, you should get a response with the ARN of the policy created.
- Create a role using the aws iam create-role command:
aws iam create-role \
--role-name lambda_iam_role_test \
--assume-role-policy-document file://iam-role-trust-relationship.txt \
--profile admin
The policy file is available in the resources folder of the recipe. If successful, you should get a response with the arn of the role created.
- Attach the policy to the role:
aws iam attach-role-policy \
--role-name lambda_iam_role_test \
--policy-arn arn:aws:iam::<account_id>:policy/lambda_iam_policy_test \
--profile admin
Replace <account_id> with your account number.
- Create a Lambda function providing the role and the S3 location:
aws lambda create-function \
--function-name demo-lambda-with-cli \
--runtime java8 \
--role arn:aws:iam::<account_id>:role/lambda_iam_role_test \
--handler tech.heartin.books.serverlesscookbook.MyLambdaHandler::handleRequest \
--code S3Bucket=serverless-cookbook,S3Key=lambda-handler-with-pojos-0.0.1-SNAPSHOT.jar \
--timeout 15 \
--memory-size 512 \
--profile admin
Replace <account_id> with your account number. The code option can accept the shorthand form as used here, or a JSON.
- Invoke our Lambda from CLI:
aws lambda invoke \
--invocation-type RequestResponse \
--function-name demo-lambda-with-cli \
--log-type Tail \
--payload '{"name":"Heartin"}' \
--profile admin \
outputfile.txt
In certain platforms, you might have to add escaping for the payload specified in the command line. This is not required as the payload is specified as a file, as here:
--payload file://input.txt \
The output can be viewed in the outputfile.txt file:

- Note the following regarding cleanup roles, policy, and Lambda.
To delete Lambda, perform the following:
aws lambda delete-function \
--function-name demo-lambda-with-cli \
--profile admin
To detach policy from the role, perform the following:
aws iam detach-role-policy \
--role-name lambda_iam_role_test \
--policy-arn arn:aws:iam::<account_id>:policy/lambda_iam_policy_test \
--profile admin
Replace <account_id> with your account number.
To delete a role, note the following:
aws iam delete-role \
--role-name lambda_iam_role_test \
--profile admin
To delete policy, perform the following:
aws iam delete-policy \
--policy-arn arn:aws:iam::<account_id>:policy/lambda_iam_policy_test \
--profile admin
Replace <account_id> with your account number.
How it works...
The following are the important details and concepts that were introduced in this recipe:
Creating a role and attaching a policy
You need to create a role with a trust policy that allows our Lambda to assume the role. You also need to attach a policy that has CloudWatch permissions for logging.
Lambda memory-size and timeout
When creating a function from CLI, the default value of timeout is 3 seconds, and default value memory-size is 128 MB, which may not be sufficient for Lambdas with Uber JARs, and you may get a timeout exception or Process exited before completing request. Hence, I have set a higher timeout and memory-size. Other parameters are mostly self-explanatory.
S3 Bucket and Key
Amazon S3 is an object store. Objects (files) are stored as simple key-value pairs within containers called buckets. Bucket names have to be unique across AWS. There is no folder hierarchy within the buckets like traditional file systems. However, we can simulate folder structure with hierarchical key names. For example, consider the folder1/folder2/file.txt key, that simulates a folder-like structure. Read more about simulating folders in S3 at https://docs.aws.amazon.com/AmazonS3/latest/user-guide/using-folders.html.
Cleaning up
You need to do a cleanup in the following order:
- Delete Lambda that uses the role
- Detach policy from role
- Delete role and policy
There's more...
Once you get familiar with the AWS CLI commands, it is much faster and easier to work with AWS CLI, rather than navigate through the pages of AWS management console. This chapter covers only a very basic use case. Please follow the links in the See also section and try out more examples with AWS CLI and Lambda.
See also
- More details on installing AWS CLI using pip can be found at https://docs.aws.amazon.com/cli/latest/userguide/installing.html
- AWS documentation on CLI configuration can be found at https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html
- AWS CLI command reference can be found at https://docs.aws.amazon.com/cli/latest/reference
- If you find any issues while setting up and using AWS, you can visit this page for troubleshooting help: http://cloudmaterials.com/en/book/troubleshooting-aws-cloud-beginners
Your first Lambda with Amazon CloudFormation
Amazon CloudFormation lets you provision and model your AWS service infrastructure declaratively. Instead of using interactive tools such as management console or CLI directly, you can declare the configuration with expected order, dependencies, input, and output in a template, and CloudFormation will provision it for you.
The concept of writing code to manage infrastructure is referred to as Infrastructure as Code (IaC) and is a practice that most enterprise companies follow. You can also maintain the provisioning code in a code repository and follow practices such as code reviews like any other code. Thus, it lets you reuse the provisioning code.
In this recipe, we will use CloudFormation to provision the infrastructure for the Lambda we created in the Your Lambda with AWS CLI recipe.
Getting ready
You need to read and follow to the Getting ready section of the recipes Your first AWS Lambda and Your first Lambda with AWS CLI before proceeding.
Set up the project and S3 bucket
In this recipe, we are reusing the Lambda we created in the Your Lambda with AWS CLI recipe. Generate a JAR by running mvn clean package inside that project, and upload the JAR to S3:
aws s3 cp target/original-serverless-cookbook-lambda-handler-with-pojos-0.0.1-SNAPSHOT.jar s3://serverless-cookbook/lambda-handler-with-pojos-0.0.1-SNAPSHOT.jar --profile admin
Replace the bucket name serverless-cookbook with your bucket's name. Refer to the Getting ready section of the recipe Your First AWS CLI to create the S3 bucket.
Understanding YAML and JSON
CloudFormation templates are written in JSON or YAML. Both support data in key-value pairs, objects, arrays, and so on .YAML also supports additional features such as multi-line strings, comments, and so on. I will also be using YAML for the examples. Since YAML support was introduced later for CloudFormation, you will also see a lot of JSON templates in the web. So, it is also good to have a decent understanding of YAML and JSON. If you are familiar with one, you may also use one of the JSON to YAML or YAML to JSON converters available online.
How to do it...
- Create the CloudFormation template.
Resources components specify the AWS resources used. We need two resources for our use case: a role and a Lambda function with that role. The following is the basic structure of our CloudFormation template:
---
AWSTemplateFormatVersion: '2010-09-09'
Description: Building Lambda with AWS CloudFormation
Resources:
IamRoleLambdaExecution:
Type: AWS::IAM::Role
Properties:
# Properties for the role are shown later.
LambdaFunctionWithCF:
Type: AWS::Lambda::Function
Properties:
# Properties for the Lambda are shown later.
DependsOn:
- IamRoleLambdaExecution
I have also defined AWSTemplateFormatVersion and Description as a general practice, but they are optional. Note that properties for the IamRoleLambdaExecution and LambdaFunctionWithCF are not shown here. You may refer to further steps or use the template from the code files.
The role needs a trust relationship policy that allows the lambda to assume that role, and we need to attach a policy to the role that provides CloudWatch logging permissions. The AssumeRolePolicyDocument property specifies the trust relationship policy for the role:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- sts:AssumeRole
The policy is specified inline within the Policies property of the role:
Policies:
- PolicyName: 'lambda-with-cf-policy'
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource: arn:aws:logs:*:*:*
We will also define two more properties for the role, namely path and name:
Path: "/"
RoleName: "lambda-with-cf-role"
Our Lambda function will have the following basic configuration:
LambdaFunctionWithCF:
Type: AWS::Lambda::Function
Properties:
Code:
S3Bucket: 'serverless-cookbook'
S3Key: lambda-handler-with-pojos-0.0.1-SNAPSHOT.jar
FunctionName: first-lambda-with-cloud-formation
Handler: tech.heartin.books.serverlesscookbook.MyLambdaHandler::handleRequest
MemorySize: 512
Role:
Fn::GetAtt:
- IamRoleLambdaExecution
- Arn
Runtime: java8
Timeout: 15
DependsOn:
- IamRoleLambdaExecution
We specify the role as a dependency for the Lambda function, and use Fn::GetAtt to retrieve the role dynamically instead of hardcoding the name. Most of the other properties are self-explanatory.
A CloudFormation stack is a collection of AWS resources that you need to manage as a single unit. All the resources in a stack are defined by a CloudFormation template. When you delete the stack, all of its related resources are also deleted.
We can create a CloudFormation stack in different ways, including the following:
-
- Going through the Create Stack option within the CloudFormation service inside AWS Management Console
- Uploading directly from the Template Designer within the CloudFormation service inside AWS Management Console
- AWS CLI
In this recipe, I will use Designer, but in all other recipes I will be using AWS CLI. AWS CLI is the best way to deploy CloudFormation templates. Designer is also a good tool to visualize and validate your scripts.
- Create CloudFormation stack from Designer:
- Log in to AWS and go to CloudFormation service.
- Click on the Design template button to go to Designer. Within designer, you may do the following:
- Choose template language as YAML in the editor. (If you are using a JSON template, use JSON instead.)
- Select the Template tab in the editor.
- Copy and paste your template into the template editor window.
- Click on refresh on the Designer to see the template in the Design view.
- If any changes are required, you can either make changes within the Template tab or use the Components tab.
- If everything looks good, click on the upload button on the top left of the designer to launch the Stack creation wizard with the current template.
- Follow the wizard with defaults, and select the checkbox for I acknowledge that AWS CloudFormation might create IAM resources with custom names. Finally, click on Create Stack.
- Invoke our Lambda with AWS CLI as follows and verify:
aws lambda invoke \
--invocation-type RequestResponse \
--function-name first-lambda-with-cloud-formation \
--log-type Tail \
--payload '{"name":"Heartin"}' \
--profile admin \
outputfile.txt
Output can be viewed in the outputfile.txt file:

Cleaning up roles, policy, and Lambda
To clean up resources created by CloudFormation, you just need to delete the stack. This is the default setting. Since we have used AWS management console for stack creation, we will use it for deletion as well.
You can delete a CloudFormation stack from the management console as follows: go to CloudFormation service, select the stack, click on Actions, and click Delete Stack.
How it works...
In this recipe, we used the following CloudFormation template components: Resource, AWSTemplateFormatVersion, and Description. Resources are the AWS resources used in the template. AWSTemplateFormatVersion is the version of CloudFormation template the template conforms to.
We used two resources: a role (IAMRoleLambdaExecution) and a Lambda function (LambdaFunctionWithCF) that depends on that role. Resource names can be anything. Type specifies the type of the resource. We used two types, namely AWS::IAM::Role and AWS::Lambda::Function.
The properties of the AWS::IAM::Role resource type that we used are as follows:
- AssumeRolePolicyDocument specifies the trust relationship policy for the role
- Policies specify the policies inline
The properties of the AWS::Lambda::Function resource type that we used are as follows:
- Code property specifies the S3 bucket and the key. You can also specify a reference to an S3 Bucket resource type so that a new bucket is created dynamically and its name is used here.
- FunctionName specifies the name of the Lambda function.
- Handler specifies the fully qualified name of the handler class with the handler method.
- MemorySize specifies the memory in MB. The number of CPU cores is decided by AWS based on the memory.
- Role specifies the role.
- Runtime specifies the runtime (for instance, java8).
- TimeOut specifies the timeout.
To get the role Arn, we used the GetAtt function passing the logical name of the Role and the property name Arn:

Fn::GetAtt is an intrinsic function that returns the value of an attribute from a resource in the template.
We used CloudFormation designer in the recipe to see our template in design view, and then uploaded the template into a stack from the designer. You can also use the Designer to design CloudFormation templates from scratch.
There's more...
You can check the documentation and study related components within Lambda code if interested:
CloudFormation Template Components
CloudFormation templates are composed of the following primary components:
- AWSTemplateFormatVersion is the version of CloudFormation template the template conforms to
- Description is a text that describes the template
- Resource components are the AWS resources used in the template
- Parameter components are the input (dynamic) to your template
- Mapping components are variables (static) for your template
- Output components describe the values that are returned
- Condition components control resource provisioning
- Metadata provides additional information about the template
- Transform specifies the version of the AWS Serverless Application Model (AWS SAM) for Serverless applications
We will talk about the components in the recipe in which they are introduced. Read more about template components at https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-anatomy.html.
Resource component
The following are some of the important features of Resource component:
- Resource component of the template specifies the AWS resources used in the template
- Resource can reference each other using the ref element
- Resource names can be anything
- Type specifies the type of the resource
- Each type has its own set of properties that you can refer to from the documentation, given under the properties element
- DependsOn specifies the other resources that the current resource is dependent on
Intrinsic functions
Intrinsic functions are built-in functions provided by AWS to use within a template for dynamically adding values. Common intrinsic functions used within CloudFormation templates are as follows: Fn::Base64, Fn::Cidr, Fn::FindInMap, Fn::GetAtt, Fn::GetAZs, Fn::ImportValue, Fn::Join, Fn::Select, Fn::Split, Fn::Sub, and Ref.
CloudFormation also supports the following conditional functions: Fn::And, Fn::Equals, Fn::If, Fn::Not, and Fn::Or.
We can specify the functions in the standard forms as mentioned here or in the short-hand form (for instance, !Base64, !Cidr, !Ref, and so on) if you are using YAML. We used the standard syntax for this recipe for reference, but will use the short-hand syntax in later recipes.
We will discuss the functions introduced in each chapter. You can read more about all intrinsic functions at https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html.
CloudFormation Designer
The following are some of the important features of the CloudFormation Designer:
- Create templates from scratch visually, validate, and upload
- Copy existing templates, see them visually, validate, and upload
- Drag and drop the resources you need
- Define relationships between resources
- Right-click on the service and click on the appropriate context menu option to go directly to the CloudFormation documentation for that service
- Edit logical name and other properties in the auto-generated template
- Copy and paste an existing template and see it in design view
- Directly upload the script to S3 and launch Create stack wizard in a single click
Additional benefits of CloudFormation
Apart from automated provisioning of resources through code and enabling reuse, CloudFormation also has other important usages, including the following:
- Lets you estimate costs based on the templates
- Enables tracking costs effectively
- Helps in saving costs by automated deletion of resources when not needed
- Diagrams generated based on templates can help in understanding the system better, and can be used in design discussions
Cloud Formation alternatives
Important alternatives to using CloudFormation include Ansible, Terraform, Chef, AWS OpsWorks, and AWS Elastic Beanstalk.
See also
- All resources supported by CloudFormation are available at https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html
Using AWS SDK, Amazon CloudFormation, and AWS CLI with Lambda
AWS SDK allows you to write code that interacts with AWS services. In this recipe, we will use AWS Java SDK for IAM to do some basic IAM operations to form a Lambda programmatically. We will use it along with Amazon CloudWatch and AWS CLI, which is a general practice followed in most real-world projects.
Getting ready
You need an active AWS account, and read and follow the Getting started section of the recipes, Your first AWS Lambda and Your first Lambda with AWS CLI to set up Java, Maven, the parent project, serverless-cookbook-parent-aws-java, and AWS CLI, and other code usage guidelines.
How to do it...
We will create a Java Maven project and set the parent as serverless-cookbook-parent-aws-java.
- Create a Java Maven project and set dependencies:
<parent>
<groupId>tech.heartin.books.serverlesscookbook</groupId>
<artifactId>serverless-cookbook-parent-aws-java</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
- Specify dependencies in the POM file:
<dependencies>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-core</artifactId>
<version>${aws.lambda.java.core.version}</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-iam</artifactId>
<version>${aws.sdk.version}</version>
</dependency>
</dependencies>
Creating the POJOs for requests and response.
- Create a request POJO for accepting requests:
import lombok.Data;
@Data
public class IAMOperationRequest {
private String operation;
private String userName;
}
- Create a POJO for sending back the response from the handler:
import lombok.AllArgsConstructor;
import lombok.Data;
@AllArgsConstructor
@Data
public class IAMOperationResponse {
private String message;
private String errorMessage;
}
Creating a service class to implement the IAM Operations using AWS SDK:
- Import the required classes:
import com.amazonaws.services.identitymanagement.AmazonIdentityManagement;
import com.amazonaws.services.identitymanagement.AmazonIdentityManagementClientBuilder;
import com.amazonaws.services.identitymanagement.model.CreateUserRequest;
import com.amazonaws.services.identitymanagement.model.CreateUserResult;
import com.amazonaws.services.identitymanagement.model.DeleteConflictException;
import com.amazonaws.services.identitymanagement.model.DeleteUserRequest;
import com.amazonaws.services.identitymanagement.model.ListUsersRequest;
import com.amazonaws.services.identitymanagement.model.ListUsersResult;
import com.amazonaws.services.identitymanagement.model.User;
- Create and initialize a client object of AmazonIdentityManagement type:
private final AmazonIdentityManagement iamClient;
public IAMService() {
iamClient = AmazonIdentityManagementClientBuilder.defaultClient();
}
- Write code for creating a user in a method:
CreateUserRequest request = new CreateUserRequest().withUserName(userName);
CreateUserResult response = iamClient.createUser(request);
// get user details from response.
- Write code for checking if a user is present in another method:
boolean done = false;
ListUsersRequest request = new ListUsersRequest();
while (!done) {
ListUsersResult response = iamClient.listUsers(request);
for (User user : response.getUsers()) {
if (user.getUserName().equals(userName)) {
//return success message
}
}
request.setMarker(response.getMarker());
if (!response.getIsTruncated()) {
done = true;
}
}
// return error message
- Write code for deleting a user in another method:
DeleteUserRequest request = new DeleteUserRequest()
.withUserName(userName);
try {
iamClient.deleteUser(request);
} catch (DeleteConflictException e) {
// Handle exception
}
Let us now see how to create a handler.
- Create a handler class with input and output POJOs:
public final class HelloWorldLambdaHandler implements RequestHandler<IAMOperationRequest, IAMOperationResponse> {
- Implement the handleRequest method with a switch statement to invoke an appropriate service method:
public IAMOperationResponse handleRequest(final IAMOperationRequest request, final Context context) {
context.getLogger().log("Requested operation = " + request.getOperation()
+ ". User name = " + request.getUserName());
switch (request.getOperation()) {
case "CREATE" :
return this.service.createUser(request.getUserName());
case "CHECK" :
return this.service.checkUser(request.getUserName());
case "DELETE" :
return this.service.deleteUser(request.getUserName());
default:
return new IAMOperationResponse(null,
"Invalid operation " + request.getOperation()
+ ". Allowed: CREATE, CHECK, DELETE.");
}
}
- Package the dependencies into an uber JAR using mvn clean package.
Two JARs will be created: one with only class files (starting with original-) and an Uber JAR with all dependencies (starting with serverless-). We will use the Uber JAR in this recipe.
- Upload the JAR to S3:
aws s3 cp target/serverless-cookbook-iam-operations-0.0.1-SNAPSHOT.jar s3://serverless-cookbook/iam-operations-0.0.1-SNAPSHOT.jar --profile admin
- Create a CloudFormation template for our lambda function.
You need to create a role with a trust policy that allows our Lambda to assume the role. You also need to create a policy with CloudFormation and IAM permissions.
We need to add permissions for IAM operations in our policies:
- Effect: Allow
Action:
- iam:CreateUser
- iam:DeleteUser
- iam:ListUsers
Resource:
- Fn::Sub: arn:aws:iam::${AWS::AccountId}:user/*
We have used a pseudo-parameter, AWS::AccountId, within a sub-intrinsic function to dynamically populate the account ID. I also improved the CloudWatch logging permission policy from the previous recipe using the pseudo-parameters:
- Effect: Allow
Action:
- logs:CreateLogStream
Resource:
- Fn::Sub: arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/aws-sdk-iam-with-cf-cli:*
- Effect: Allow
Action:
- logs:PutLogEvents
Resource:
- Fn::Sub: arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/aws-sdk-iam-with-cf-cli:*:*
You should be able to complete this recipe by referring to the previous recipe, Your First Lambda using CloudFormation.
- Upload the CloudFormation template to S3:
aws s3 cp ../resources/cf-template-iam-operations.yml s3://serverless-cookbook/cf-template-iam-operations.yml --profile admin
- Create a CloudFormation stack using the CloudFormation template from AWS CLI:
aws cloudformation create-stack --stack-name myteststack --template-url https://s3.amazonaws.com/serverless-cookbook/cf-template-iam-operations.yml --capabilities CAPABILITY_NAMED_IAM --profile admin
This immediately responds with StackId. Note that you used a parameter, --capabilities CAPABILITY_NAMED_IAM. This is a security-related precaution. You are explicitly telling CloudFormation that you know what you are doing.
You can check the status of stack creation using the describe-stacks command:
aws cloudformation describe-stacks --stack-name <StackId> --profile admin
StackStatus: CREATE_COMPLETE means stack creation was successful.
- Verify the deployment with AWS CLI Lambda invoke:
aws lambda invoke --invocation-type RequestResponse --function-name aws-sdk-iam-with-cf-cli --log-type Tail --payload '{"operation":"CREATE", "userName":"abcd"}' --profile admin outputfile.txt
You can replace CREATE in the payload with CHECK for checking if the user was created, and DELETE for deleting the user.
- Delete the CloudFormation stack:
aws cloudformation delete-stack --stack-name <StackId> --profile admin
How it works...
AWS SDKs are used to interact with AWS services programmatically. There are SDKs available for programming languages such as Java, .Net, Node.js. PHP, Python, Ruby, Browser, Go, and C++.
We uploaded our CloudFormation template to S3 and provided the location using --template-url. You can also specify the template contents directly or from a file using file:// with another option --template-body.
We created our roles for Lambda manually. If we are using Management console, we can create custom Lambda roles from within our Lambda create function page, or directly from IAM.
We used one new intrinsic function in our CloudFormation template, Fn::Sub. Fn::Sub, which substitutes variables in an input string with values that you specify. We used it to substitute the AWS Account ID and a few other values rather than hard-coding them.
We also used the following pseudo-parameters: AWS::AccountId, AWS::Partition, and AWS::Region, which represents the current account ID, partition, and region respectively. For most regions, the partition is aws. For resources in other partitions, the partition is named as aws-partitionn (for instance, aws-cn for China and aws-us-gov for the AWS GovCloud (US) region). Using pseudo-parameters lets us avoid worrying about the actual partition name.
There's more...
We used only basic IAM operations in this recipe. You can check the documentation and implement more complex operations from within Lambda code if interested.
Pseudo-parameters
Pseudo-parameters are predefined parameters provided by AWS CLoudFormation. You can use them within a Ref or a Sub function to dynamically populate values. Pseudo-parameters available to use within a CloudFormation template include AWS::AccountId, AWS::NotificationARNs, AWS::NoValue, AWS::Partition, AWS::Region, AWS::StackId, AWS::StackName, and AWS::URLSuffix.
Read more about pseudo-parameters at https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/pseudo-parameter-reference.html.
See also
- https://aws.amazon.com/sdk-for-java
- https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_manage.html
- https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_examples.html
- https://docs.aws.amazon.com/lambda/latest/dg/limits.html
- https://docs.aws.amazon.com/cli/latest/reference/cloudformation/index.html#cli-aws-cloudformation
Dev Practices – dependency injection and unit testing
In this recipe, I will implement some of the common dev practices for creating Lambdas, such as using lightweight frameworks for dependency injection and writing unit tests for your code.
For dependency injection, we will use Guice, which is one of the dependency injection (IoC) frameworks suggested by AWS at https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html. For unit testing, we will use JUnit and Mockito libraries.
Getting ready
You need an active AWS account, and read and follow the Getting started section of the recipes, Your first AWS Lambda and Your first Lambda with AWS CLI to set up Java, Maven, the parent project, serverless-cookbook-parent-aws-java, and AWS CLI, and other code usage guidelines.
This recipe also assumes you are familiar with general software development concepts and practices such as dependency injection, unit testing, and coding to interfaces. Familiarity with libraries such as JUnit and Mockito will be good to have.
Code refactoring
We will be improving the code we created in the Using AWS SDK, Amazon CloudWatch and AWS CLI with Lambda recipe. Before doing Dependency Injection, you need to refactor your code to follow the principle of programming to interfaces.
Refactor the service class into an interface and its implementation. I will also add lombok's @AllArgsConstructor annotation to generate an all args constructor, which will be used during unit testing to inject the mock object.
- We will first create an interface IAMService:
/**
* Interface for IAM operations.
*/
public interface IAMService {
We will define the corresponding implementation as IAMServiceImpl:
/**
* Implementation of {@link IAMService}.
*/
@AllArgsConstructor
public class IAMServiceImpl implements IAMService {
- Extract the methods as well, and then replace the usage of the implementation with an interface:
private IAMService service;
public MyLambdaHandler() {
service = new IAMServiceImpl();
}
How to do it...
Let us do dependency injection with Guice, which is a lightweight framework suggested by AWS.
- Add Maven dependency for Guice:
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>4.2.0</version>
</dependency>
- Create the Guice configuration class to bind interfaces to implementation:
public class ApplicationModule extends AbstractModule {
protected final void configure() {
bind(IAMService.class).to(IAMServiceImpl.class);
}
}
- Configure the handler class for using Guice:
public final class MyLambdaHandler implements RequestHandler<IAMOperationRequest, IAMOperationResponse> {
private static final Injector INJECTOR =
Guice.createInjector(new ApplicationModule());
private IAMService service;
public MyLambdaHandler() {
INJECTOR.injectMembers(this);
Objects.requireNonNull(service);
}
@Inject
public void setService(final IAMService service) {
this.service = service;
}
I created a static Injector class and initialized it with our Guice configuration class. I added a default constructor to add this class to be injected by Guice. Objects.requireNonNull verifies if the implementation was injected successfully. I annotated it with Java's @Inject annotation for Guice to inject dependency.
Let us write unit tests for our code.
- Add Maven dependency for JUnit and Mockito:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.21.0</version>
<scope>test</scope>
</dependency>
- Create a simple test class for the handler that checks if the service implementation is injected:
package tech.heartin.books.serverlesscookbook;
import org.junit.Test;
public class MyLambdaHandlerTest {
@Test
public void testDependencies() throws Exception {
MyLambdaHandler testHandler = new MyLambdaHandler();
}
}
- Create a test class for the service class that uses Mockito to mock AWS calls:
@RunWith(MockitoJUnitRunner.class)
public class IAMServiceImplTest {
@Mock
private AmazonIdentityManagement iamClient;
private IAMService service;
@Before
public void setUp() {
service = new IAMServiceImpl(iamClient);
Objects.requireNonNull(service);
}
// Actual tests not shown here
}
- Add the test method for create user:
@Test
public void testCreateUser() {
IAMOperationResponse expectedResponse = new IAMOperationResponse(
"Created user test_user", null);
when(iamClient.createUser(any()))
.thenReturn(new CreateUserResult()
.withUser(new User().withUserName("test_user")));
IAMOperationResponse actualResponse
= service.createUser("test_user");
Assert.assertEquals(expectedResponse, actualResponse);
}
- Add the test method to check user:
@Test
public void testCheckUser() {
IAMOperationResponse expectedResponse = new IAMOperationResponse(
"User test_user exist", null);
when(iamClient.listUsers(any()))
.thenReturn(getListUsersResult());
IAMOperationResponse actualResponse
= service.checkUser("test_user");
Assert.assertEquals(expectedResponse, actualResponse);
}
private ListUsersResult getListUsersResult() {
ListUsersResult result = new ListUsersResult();
result.getUsers().add(new User().withUserName("test_user"));
- Add the test method to delete user:
@Test
public void testDeleteUser() {
IAMOperationResponse expectedResponse = new IAMOperationResponse(
"Deleted user test_user", null);
when(iamClient.deleteUser(any()))
.thenReturn(new DeleteUserResult());
IAMOperationResponse actualResponse
= service.deleteUser("test_user");
Assert.assertEquals(expectedResponse, actualResponse);
}
- To Package, deploy, and verify, follow the Using AWS SDK, Amazon CloudFormation and AWS CLI with Lambda recipe, and package, deploy, and verify by invoking the Lambda.
How it works...
We added a lightweight dependency injection framework, Guice, and modified code to incorporate it. We also used JUnit and Mockito to do unit testing of the code. Going deep into the working of Guice, JUnit, or Mockito is outside the scope of this book. But, you may ask any questions on the open source repository for the project (given in the introduction in Chapter 1, Getting Started with Serverless Computing on AWS).
There's more...
You may also use Dagger instead of Guice for dependency injection. Dagger is also a recommended framework from AWS for lightweight dependency injection. You can technically use Spring for dependency injection, but it is not recommended because of its bigger size.
You may use TestNG instead of JUnit for unit testing. TestNG provides additional features such as DataProviders. DataProviders allow you to supply an array with all possible inputs and their expected values for a single test method. With JUnit, you will have to write a test method per input combination. You may also use Hamcrest to create more flexible expressions in tests.
See also
- You may refer to other books at PacktPub to become familiar with the dependency injection and testing frameworks.
Your first Lambda with serverless framework
Serverless is an open source command line utility framework for building and deploying serverless applications. Serverless supports multiple cloud providers such as Amazon Web Services, Microsoft Azure, IBM OpenWhisk, Google Cloud Platform, Kubeless, Spotinst, Webtasks, and Fn.
In this recipe, we will use the Serverless framework to develop, deploy, invoke, check logs, and finally remove a simple hello world Lambda function on the AWS cloud platform.
Getting ready
Two dependencies are needed for the Serverless framework: node.js and AWS CLI. For installing AWS CLI, you may refer to the 'Deploying and Invoking Lambda with AWS CLI' recipe. You can install node using node packet as given at https://nodejs.org/en/download/package-manager.
You need to create a user for Serverless in AWS. It is a general practice to use the name serverless-admin and give administrator permission. It is not a very good practice to create users with administrator access, but currently that is the easiest way to work with Serverless. You should be careful about storing and using these credentials.
How to do it...
Let us create a simple Lambda using the Serverless framework:
- Install Serverless in your machine using npm:
npm install -g serverless
- Configure Serverless with user credentials:
serverless config credentials --provider aws --key <access key> --secret <secret access key> --profile serverless-admin
You should get a success message stating that keys were stored under the serverless-admin profile.
- Create a Lambda function based on Java and Maven:
sls create --template aws-java-maven --path hello-world-java-maven
It creates a hello-world-java-maven folder, with pom.xml and serverless.yml files, and the src folder. You may open this Maven project in your IDE of choice. The auto-generated files looks as shown here in my IDE:

As you can see, Serverless has created a bit more than a simple hello world. Serverless takes care of most of the things we did manually, including creating a role, setting memory, setting timeout, and so on.
Add a user profile and region to serverless.yml. The region is optional if you are using the default region:

Build the jar file with:
mvn clean package
- Deploy the jar file to AWS:
sls deploy -v
You can log in to the AWS console and verify the new Lambda service. From the log statements, you can see that Serverless framework internally makes use of CloudFormation. You can verify the same from AWS Management console.
- Invoke the function from sls:
sls invoke -f hello -l
Option -f specifies the function name, and -l specifies that logs need to be printed to terminal. The function name to invoke is hello and is available in the serverless.yml file. You can see the output and logs on the terminal.
- Checking logs from the CLI:
sls logs -f hello -t
Option -f specifies the function name and -t denotes to tail the logs. You can now run the invoke command from the other terminal and see the logs being printed.
- Now, clean up everything:
sls remove
- Log in to AWS Management console and verify that everything is cleaned up.
How it works...
Serverless framework internally makes use of AWS CloudFormation for provisioning AWS resources. You can log in to Management console, go to CloudFormation service, select the stack named hello-world-java-maven-dev, and click on the Template tab for viewing the complete CloudFormation template.
You can further click on the View/Edit template in Designer option to see the template visually. The designer view of the CloudFormation template created for our example by the Serverless framework is shown here:

There's more...
Serverless framework is part of the serverless.com Serverless Platform. The other two components of the serverless platform are Serverless dashboard and event gateway. Serverless framework also integrates well with other processes and tools, such as CI and CD.
See also
- https://serverless.com/framework/docs.
- The last chapter, Chapter 10, Serverless Computing with Other Cloud Providers, Tools and Frameworks contains examples of other cloud providers.