DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
The Latest "Software Integration: The Intersection of APIs, Microservices, and Cloud-Based Systems" Trend Report
Get the report
  1. DZone
  2. Software Design and Architecture
  3. Cloud Architecture
  4. AWS Lambda With MySQL (RDS) and API Gateway

AWS Lambda With MySQL (RDS) and API Gateway

Vaquar Khan user avatar by
Vaquar Khan
·
May. 26, 22 · Tutorial
Like (9)
Save
Tweet
Share
39.51K Views

Join the DZone community and get the full member experience.

Join For Free

I have been working on Lambda for some projects, and recently, I had to design and write an FAS service using Lambda functions and read/write data into RDS (MySQL). I'm sharing what I've learned here.

Before We Begin

Prerequisites

This tutorial assumes that you have some knowledge of basic Lambda operations and the AWS console, RDS, IAM, and Node.js.

To understand whether a serverless application is good for you or not, you need to understand the limitations of Lambda, what a cold start is, and how concurrency works in Lambda. The Lambda execution model is, of course, a different architecture than traditional web applications in Spring.

AWS and application architecture

AWS and application architecture

What Is a Cold Start?

When a user starts their first request, Lambda has a slight delay while it spins up a new container and loads our code and dependencies in memory. This is called a cold start. A cold start only happens if there is no idle container available or waiting to run our code. Once a connection is timed out, AWS kills the container, and future requests will again spin up a new container. The first request will always be a bit slower due to the cold start, but subsequent requests will hit the same instance quickly.

You may also enjoy: Querying RDS MySQL DB With NodeJS Lambda Function

We can use a Cloud Watch Timer/dummy request to keep lambdas warm.

Concurrency

Concurrent requests will trigger the creation of new AWS Lambda instances. For example, if you have five concurrent requests to the same Lambda function, AWS will create five containers to serve the requests. In short, when you first invoke a function, AWS Lambda creates an instance of the function and runs its handler method to process the event. If you invoke the function again while the first event is being processed, Lambda creates another instance.

You can configure a function with reserved concurrency to guarantee that it can always reach a certain level of concurrency. This function can run with this maximum amount of concurrency without interrupting or waiting.

The Lambda currency limit is 1000 by default. Take note that one Lambda function that has scaled up can hit the performance of every other Lambda function in the same region.

Concurrency

Concurrency


Reserve concurrency doesn't start until 20 instances on the first Lambda call. Its reserve capacity for a function can scale up or down. As soon as the concurrent executions limit is reached, the next execution gets throttled. 

  • https://aws.amazon.com/blogs/compute/managing-aws-lambda-function-concurrency/

Retry Behavior

Lambda functions will retry three times before they fail due to an uncaught application error. If you added context.succeed and did not handle exceptions properly, Lambda will not retry the function and instead, will assume that the function was successful. If you have added context.fail, Lambda will retry the function.

JavaScript
 




x
11


 
1
module.exports.handler(event, context, callback) {
2
  try {  
3
     // Do you what you want to do.  
4
      return callback(null, 'Success') 
5
 } catch (err) { 
6
     // You probably still want to log it. 
7
     console.error(err) 
8
     // Return fail. 
9
     return callback(null, 'fail') 
10
  }
11
 }



Common Invocation Errors

  • Request – The request event is too large or isn't valid JSON, the function doesn't exist, or a parameter value is of the wrong type.
  • Caller – The user or service doesn't have permission to invoke the function.
  • Account – The maximum number of function instances are already running or requests are being made too quickly.

Debug Lambda

The following are two approaches to debug Lambda on a local machine:

    1. Choose Test at the top right of your Lambda function to bring up a screen that allows you to                      configure a new test that can be run to verify success/failure and you can also add console.log for              debugging.

    2. Another most popular option is Cloudwatch for debugging on Aws console .When you review                  CloudWatch log files or metrics when you're troubleshooting errors, be aware that they are                        displayed or stored in the Region closest to the location where the function executed.

