--- type: article title: 'AWS CLI Lambda Function' date: '2023-03-13T06:27:40.912Z' slug: 'node-lambda-cli' image: name: 'lambda-cli.png' width: 1280 height: 720 status: 'published' description: "In this tutorial we will learn how to use the AWS cli to deploy a serverless node.js application using AWS Lambda and AWS API Gateway." tags: ['AWS', 'Lambda', "Serverless", "aws cli", "Infrastructure as code", "iac"] --- In this tutorial we will learn how to use the AWS cli to deploy a serverless node.js application using AWS Lambda and AWS API Gateway. Before we get started, I want to be honest with you. This may not be the most ideal way of doing things, but it's always helpful to understand the basics before diving into more advanced tools like terraform, serverless framework, SAM, AWS CDK, and others. Don't worry, I'll be covering some of those tools in future tutorials, but for now, let's enjoy the learning experience and appreciate the fundamentals of deploying a serverless application with AWS CLI. ## AWS CLI AWS CLI is a command line tool that allows you to interact with AWS services from, you guessed it, the command line. It's a great tool to have in your arsenal, and setting it up is usually the first step before using any infrastructure as code tool. If you haven't already, follow my tutorial on how to install and configure the AWS CLI. ## Node.js Lambda Function We'll start by creating a basic node function that just returns a "Hello World" message. Then we'll create a new lambda function in AWS and deploy our code. Follow these steps to create a new node.js function: 1. Create a new directory for your function and navigate to it in the terminal. 2. Initialize your function with `npm init` and follow the prompts to create a new `package.json` file. 3. Add `"type": "module"` to the `package.json` file to enable ES6 modules. 4. Create a new file called `index.js` and add the following code: ``` export const handler = async (event) => { return { statusCode: 200, body: "Hello World!", }; }; ``` Zip your function code into `function.zip` by running the following command: {/* prettier-ignore */} ``` zip -r function.zip index.js package.json ``` ``` Compress-Archive -Path index.js, package.json -DestinationPath function.zip ``` When you have dependencies, you'll need to zip them as well. You can do this by running the following command: {/* prettier-ignore */} ``` zip -r function.zip index.js package.json node_modules/ ``` ``` Compress-Archive -Path index.js, package.json, node_modules/ -DestinationPath function.zip ``` ## Create a Lambda Function Before we can create a new Lambda function on AWS, we need to create an IAM role for the Lambda function. This role will grant the Lambda function permissions to access whichever AWS resources it needs. For now it will just need the `AWSLambdaBasicExecutionRole` policy, which grants the function basic permissions to access CloudWatch. Run the following command to create the IAM role: {/* prettier-ignore */} ```bash aws iam create-role \ --role-name MyFunctionName_Role \ --assume-role-policy-document '{"Version": "2012-10-17","Statement": [{"Effect": "Allow","Principal": {"Service": "lambda.amazonaws.com"},"Action": "sts:AssumeRole"}]}' ``` ``` aws iam create-role ` --role-name MyFunctionName_Role ` --assume-role-policy-document '{"Version": "2012-10-17","Statement": [{"Effect": "Allow","Principal": {"Service": "lambda.amazonaws.com"},"Action": "sts:AssumeRole"}]}' ``` Attach the `AWSLambdaBasicExecutionRole` policy to the role by running the following command: {/* prettier-ignore */} ```bash aws iam attach-role-policy \ --role-name MyFunctionName_Role \ --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole ``` ``` aws iam attach-role-policy ` --role-name MyFunctionName_Role ` --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole ``` Make a note of what the role ARN is. Create a new lambda function: {/* prettier-ignore */} ```bash aws lambda create-function \ --function-name MyFunctionName \ --runtime nodejs18.x \ --role \ --handler index.handler \ --zip-file fileb://function.zip ``` ``` aws lambda create-function ` --function-name MyFunctionName ` --runtime nodejs18.x ` --role ` --handler index.handler ` --zip-file fileb://function.zip ``` Replace `` the the arn of the IAM role you created earlier. Make a note of the `FunctionArn` that is returned. You'll need this later. And that's it! You've now created a new Lambda function with your JS code. ## Re Deploying Code Every time you make an update to your code you'll need to redeploy it to AWS. You can do this by running the following command: Zip your function code and dependencies by running the following command: {/* prettier-ignore */} ``` zip -r function.zip index.js package.json node_modules/ ``` ``` Compress-Archive -Path index.js, package.json, node_modules/ -DestinationPath function.zip ``` Update the lambda function with the new code: {/* prettier-ignore */} ```bash aws lambda update-function-code \ --function-name MyFunctionName \ --zip-file fileb://function.zip ``` ``` aws lambda update-function-code ` --function-name MyFunctionName ` --zip-file fileb://function.zip ``` ## Deleting a Lambda Function And when you're done with your function, you can delete it by running the following command: {/* prettier-ignore */} ```bash aws lambda delete-function \ --function-name MyFunctionName ``` ``` aws lambda delete-function ` --function-name MyFunctionName ``` ## API Gateway Of course, we don't want to have to call our Lambda function directly. We want to be able to call it from the web. To do this, we'll use API Gateway. But before we can do that, we need our function's ARN. Get the ARN of your Lambda function by running the following command: ``` aws lambda get-function --function-name MyFunctionName ``` To create a new HTTP API Gateway for the Lambda function, we can use the `create-api` and `create-resource` commands. Run the following command to create a new HTTP API: {/* prettier-ignore */} ```bash aws apigatewayv2 create-api \ --name MyHTTPAPI \ --protocol-type HTTP ``` ``` aws apigatewayv2 create-api ` --name MyHTTPAPI ` --protocol-type HTTP ``` Make a note of the API id. Create a new auto deployment for API gateway by running the following command: ``` aws apigatewayv2 create-stage \ --api-id \ --stage-name dev \ --auto-deploy ``` Replace `ApiId` with the id of the API you just created. Now whenever we make a change, like adding a new lambda function to the gateway, the changes will get automatically deployed. Add the lambda function to the API gateway by running the following command: {/* prettier-ignore */} ```bash aws apigatewayv2 create-integration \ --api-id \ --integration-type AWS_PROXY \ --integration-uri \ --payload-format-version 2.0 ``` ``` aws apigatewayv2 create-integration ` --api-id ` --integration-type AWS_PROXY ` --integration-uri ` --payload-format-version 2.0 ``` Make a note of the `IntegrationId` that is returned. Create a new route for the API gateway by running the following command: {/* prettier-ignore */} ```bash aws apigatewayv2 create-route \ --api-id \ --route-key "GET /test" \ --target integrations/ ``` ``` aws apigatewayv2 create-route ` --api-id ` --route-key "GET /test" ` --target integrations/ ``` We're almost there, we just need to give API gateway permission to invoke the function. But in order to do that, you need your aws profile id which you can find by running the following command: ``` aws sts get-caller-identity --query "Account" --output text ``` Add permission to the lambda function by running the following command: {/* prettier-ignore */} ```bash aws lambda add-permission \ --function-name \ --statement-id \ --action lambda:InvokeFunction \ --principal apigateway.amazonaws.com \ --source-arn ``` ``` aws lambda add-permission ` --function-name ` --statement-id ` --action lambda:InvokeFunction ` --principal apigateway.amazonaws.com ` --source-arn ``` The ARN of the HTTP API Gateway should be in the format `arn:aws:execute-api:::/*`. Once all of these steps have been succesfully completed, you should be able to visit your API gateway in the browser. Find the url by running the following command: {/* prettier-ignore */} ```bash aws apigatewayv2 get-api \ --api-id ``` ``` aws apigatewayv2 get-api ` --api-id ``` ## Delete API gateway When you're ready to delete your api gateway, you can do so with this command: ``` aws apigatewayv2 delete-api --api-id ```