How can I turn my Restful API into a Serverless application and deploy it to AWS Lambda Step by Step — Part II
This is the second part of this tutorial you can find the first one here. The whole tutorial is divided in five steps.
3. Configure a VPC for your lambda function
This part of the tutorial is only needed if you want to access to private resources of a VPC for example, for example, you want to connect with an Amazon RDS instance or Amazon EC2 Instance or you want to connect with a third party service like Mongodb Atlas but you don’t want to add the IP address 0.0.0.0/0 to your IP addresses whitelist (do this exposes your database to everybody).
To understand this section we will need to understand some key concepts that are really well explained by the AWS Team:
- A Virtual Private Cloud (VPC) is a virtual network dedicated to your AWS account. It is logically isolated from other virtual networks in the AWS Cloud. You can launch your AWS resources, such as Amazon EC2 instances, lambda functions, into your VPC. You can specify an IP address range for the VPC, add subnets, associate security groups, and configure route tables.
- A subnet is a range of IP addresses in your VPC. You can launch AWS resources into a specified subnet. Use a public subnet for resources that must be connected to the internet, and a private subnet for resources that won’t be connected to the internet. To protect the AWS resources in each subnet, you can use multiple layers of security, including security groups and network access control lists (ACL).
- A Routing Table contains a set of rules, called routes, that are used to determine where network traffic is directed. Each subnet in your VPC must be associated with a route table; the table controls the routing for the subnet. A subnet can only be associated with one route table at a time, but you can associate multiple subnets with the same route table.
- An Internet Gateway: An internet gateway is a horizontally scaled, redundant, and highly available VPC component that allows communication between instances in your VPC and the internet. It therefore imposes no availability risks or bandwidth constraints on your network traffic. An internet gateway serves two purposes: to provide a target in your VPC route tables for internet-routable traffic, and to perform network address translation (NAT) for instances that have been assigned public IPv4 addresses.
- A Network Address Translation You can use a network address translation (NAT) gateway to enable instances in a private subnet to connect to the internet or other AWS services, but prevent the internet from initiating a connection with those instances.
Let’s do it 💪.
First we are going to create our VPC, we need to create a public subnet and two private subnets and we need to define the CIDR blocks range addresses for each one of them.
Why do we need a public subnet? To allocate our NAT gateway and communicate our resources with the internet through an Internet Gateway.
Why do we need two private subnets? Because is a good practice to allocate your Lambda Function instances inside two dedicated sub-networks and keep your lambdas separated from the EC2 instances.
CIDR NOTATION in 1 minute:
- Shorthand for 10.0.0.0–10.0.0.255 => 10.0.0.0/24
- First 24 bits reserved for network address
- Last 8 bits reserved for host address
- 2⁸ = ~ 256 IPs
- First 16 bits reserved for network address
- Last 16 bits reserved for host address
- 2¹⁶ = ~ 65.536 IPs
- 10.0.0.0/32 == ONE IP == 10.0.0.0
- 0.0.0.0/0 == ALL
- Largest CIDR Block you get in aws: /16
- Smallest CIDR Block you get in aws: /28
- Create your VPC using /16
- Create all your subnets using /24
Now having this concepts in mind just recently taken out of the oven, wi will go to to our AWS Console management => under Network & Content Delivery => select VPC option => Click on Create VPC.
Complete the form data and click on Create button. Now you will see your new VPC in your VPC list.
Now in the left side panel click on the menu Subnets.
Click on Create Subnet.
Type a logic name for your public subnet. Select from the VPC dropdown the VPC your just created. In the field of Availability Zone leave it by default.
In our IPv4 CIDR block is where the magic happens, we need to choose a range that falls inside your VPC CIDR block. How this is going to be our public sub-network this range should be the first range behind of the all others sub-networks range CIDR block.
This public subnetwork is now attached to our VPC. Is time to create our two private sub-networks.
This private sub-network will use a CIDR block: 10.0.1.0/24 that falls in our VPC range. You need to select from the VPC dropdown your VPC recently created .
This private sub-network will use a CIDR block: 10.0.2.0/24 that falls in our VPC range. You need to select from the VPC dropdown your VPC recently created .
Public Subnetwork — 10.0.0.0/16
Private Subnetwork #1–10.0.1.0/24
Public Subnetwork #2–10.0.2.0/24
Note: you can use different ranges of CIDR blocks but remembers that must be inside your VPC CIDR block range.
Our next step is to create and configure two Route tables one for our public subnet and other for our private subnetworks. Select in the side menu the menu Route tables.
Click on the Create route table button. Complete the form fields.
We are creating our public route table. In the Dropdown of VPC select your VPC. Click on Create button.
We are creating our private route table. In the Dropdown of VPC select your VPC. Click on Create button.
Now you can see your two recently created routing tables.
Our next step is to associate our public subnetwork with our public-serverless routing table and associate our two private subnetworks with our private-serverless routing table.
Let’s do this. Select your public-serverless routing table. In the bottom section select the Subnet Associations Tab. Click on the Edit subnet associations button.
Now you will see a screen with the list of all your subnetworks inside your VPC.
Select your public subnetwork. In this case is the one with the name of public-serverless. Click on save button.
Now you should be able to see the list of subnetworks associated with your public routing table. Let’s do the same but this time for our private subnetwors. Select the routing table you created for your private sub-network from the list. Click on the Edit subnet associations.
Select only the private subnetworks you created for your lambda function from the list. Click on save button.
You should see how you private subnetworks are associated to your routing table.
Now is time to create our Internet Gateways. In the side menu select the Internet gateway option.
You can see the list of your Internet gateways, these are used to enable internet access to your VPC. Click on Create internet gateway button.
Type a logical name for your gateway. Click on create button.
Now you should see your new internet gateway in the list. Select the dropdown Actions and select the option Attach to VPC.
Now from the dropdown select your VPC and click on Attach button. You should see your internet gateway with the status attached.
Now is time to create our NAT gateway. In the side menu click on the menu NAT Gateway. Click on the Create NAT gateway button.
In the Subnet Field you must select your public subnet to host your NAT Gateway. In the Elastic IP Allocation ID you have to options or create a new one Elastic IP or select one of your list of EIPs. If you select Create New EIP the system will create one new EIP for you and assigns it to your NAT Gateway. Click on Create Nat Gateway button.
Now you should see your recently created NAT Gateway in the list. Probably takes a couple of minutes while your NAT Gateway changes of status from pending to available.
Go back to your route tables section because is time to configure them. But before we start configuring our route tables I want to explain something about them.
Basically what makes a subnet public or private depends on its route table. Every route table has a default route, which determines the next hop for packets that have a public destination.
- Private subnet: the default route points to a NAT gateway (nat-…) or NAT instance (eni-…).
- Public subnet: the default route points to an internet gateway (igw-…).
- 0.0.0.0/0 => Default route
The configuration for our Route tables will be the next:
Private serverless — Route Table
- Our private subnets 10.0.1.0/24 and 10.0.2.0/24 are bound to this route table
- The NAT Gateway is hosted inside our public subnetwork
What does mean this table?.
- If any packets that comes in falls into this CIDR block range 10.0.0./16 it’s going to be mapped to our local VPC. (packets that goes to resources in our private networks)
- If the packet falls outside of our previous CIDR block range It’s going to be mapped to our default route that redirects the packets to our NAT Gateway.
Public serverless — Route Table
- Our public subnet 10.0.0.0/24 is bound to this route table
- If any packets that comes in falls into this CIDR block range 10.0.0./16 it’s going to be mapped to our local VPC. (packets that goes to resources in our public network)
- If the packet falls outside of our previous CIDR block range It’s going to be mapped to our default route that redirect the packets to our Internet Gateway.
We can see how the packets are redirect from one subnetwork to another until find its corresponding destiny.
Our next step is to configure our Route tables following the previous indications.
In the list of route tables select your public route table (public-serverless) and in the bottom section select the routes tab. Click on the Edit routes button.
Click on add route. Type your default route that points to your Internet Gateway then click on Save routes.
You can see how your route table has a new router entry. Now let’s do the same with our other route table bound to our private networks.
Click on add route. Type your default route that points to your NAT Gateway then click on Save routes.
We have finished the most complex part of the process. Let’s move to the next step to grant access to internet to the AWS Lambda function.
4. Grant internet access to the lambda function in a safety way
Go to your Lambda function Section in your AWS Management console and select your lambda function from the list of functions. Scroll down to Network section.
In the field of Virtual Private Cloud (VPC) select the VPC you created for your lambda function. In the subnets field select both private networks. In security groups field select the default one.
This is how your lambda function configuration should looks. Now click on orange save button.
Now we are going to run our second checkpoint. In order to test that everything goes well, scroll up to Designer section and click on the API Gateway trigger and click on the URL that shows here.
If everything is ok you should see a message response from your lambda function. I change the message in the source code of my lambda function.
5. Create the handler object for your Node.js — Restful API
AWS Lambda invokes your Lambda function via a handler object. A handler represents the name of your Lambda function and serves as the entry point that AWS Lambda uses to execute your function code.
In order to create our handler object for our Restful API. We are going to use one of those excellent libraries that makes your like simpler https://github.com/awslabs/aws-serverless-express citing what they said in the repository this library is for:
“Run serverless applications and REST APIs using your existing Node.js application framework, on top of AWS Lambda and Amazon API Gateway”
You must run in your terminal: npm install aws-serverless-express
The key point here is that you already have built a Rest API with node.js, probably you have a server.js or main.js or index.js file that works as the entry point for your application. There are some cases in which you have your app’s configurations and the call to the method app.listen() in the same file.
In this case we need to split this logic between two files, one file named server.js where you start your application calling app.listen() on a specific port and other file named app.js where you configure your routes, middlewares and error middlewares, etc.
Here I give you an example of my three files:
I am attaching an example of my project’s folder structure:
Open the package.json file and add a new script name “build”. This script what does is to zip your code into one just file that you can upload to replace the code of your lambda function.
build: zip -rq ./build.zip * -x .vscode/\\* -x server.js -x ad.lambda.js
Open a terminal and run the next command: npm run build
In the the left side panel in your folder structure you should see a build.zip file that was generated by the previous command. If you open it you will find all the code of your API Rest except the files with the prefix -x. This last parameter what makes is to exclude files from your zip file.
Go to your lambda function again and in the Function Code, in the dropdown Code entry type select the option Upload a .zip file and choose your previous zip file generated.
Don’t forget to change your Handler name file from index.handler to lambda.handler. Click on the orange save button.
Now scroll down to Environment variables section.
This is the place where you configure the Environment variables for your AWS Lambda function. Variables such as api keys, url databases, etc.
You must use the Elastic IP Address attached to your NAT Gateway to enable the access of your Lambda function to your third party services like Amazon RDS or Mongodb Atlas. Several third party services uses a whitelist of IPs to enable the access to their services.
If you go again to the Invoke URL of your API Gateway and send a request to any of the routes mapped in your router of your Rest API you should see a answer direct from your API.
I hope have been of helpful for your learning, that you have understood some of the base concepts and theory behind the process of turning your Restful API into a serverless application and deploying it to AWS Lambda.
If you have any question don’t hesitate in contact me I’ll be willing to help and share.
If you like this tutorial don’t forget to share in your social networks and follow me on twitter, I like to learn by sharing with the community.