Lambda-local lets you test Amazon Lambda functions on your local machine, by providing a simplistic API and command-line tool.

Shell
 




xxxxxxxxxx
1


 
1
npm install -g lambda-local 



You can use Lambda-local as a command line tool.

Shell
 




xxxxxxxxxx
1


 
1
# Simple usage  lambda-local -l index.js -h handler -e examples/s3-put.js  
2
# Input environment variables  lambda-local -l index.js -h handler -e examples/s3-put.js -E '{"key":"value","key2":"value2"}'  



You can find further information from the following link:

  • https://www.npmjs.com/package/lambda-local.

You can also use SAM Local to develop and test Lambda functions locally with Docker.

You can find further information on following link

  • https://dzone.com/articles/run-aws-lambda-functions-locally-on-windows-machin

Lambda Functions Versioning and Deployment

If you want to publish a new version of a function for QA testing without affecting the stable production version, then you can use Lambda version option. When you choose a new version, the system creates a new version of your Lambda function each time that you publish the function. We can publish multiple versions of a function. Each version can be invoked in parallel in a separate container. By default, the version would be $LATEST.

Choosing version

Choosing version


We can configure blue-green /canary deployment for continuous delivery:

  • https://aws.amazon.com/quickstart/architecture/blue-green-deployment/
  • https://aws.amazon.com/blogs/compute/implementing-canary-deployments-of-aws-lambda-functions-with-alias-traffic-shifting/

Configure RDS 

The first step to start code is to provision an RDS instance using AWS Console. Then, try AWS Free Tier with Amazon RDS. 

MySQL 750 hours of Amazon RDS Single-AZ db.t2.micro Instance usage running MySQL 20 GB of General Purpose (SSD) DB Storage and 20 GB of backup storage for your automated database backups and any user-initiated DB Snapshots

  • https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_Tutorials.WebServerDB.CreateDBInstance.html

Write Your First Lambda Function

When you invoke a function, you can choose to invoke it synchronously or asynchronously. With synchronous invocation, you wait for the function to process the event and return a response. With asynchronous invocation, Lambda queues the event for processing and returns a response immediately. For asynchronous invocation, Lambda handles retries and can send failed events to a dead-letter queue.

You need to create a role for Lambda. As a best practice, define policies that follow the principle of granting least privilege. In other words, the policies include only the permissions that users require to perform their tasks, for learning purpose adding broad role but you can narrow as per your requirements.

  • https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege

AmazonRDSFullAccess

JSON
 




xxxxxxxxxx
1
53


 
1
{ 
2
   "Version":"2012-10-17",
3
   "Statement":[ 
4
      { 
5
         "Action":[ 
6
            "rds:*",
7
            "application-autoscaling:DeleteScalingPolicy",
8
            "application-autoscaling:DeregisterScalableTarget",
9
            "application-autoscaling:DescribeScalableTargets",
10
            "application-autoscaling:DescribeScalingActivities",
11
            "application-autoscaling:DescribeScalingPolicies",
12
            "application-autoscaling:PutScalingPolicy",
13
            "application-autoscaling:RegisterScalableTarget",
14
            "cloudwatch:DescribeAlarms",
15
            "cloudwatch:GetMetricStatistics",
16
            "cloudwatch:PutMetricAlarm",
17
            "cloudwatch:DeleteAlarms",
18
            "ec2:DescribeAccountAttributes",
19
            "ec2:DescribeAvailabilityZones",
20
            "ec2:DescribeInternetGateways",
21
            "ec2:DescribeSecurityGroups",
22
            "ec2:DescribeSubnets",
23
            "ec2:DescribeVpcAttribute",
24
            "ec2:DescribeVpcs",
25
            "sns:ListSubscriptions",
26
            "sns:ListTopics",
27
            "sns:Publish",
28
            "logs:DescribeLogStreams",
29
            "logs:GetLogEvents"
30
         ],
31
         "Effect":"Allow",
32
         "Resource":"*"
33
      },
34
      { 
35
         "Action":"pi:*",
36
         "Effect":"Allow",
37
         "Resource":"arn:aws:pi:*:*:metrics/rds/*"
38
      },
39
      { 
40
         "Action":"iam:CreateServiceLinkedRole",
41
         "Effect":"Allow",
42
         "Resource":"*",
43
         "Condition":{ 
44
            "StringLike":{ 
45
               "iam:AWSServiceName":[ 
46
                  "rds.amazonaws.com",
47
                  "rds.application-autoscaling.amazonaws.com"
48
               ]
49
            }
50
         }
51
      }
52
   ]
53
}



