This is a Tidbit, basically whenever you see
Tidbit:
in the title,
it means I am going to simply throw some helpful code without
explaining too much around it.
What will you be able to do after going through this?
Build & deploy a REST API on AWS Lambda using nodeJS which uses AWS API gateway as its front and AWS Dynamo DB as its storage. We will deploy the Lambda function using the Serverless framework, if you don’t know what this is, I recommend you familiar with it using this article of mine to get started with Serverless framework on AWS.
What will it look like?
The API will have two Lambda functions running, one for creating an entity called Domain
and the other for retrieving it.
The code
- Create a new directory for your project
- Run
npm init #follow the guide to create package.json
npm install serverless -g
installs the serverless framework globally.serverless create --template aws-nodejs --path domain
Creates a directory calleddomain
and creates aserverless.yml
file in it with default values for a nodeJS project.- Delete the default
handler.js
file created and instead create two new files calledget.js
andput.js
in thedomain
directory.
get.js
'use strict'; var AWS = require('aws-sdk'), uuid = require('uuid'), dynamoClient = new AWS.DynamoDB.DocumentClient(); module.exports.domainget = (event, context, callback) => { var params = { Key: { "Id": event.queryStringParameters.id, }, TableName : process.env.dynamoTableName }; dynamoClient.get(params, function(err, data){ var response; if (err){ response = getErrorResponse(event, err); } else{ response = getSuccessResponse(data); } callback(null, response); }); }; var getSuccessResponse = function (data){ console.log("Retrieved domain with id: " + data.id) var response = { statusCode: 200, body: JSON.stringify(data) }; return response; } var getErrorResponse = function (input, err){ console.log({ input: input, err: err }); var response = { statusCode: 500, body: JSON.stringify({ message: err, input: input }) }; return response; }
The request and response follows the AWS API gateway expectations for Lambda response expectations.
The Lambda function stops executions after you call the callback
function passed to the JS function via the Lambda runtime.
The rest of the code should be self-explanatory.
put.js
'use strict'; var AWS = require('aws-sdk'), uuid = require('uuid'), dynamoClient = new AWS.DynamoDB.DocumentClient(); module.exports.domainput = (event, context, callback) => { var id = uuid.v1(); var body = JSON.parse(event.body); var params = { Item : { "Id": id, "Name": body.name, "Desc": body.desc }, TableName : process.env.dynamoTableName }; dynamoClient.put(params, function(err, data){ var response; if (err){ response = getErrorResponse(event, err); } else{ response = getSuccessResponse(id, event); } callback(null, response); }); }; var getSuccessResponse = function (id, input){ console.log("Created domain with id: " + id) var response = { statusCode: 200, body: JSON.stringify({ location: "/domains/get/" + id, input: input }) }; return response; } var getErrorResponse = function (input, err){ console.log({ input: input, err: err }); var response = { statusCode: 500, body: JSON.stringify({ message: err, input: input }) }; return response; }
serverless.yml
service: domains provider: name: aws runtime: nodejs6.10 region: us-east-1 environment: dynamoTableName: ${opt:stage}-domains iamRoleStatements: - Effect: Allow Action: - dynamodb:Query - dynamodb:Scan - dynamodb:GetItem - dynamodb:PutItem - dynamodb:UpdateItem - dynamodb:DeleteItem Resource: "arn:aws:dynamodb:${opt:region, self:provider.region}:*:table/${self:provider.environment.dynamoTableName}" package: include: - get.js - put.js # exclude: # - exclude-me.js # - exclude-me-dir/** functions: domainget: handler: get.domainget events: - http: path: domains method: get domainput: handler: put.domainput events: - http: path: domains method: put resources: Resources: usersTable: Type: AWS::DynamoDB::Table Properties: TableName: ${opt:stage}-domains AttributeDefinitions: - AttributeName: Id AttributeType: S KeySchema: - AttributeName: Id KeyType: HASH ProvisionedThroughput: ReadCapacityUnits: 1 WriteCapacityUnits: 1
Deploy the code
You should have your AWS credentials configured on the machine with enough access to create IAM roles, S3 bucket (for Lambda code upload and serverless bucket creation), ability to create Cloudformation scripts, API gateway creation, Lambda creation & Dynamo DB creation.
Everything this creates will lie in the AWS free tier if you qualify for it, remember, you are responsible for your costs though.
Run the following commands:
cd domain #will create the get & put lambda functions, api gateway & dynamo db table to store domains serverless deploy --region us-east-1 --stage dev
Try the service
Note the API gateway endpoint created in the deploy
step above, it should be present in the output. In case you don’t have the output anymore, go to AWS console and get the API URL from the API Gateway part of the console.
Example:
Create a domain
Request:
PUT https://2w31hwi1f6.execute-api.us-east-1.amazonaws.com/dev/domains HTTP/1.1 User-Agent: Fiddler Host: 2w31hwi1f6.execute-api.us-east-1.amazonaws.com Content-Length: 57 { "name": "a domain", "desc": "some description" }
Response:
HTTP/1.1 200 OK Content-Type: application/json Content-Length: 1571 Connection: keep-alive Date: Mon, 26 Mar 2018 09:10:22 GMT x-amzn-RequestId: 839271de-30d5-11e8-99e5-75b6d1ec532c x-amz-apigw-id: EWHX0Fq3IAMFSHg= X-Amzn-Trace-Id: sampled=0;root=1-5ab8b8fe-29ea1c26fe1c5797c9d33d25 X-Cache: Miss from cloudfront Via: 1.1 622984f77dccd480b1b655dc4625dd24.cloudfront.net (CloudFront) X-Amz-Cf-Id: -YALvHLfr2WlmRHcHjakoQiApkVSO_jilEoXZYzjjpz64t45SqcwSQ== {"location":"/domains/get/83990110-30d5-11e8-b030-3585da8b8c33","input":{"resource":"/domains","path":"/domains","httpMethod":"PUT","headers":{"CloudFront-Forwarded-Proto":"https","CloudFront-Is-Desktop-Viewer":"true","CloudFront-Is-Mobile-Viewer":"false","CloudFront-Is-SmartTV-Viewer":"false","CloudFront-Is-Tablet-Viewer":"false","CloudFront-Viewer-Country":"IN","Host":"2w31hwi1f6.execute-api.us-east-1.amazonaws.com","User-Agent":"Fiddler","Via":"1.1 622984f77dccd480b1b655dc4625dd24.cloudfront.net (CloudFront)","X-Amz-Cf-Id":"tH9mAyUJ7zUwvZ8M0UdjNe-DeKeRt7FQC4bRfGVZ5vWPYv-MKcCpNA==","X-Amzn-Trace-Id":"Root=1-5ab8b8fe-8604b2b42c3fbe7678040f00","X-Forwarded-For":"114.143.135.82, 54.182.245.48","X-Forwarded-Port":"443","X-Forwarded-Proto":"https"},"queryStringParameters":null,"pathParameters":null,"stageVariables":null,"requestContext":{"resourceId":"wrhq1m","resourcePath":"/domains/put","httpMethod":"PUT","extendedRequestId":"EWHX0Fq3IAMFSHg=","requestTime":"26/Mar/2018:09:10:22 +0000","path":"/dev/domains/put","accountId":"522390200088","protocol":"HTTP/1.1","stage":"dev","requestTimeEpoch":1522055422838,"requestId":"839271de-30d5-11e8-99e5-75b6d1ec532c","identity":{"cognitoIdentityPoolId":null,"accountId":null,"cognitoIdentityId":null,"caller":null,"sourceIp":"114.143.135.82","accessKey":null,"cognitoAuthenticationType":null,"cognitoAuthenticationProvider":null,"userArn":null,"userAgent":"Fiddler","user":null},"apiId":"2w31hwi1f6"},"body":"{\r\n \"name\": \"a domain\",\r\n \"desc\": \"some description\"\r\n}","isBase64Encoded":false}}
Get the created domain:
Request:
GET https://2w31hwi1f6.execute-api.us-east-1.amazonaws.com/dev/domains/?id=83990110-30d5-11e8-b030-3585da8b8c33 HTTP/1.1 User-Agent: Fiddler Host: 2w31hwi1f6.execute-api.us-east-1.amazonaws.com Content-Length: 0
Response:
HTTP/1.1 200 OK Content-Type: application/json Content-Length: 98 Connection: keep-alive Date: Mon, 26 Mar 2018 09:13:11 GMT x-amzn-RequestId: e80db607-30d5-11e8-8d33-a506aa878829 x-amz-apigw-id: EWHyKF1zIAMFQeQ= X-Amzn-Trace-Id: sampled=0;root=1-5ab8b9a7-2dcc0c49e6716d5701fe8cea X-Cache: Miss from cloudfront Via: 1.1 622984f77dccd480b1b655dc4625dd24.cloudfront.net (CloudFront) X-Amz-Cf-Id: 3uxvpW74GzyJG4BGgUCrgyh1pc_lEobzl5zfAjku2kPS7PWYX24Ftw== {"Item":{"Desc":"some description","Id":"83990110-30d5-11e8-b030-3585da8b8c33","Name":"a domain"}}
Remove deployment
Run the following:
# assumption: start from root folder cd domain serverless remove --region us-east-1 --stage dev
That’s it.
If you liked this article, you can choose to follow this blog/subscribe to email alerts (floating follow button {bottom-right} or below comments in mobile) so that you know when any future posts come about.
Pingback: 1 – Getting started with AWS Lambda function using nodeJS
Will share this article with my professor.
LikeLiked by 1 person
Thhis is great
LikeLike