Deploy a Function to Lambda Using the Node.js AWS SDK

The AWS API has an endpoint for deploying a function on Lambda. With a little bit of work, you can upload a Lambda function using the AWS SDK for Node.js. Here's how you can upload and run a Lambda function in 3 steps:

1. Upload the Function Bundle to S3

Unfortunately, the AWS API requires you to store your bundled Lambda function as a .zip file on S3, and that S3 bucket needs to be in the same AWS region as your Lambda function.

You can read more about uploading objects to S3 in Node.js here. Here's the abridged version.

First, suppose you have a simple test.js file that contains a handler function:

exports.handler = async function ( event, context ) { return { statusCode : 200 , body : 'Hello, World' }; };

Lambda will execute this function for you and return "Hello World". But first, you need to archive this test.js file into a .zip file and upload it to S3. To bundle a zip file, you can use the adm-zip package on npm:

const AdmZip = require ( 'adm-zip' ); const AWS = require ( 'aws-sdk' ); const file = new AdmZip(); file.addFile( 'test.js' , Buffer.from( ` exports.handler = async function(event, context) { return { statusCode: 200, body: 'Hello, World' }; }; ` )); file.writeZip( './test.zip' ); AWS.config.update({ accessKeyId : process.env.AWS_ACCESS_KEY_ID, secretAccessKey : process.env.AWS_SECRET_ACCESS_KEY, region : 'us-east-1' }); const s3 = new AWS.S3(); await new Promise ( ( resolve, reject ) => { s3.upload({ Bucket : awsBucket, Body: fs.createReadStream( './test.zip' ), Key : 'test.zip' }, (err, data) => err == null ? resolve(data) : reject(err)); });

2. Create a Lambda Function

Now that the file is on S3, you can create a Lambda function and invoke it using the AWS.Lambda() helper:

const AWS = require ( 'aws-sdk' ); const promisify = require ( 'util' ).promisify; AWS.config.update({ accessKeyId : process.env.AWS_ACCESS_KEY_ID, secretAccessKey : process.env.AWS_SECRET_ACCESS_KEY, region : 'us-east-1' }); const lambda = new AWS.Lambda(); const opts = { FunctionName : 'nodetest' , Runtime : 'nodejs12.x' , Role: 'add actual role that starts with `arn:aws:iam::` here' , Handler: 'test.handler' , Code : { 'S3Bucket' : awsBucket, 'S3Key' : 'test.zip' } }; const fn = await promisify(lambda.createFunction).call(lambda, opts); functionArn = fn.FunctionArn; await promisify(lambda.addPermission).call(lambda, { FunctionName : 'nodetest' , StatementId : 'doesntmatter' , Action : 'lambda:InvokeFunction' , Principal : 'apigateway.amazonaws.com' }); const res = await promisify(lambda.invoke).call(lambda, { FunctionName : 'nodetest' }); res.Payload;

For convenience, the above code uses Node.js' util.promisify() helper, since the AWS SDK doesn't currently support promises. Learn more about util.promisify() here.

3. Create an API Gateway to Access the Function via HTTP

So now you have a Lambda function that you can invoke via the AWS SDK. But what about invoking it via HTTP? That's what you need the AWS API Gateway API for. You need to create a new REST API and add an integration to it.

Step by step, you need to:

Create a new REST API Add a resource to the REST API Add a GET method to the resource Hook up the GET method to call Lambda

Here's the full script:

this .timeout( 5000 ); const AWS = require ( 'aws-sdk' ); const promisify = require ( 'util' ).promisify; AWS.config.update({ accessKeyId : process.env.AWS_ACCESS_KEY_ID, secretAccessKey : process.env.AWS_SECRET_ACCESS_KEY, region : 'us-east-1' }); const gateway = new AWS.APIGateway(); const api = await promisify(gateway.createRestApi).call(gateway, { name : 'My Test API' }); const restApiId = api.id; const resources = await promisify(gateway.getResources).call(gateway, { restApiId }); const resource = await promisify(gateway.createResource).call(gateway, { restApiId, parentId: resources.items[ 0 ].id, pathPart : 'test' }); await promisify(gateway.putMethod).call(gateway, { restApiId, resourceId : resource.id, httpMethod : 'GET' , authorizationType : 'NONE' }); await promisify(gateway.putIntegration).call(gateway, { restApiId, resourceId : resource.id, httpMethod : 'GET' , integrationHttpMethod : 'POST' , type : 'AWS_PROXY' , uri : `arn:aws:apigateway:us-east-1:lambda:path//2015-03-31/functions/ ${functionArn} /invocations` }); await promisify(gateway.createDeployment).call(gateway, { restApiId, stageName : 'prod' }); await promisify(gateway.putMethodResponse).call(gateway, { restApiId, resourceId : resource.id, httpMethod : 'GET' , statusCode : '200' }); await promisify(gateway.putIntegrationResponse).call(gateway, { restApiId, resourceId : resource.id, httpMethod : 'GET' , statusCode : '200' }); const axios = require ( 'axios' ); const res = await axios.get( `https:// ${api.id} .execute-api.us-east-1.amazonaws.com/prod/test` ); res.data;

More Node Tutorials