AmazonVPCFullAccess

JSON
 




xxxxxxxxxx
1
152


 
1
{ 
2
   "Version":"2012-10-17",
3
   "Statement":[ 
4
      { 
5
         "Effect":"Allow",
6
         "Action":[ 
7
            "ec2:AcceptVpcPeeringConnection",
8
            "ec2:AcceptVpcEndpointConnections",
9
            "ec2:AllocateAddress",
10
            "ec2:AssignIpv6Addresses",
11
            "ec2:AssignPrivateIpAddresses",
12
            "ec2:AssociateAddress",
13
            "ec2:AssociateDhcpOptions",
14
            "ec2:AssociateRouteTable",
15
            "ec2:AssociateSubnetCidrBlock",
16
            "ec2:AssociateVpcCidrBlock",
17
            "ec2:AttachClassicLinkVpc",
18
            "ec2:AttachInternetGateway",
19
            "ec2:AttachNetworkInterface",
20
            "ec2:AttachVpnGateway",
21
            "ec2:AuthorizeSecurityGroupEgress",
22
            "ec2:AuthorizeSecurityGroupIngress",
23
            "ec2:CreateCustomerGateway",
24
            "ec2:CreateDefaultSubnet",
25
            "ec2:CreateDefaultVpc",
26
            "ec2:CreateDhcpOptions",
27
            "ec2:CreateEgressOnlyInternetGateway",
28
            "ec2:CreateFlowLogs",
29
            "ec2:CreateInternetGateway",
30
            "ec2:CreateNatGateway",
31
            "ec2:CreateNetworkAcl",
32
            "ec2:CreateNetworkAcl",
33
            "ec2:CreateNetworkAclEntry",
34
            "ec2:CreateNetworkInterface",
35
            "ec2:CreateNetworkInterfacePermission",
36
            "ec2:CreateRoute",
37
            "ec2:CreateRouteTable",
38
            "ec2:CreateSecurityGroup",
39
            "ec2:CreateSubnet",
40
            "ec2:CreateTags",
41
            "ec2:CreateVpc",
42
            "ec2:CreateVpcEndpoint",
43
            "ec2:CreateVpcEndpointConnectionNotification",
44
            "ec2:CreateVpcEndpointServiceConfiguration",
45
            "ec2:CreateVpcPeeringConnection",
46
            "ec2:CreateVpnConnection",
47
            "ec2:CreateVpnConnectionRoute",
48
            "ec2:CreateVpnGateway",
49
            "ec2:DeleteCustomerGateway",
50
            "ec2:DeleteDhcpOptions",
51
            "ec2:DeleteEgressOnlyInternetGateway",
52
            "ec2:DeleteFlowLogs",
53
            "ec2:DeleteInternetGateway",
54
            "ec2:DeleteNatGateway",
55
            "ec2:DeleteNetworkAcl",
56
            "ec2:DeleteNetworkAclEntry",
57
            "ec2:DeleteNetworkInterface",
58
            "ec2:DeleteNetworkInterfacePermission",
59
            "ec2:DeleteRoute",
60
            "ec2:DeleteRouteTable",
61
            "ec2:DeleteSecurityGroup",
62
            "ec2:DeleteSubnet",
63
            "ec2:DeleteTags",
64
            "ec2:DeleteVpc",
65
            "ec2:DeleteVpcEndpoints",
66
            "ec2:DeleteVpcEndpointConnectionNotifications",
67
            "ec2:DeleteVpcEndpointServiceConfigurations",
68
            "ec2:DeleteVpcPeeringConnection",
69
            "ec2:DeleteVpnConnection",
70
            "ec2:DeleteVpnConnectionRoute",
71
            "ec2:DeleteVpnGateway",
72
            "ec2:DescribeAccountAttributes",
73
            "ec2:DescribeAddresses",
74
            "ec2:DescribeAvailabilityZones",
75
            "ec2:DescribeClassicLinkInstances",
76
            "ec2:DescribeCustomerGateways",
77
            "ec2:DescribeDhcpOptions",
78
            "ec2:DescribeEgressOnlyInternetGateways",
79
            "ec2:DescribeFlowLogs",
80
            "ec2:DescribeInstances",
81
            "ec2:DescribeInternetGateways",
82
            "ec2:DescribeKeyPairs",
83
            "ec2:DescribeMovingAddresses",
84
            "ec2:DescribeNatGateways",
85
            "ec2:DescribeNetworkAcls",
86
            "ec2:DescribeNetworkInterfaceAttribute",
87
            "ec2:DescribeNetworkInterfacePermissions",
88
            "ec2:DescribeNetworkInterfaces",
89
            "ec2:DescribePrefixLists",
90
            "ec2:DescribeRouteTables",
91
            "ec2:DescribeSecurityGroupReferences",
92
            "ec2:DescribeSecurityGroups",
93
            "ec2:DescribeStaleSecurityGroups",
94
            "ec2:DescribeSubnets",
95
            "ec2:DescribeTags",
96
            "ec2:DescribeVpcAttribute",
97
            "ec2:DescribeVpcClassicLink",
98
            "ec2:DescribeVpcClassicLinkDnsSupport",
99
            "ec2:DescribeVpcEndpointConnectionNotifications",
100
            "ec2:DescribeVpcEndpointConnections",
101
            "ec2:DescribeVpcEndpoints",
102
            "ec2:DescribeVpcEndpointServiceConfigurations",
103
            "ec2:DescribeVpcEndpointServicePermissions",
104
            "ec2:DescribeVpcEndpointServices",
105
            "ec2:DescribeVpcPeeringConnections",
106
            "ec2:DescribeVpcs",
107
            "ec2:DescribeVpnConnections",
108
            "ec2:DescribeVpnGateways",
109
            "ec2:DetachClassicLinkVpc",
110
            "ec2:DetachInternetGateway",
111
            "ec2:DetachNetworkInterface",
112
            "ec2:DetachVpnGateway",
113
            "ec2:DisableVgwRoutePropagation",
114
            "ec2:DisableVpcClassicLink",
115
            "ec2:DisableVpcClassicLinkDnsSupport",
116
            "ec2:DisassociateAddress",
117
            "ec2:DisassociateRouteTable",
118
            "ec2:DisassociateSubnetCidrBlock",
119
            "ec2:DisassociateVpcCidrBlock",
120
            "ec2:EnableVgwRoutePropagation",
121
            "ec2:EnableVpcClassicLink",
122
            "ec2:EnableVpcClassicLinkDnsSupport",
123
            "ec2:ModifyNetworkInterfaceAttribute",
124
            "ec2:ModifySubnetAttribute",
125
            "ec2:ModifyVpcAttribute",
126
            "ec2:ModifyVpcEndpoint",
127
            "ec2:ModifyVpcEndpointConnectionNotification",
128
            "ec2:ModifyVpcEndpointServiceConfiguration",
129
            "ec2:ModifyVpcEndpointServicePermissions",
130
            "ec2:ModifyVpcPeeringConnectionOptions",
131
            "ec2:ModifyVpcTenancy",
132
            "ec2:MoveAddressToVpc",
133
            "ec2:RejectVpcEndpointConnections",
134
            "ec2:RejectVpcPeeringConnection",
135
            "ec2:ReleaseAddress",
136
            "ec2:ReplaceNetworkAclAssociation",
137
            "ec2:ReplaceNetworkAclEntry",
138
            "ec2:ReplaceRoute",
139
            "ec2:ReplaceRouteTableAssociation",
140
            "ec2:ResetNetworkInterfaceAttribute",
141
            "ec2:RestoreAddressToClassic",
142
            "ec2:RevokeSecurityGroupEgress",
143
            "ec2:RevokeSecurityGroupIngress",
144
            "ec2:UnassignIpv6Addresses",
145
            "ec2:UnassignPrivateIpAddresses",
146
            "ec2:UpdateSecurityGroupRuleDescriptionsEgress",
147
            "ec2:UpdateSecurityGroupRuleDescriptionsIngress"
148
         ],
149
         "Resource":"*"
150
      }
151
   ]
152
}



AWSLambdaVPCAccessExecutionRole

JSON
 




xxxxxxxxxx
1
17


 
1
{ 
2
   "Version":"2012-10-17",
3
   "Statement":[ 
4
      { 
5
         "Effect":"Allow",
6
         "Action":[ 
7
            "logs:CreateLogGroup",
8
            "logs:CreateLogStream",
9
            "logs:PutLogEvents",
10
            "ec2:CreateNetworkInterface",
11
            "ec2:DescribeNetworkInterfaces",
12
            "ec2:DeleteNetworkInterface"
13
         ],
14
         "Resource":"*"
15
      }
16
   ]
17
}



permission policies

Permission policies


To create a Lambda function, go to AWS Console and select Lambda.

Creating a Lambda function

Creating a Lambda function


Click create function and choose Node.js 12.x. Then, choose existing role we created above.

creating a function

In order to support a MySQL dependency, we need to create code first on your local computer and then upload it to the Lambda console.

Create a folder and create package.json

Shell
 




xxxxxxxxxx
1


 
1
npm init


creating package.json file

Creating package.json file


Once the file is created, you can find the following JSON in the folder.

JSON
 




xxxxxxxxxx
1
11


 
1
{ 
2
   "name":"test",
3
   "version":"1.0.0",
4
   "description":"test",
5
   "main":"index.js",
6
   "scripts":{ 
7
      "test":"echo \"Error: no test specified\" && exit 1"
8
   },
9
   "author":"Vaquar khan",
10
   "license":"ISC"
11
}



You need to add MYSQL node dependency in project using following command

Shell
 




xxxxxxxxxx
1


 
1
npm install --save mysql 



Now, add a handler into the app, create index.js (index.handler), and add Lambda logic.

In Lambda, first, we are going to create a connection object and then call our database.

JavaScript
 




xxxxxxxxxx
1
18


 
1
const mysql = require('mysql'); 
2

          
3
const connection = mysql.createConnection({ 
4
 //following param coming from aws lambda env variable 
5
  host: process.env.RDS_LAMBDA_HOSTNAME,  
6
  user: process.env.RDS_LAMBDA_USERNAME, 
7
  password: process.env.RDS_LAMBDA_PASSWORD, 
8
  port: process.env.RDS_LAMBDA_PORT, 
9
  // calling direct inside code  
10
  connectionLimit: 10,   
11
  multipleStatements: true,
12
 // Prevent nested sql statements 
13
  connectionLimit: 1000,   
14
connectTimeout: 60 * 60 * 1000, 
15
  acquireTimeout: 60 * 60 * 1000, 
16
  timeout: 60 * 60 * 1000, 
17
  debug: true 
18
});



Then, we need to call our Lambda handler.

JavaScript
 




xxxxxxxxxx
1
30


 
1
exports.handler = async (event) => { 
2
  try {    
3
 const data = await new Promise((resolve, reject) => {
4
       connection.connect(function (err) {   
5
      if (err) {      
6
     reject(err);     
7
    }        
8
 connection.query('CREATE DATABASE testdb', function (err, result) {  
9
         if (err) {  
10
           console.log("Error->" + err);     
11
        reject(err);        
12
   }         
13
  resolve(result);  
14
       });     
15
  })  
16
   }); 
17

          
18
    return { 
19
      statusCode: 200,  
20
     body: JSON.stringify(data)   
21
  } 
22

          
23
  } catch (err) {    
24
 return {   
25
    statusCode: 400,   
26
    body: err.message 
27
    } 
28
  }
29
 }; 
30

          



Now, create a zip file and upload it.

uploading zip file

Uploading zip file



After this, upload and click on index.js. For further changes, use inline editor.

using inline editor

Using inline editor


Create a lambda env variable with its key-value pairs. 

Java
 




xxxxxxxxxx
1


 
1
 RDS_LAMBDA_HOSTNAME 
2
 RDS_LAMBDA_USERNAME 
3
 RDS_LAMBDA_PASSWORD 
4
 RDS_LAMBDA_PORT



Now, configure Lambda with RDS and VPC,  go to the Security group of the RDS instance. After selecting the default security group,  click on it. On the EC2 page, scroll down to find inbound and outbound settings.

In inbound settings, click edit. You can change the IP here.

  • 0.0.0.0/0 — this makes RDS open to the world and is not recommended.
  • Configure VPC inside the Lambda function network to Lambda function work. First, go to the Lambda function, click on Network, and then select the VPC and copy the IP address. If no VPC is selected, select a VPC that's the as the DB function and copy the IP address. Add this IP in RDS inbound settings.

Asynch-rds-create-table

Asych RDS create table


Save it and test your Lambda function.

Results

RDS output

RDS output


The following are a few Lambda handlers to understand how CRUD operations work in Lambda.

Create a database using lambda

 

JavaScript
 




xxxxxxxxxx
1
46


 
1
const mysql = require('mysql'); 
2

          
3
const connection = mysql.createConnection({ 
4
 //following param coming from aws lambda env variable  
5

          
6
 host: process.env.RDS_LAMBDA_HOSTNAME,
7
  user: process.env.RDS_LAMBDA_USERNAME,
8
  password: process.env.RDS_LAMBDA_PASSWORD, 
9
  port: process.env.RDS_LAMBDA_PORT, 
10
 // calling direct inside code 
11
  connectionLimit: 10,  
12
 multipleStatements: true,
13
// Prevent nested sql statements 
14
  connectionLimit: 1000, 
15
  connectTimeout: 60 * 60 * 1000,
16
   acquireTimeout: 60 * 60 * 1000,  
17
 timeout: 60 * 60 * 1000,  
18
 debug: true 
19
}); exports.handler = async (event) => {  
20
 try {    
21
 const data = await new Promise((resolve, reject) => {  
22
     connection.connect(function (err) {  
23
       if (err) {    
24
       reject(err);
25
         }      
26
   connection.query('CREATE DATABASE testdb',
27
 function (err, result) {  
28
         if (err) {  
29
           console.log("Error->" + err);      
30
       reject(err);        
31
   }           resolve(result);  
32
       });     
33
  })   
34
  }); 
35

          
36
    return {  
37
     statusCode: 200,   
38
    body: JSON.stringify(data)  
39
   } 
40

          
41
  } catch (err) {
42
     return {   
43
    statusCode: 400, 
44
      body: err.message   
45
  }  
46
 } }; 



Create a table using lambda   

JavaScript
 




xxxxxxxxxx
1
57


 
1
exports.handler = async (event) => {   
2
const sql = "CREATE TABLE MESSAGE (message VARCHAR(255))";  
3
 con.query(sql, function (err, result) {   
4
  if (err) throw err;  
5
   console.log("Table created");  
6
 });   
7
return "Table Created" 
8
}; 
9

          
10
const mysql = require('mysql'); 
11

          
12
const connection = mysql.createConnection({ 
13
 //following param coming from aws lambda env variable  
14
  host: process.env.RDS_LAMBDA_HOSTNAME, 
15
  user: process.env.RDS_LAMBDA_USERNAME,  
16
  password: process.env.RDS_LAMBDA_PASSWORD, 
17
  port: process.env.RDS_LAMBDA_PORT, 
18
 // calling direct inside code
19
  connectionLimit: 10,   
20
  multipleStatements: true,
21
  // Prevent nested sql statements   
22
  connectionLimit: 1000, 
23
  connectTimeout: 60 * 60 * 1000, 
24
  acquireTimeout: 60 * 60 * 1000,
25
  timeout: 60 * 60 * 1000,
26
   debug: true 
27
}); exports.handler = async (event) => { 
28
  try {    
29
 const data = await new Promise((resolve, reject) => { 
30
      connection.connect(function (err) {     
31
    if (err) {       
32
    reject(err);    
33
     }      
34
   connection.query('CREATE TABLE Employee (message VARCHAR(255))', 
35
function  (err, result) { 
36
          if (err) {    
37
         console.log("Error->" + err);  
38
         reject(err);
39
      }
40
           resolve(result);        
41
    });     
42
   })    
43
 }); 
44

          
45
    return {   
46
    statusCode: 200, 
47
      body: JSON.stringify(data)   
48
  } 
49

          
50
  } catch (err) {   
51
  return {    
52
   statusCode: 400,    
53
   body: err.message 
54
    }  
55
 }
56
 }; 
57

          


   

Insert records using lambda

 

JavaScript
 




xxxxxxxxxx
1
12


 
1
exports.handler = (event, context, callback) => {  
2
 // allows for using callbacks as finish/error-handlers  
3
 context.callbackWaitsForEmptyEventLoop = false;  
4
 const sql = "insert into testdb.Employee values(1,'Vaquar khan');";  
5
 con.query(sql, (err, res) => { 
6
    if (err) {   
7
    throw err   
8
  }     
9
callback(null, '1 records inserted.');  
10
 }) 
11
}; 
12

          



Select records using lambda  

JavaScript
 




xxxxxxxxxx
1
10
9


 
1
exports.handler = (event, context, callback) => {   
2
// allows for using callbacks as finish/error-handlers   
3
context.callbackWaitsForEmptyEventLoop = false; 
4
const sql = "select * from testdb.Employee "; 
5
con.query(sql, function (err, result) {   
6
  if (err) throw err;     
7
  callback(null, result)  
8
 });
9
 }; 


 

Select records with criteria using lambda 

JavaScript
 




xxxxxxxxxx
1


 
1
exports.handler = (event, context, callback) => { 
2
  // allows for using callbacks as finish/error-handlers  
3
 context.callbackWaitsForEmptyEventLoop = false; 
4
 const sql = "select * from  testdb.Employee where emp_id = " + event.emp_id;  
5
 con.query(sql, function (err, result) { 
6
    if (err) throw err;     callback(null, result)  
7
 }); 
8
};

 


Final Project

Now, we're down to the actual meat-and-potatoes of what we're trying to do:

Create a Table

MySQL
 




xxxxxxxxxx
1


 
1
use testdb; 
2

          
3
CREATE TABLE `Employee` ( 
4
  `emp_id` int(11) unsigned NOT NULL AUTO_INCREMENT, 
5
  `emp_name` varchar(100) DEFAULT NULL,      PRIMARY KEY (`emp_id`)    ) ENGINE=InnoDB DEFAULT CHARSET=latin1; 
6

          
7
insert into Employee values(1,'Vaquar khan'); 
8
insert into Employee values(2,'Zidan khan'); 



Create a Lambda 

JavaScript
 




xxxxxxxxxx
1
28


 
1
const mysql = require('mysql'); 
2

          
3
const con = mysql.createConnection({ 
4
   host: process.env.LAMBDA_HOSTNAME,  
5
   user: process.env.LAMBDA_USERNAME,
6
   password: process.env.LAMBDA_PASSWORD, 
7
   port: process.env.LAMBDA_PORT,  
8
   connectionLimit: 10,  
9
   multipleStatements: true,
10
   // Prevent nested sql statements  
11
   connectionLimit: 1000, 
12
   connectTimeout: 60 * 60 * 1000, 
13
   acquireTimeout: 60 * 60 * 1000, 
14
   timeout: 60 * 60 * 1000,
15
   debug: true,  
16
   database:'testdb' 
17
}); 
18

          
19
exports.handler = (event, context, callback) => {  
20
   console.log('inside lambda...'+event.emp_id) 
21
  // allows for using callbacks as finish/error-handlers 
22
  context.callbackWaitsForEmptyEventLoop = false; 
23
  const sql = "select * from Employee where emp_id = " + event.emp_id;  
24
  con.query(sql, function (err, result) {   
25
  if (err) throw err; 
26
    callback(null, result)
27
   }); 
28
}; 


 

Create a Test Event

JSON
 




xxxxxxxxxx
1


 
1
{ "emp_id":1, "emp_name":"xyz" }



Create an API Gateway

The number of APIs per account limit is 600 regional APIs, 600 private APIs, and 120 edge APIs. Now, you can create and import regional and private APIs at a rate of one request every three seconds and deploy APIs at a rate of one request every five seconds.

Note, when you deploy an API to API Gateway, throttling is enabled by default in the stage configurations.

For the time being, in this tutorial, we are not implementing security on the API gateway, but it's mandatory to add security on gateway.

The following mechanisms can be used for authentication and authorization of the API gateway:

  • Resource policies let you create resource-based policies to allow or deny access to your APIs and methods from specified source IP addresses or VPC endpoints. For more information, see Control Access to an API with Amazon API Gateway Resource Policies.
  • Standard AWS IAM roles and policies offer flexible and robust access controls that can be applied to an entire API or individual methods. IAM roles and policies can be used for controlling who can create and manage your APIs as well as who can invoke them. For more information, see Control Access to an API with IAM Permissions.
  • IAM tags can be used together with IAM policies to control access. For more information, see Using Tags to Control Access to API Gateway Resources.
  • Endpoint Policies for Interface VPC Endpoints allow you to attach IAM resource policies to interface VPC endpoints to improve the security of your private APIs. For more information, see Use VPC Endpoint Policies for Private APIs in API Gateway.
  • Lambda authorizers are Lambda functions that control access to REST API methods using bearer token authentication as well as information described by headers, paths, query strings, stage variables, or context variables request parameters. Lambda authorizers are used to control who can invoke REST API methods. For more information, see Use API Gateway Lambda Authorizers.
  • Amazon Cognito user pools let you create customizable authentication and authorization solutions for your REST APIs. Amazon Cognito user pools are used to control who can invoke REST API methods. For more information, see Control Access to a REST API Using Amazon Cognito User Pools as Authorizer
  • Secure key for API
  • https://docs.aws.amazon.com/apigateway/latest/developerguide/limits.html


Create a Resource

creating a resource

Creating a resource


Create Method add GET

creating a method

Creating a method



adding GET

Adding GET



Deploy an API

Create a new stage and deploy the API. After successfully deploying, you can see the URL.

Test Lambda with API gateway

Download Postman or use the Postman Chrome extension to call the API.

Summary

In this post, we discussed how to create applications quickly to run in AWS Lambda, which provides low cost, zero maintenance compute, and automatically scales. We also discussed the limitations of Lambda and how to design simple micro-service using AWS API gateway, and RDS. In the next post, we will try to cover AWS Cognito for Authentication/Authorization and how to sync Cognito data into an RDS table.

Further Reading

Dealing With Serverless Cold Starts, Once and For All!

A Simple API Using AWS RDS, Lambda, and API Gateway



API AWS AWS Lambda MySQL Database Requests Docker (software) JavaScript Virtual private cloud

Published at DZone with permission of Vaquar Khan. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Comparing Map.of() and New HashMap() in Java
  • Specification by Example Is Not a Test Framework
  • Distributed Tracing: A Full Guide
  • mTLS Everywere

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: