How to build and deploy AWS Lambda in Rust
How to build and deploy AWS Lambda in Rust: Build Lambda in Rust, Deploy with API Gateway and test with Postman
What we will build:
We will write an AWS Lambda function in Rust that will be invoked by API Gateway. We will receive a POST request, with a string name. Our lambda will return "Hello {name}"
Pre-Reqs:
- Cargo installed
- Rust installed
- AWS account set up
Lambda
Writing the code
Setup: View Commit
To start, execute this command in your terminal:
1cargo new rust-lambda-tutorial
Cargo will create this directory structure:
Next, move into this new directory and install our required libraries:
1cd rust-lambda-tutorial 2cargo add aws_lambda_events http lambda_runtime serde serde_json tokio
Here is what the contents of cargo.toml should look like:
Now we can jump into main.rs!
We need to replace the default hello world code with this:
1use lambda_runtime::Error; 2 3#[tokio::main] 4async fn main() -> Result<(), Error>{ 5 let lambda_handler = lambda_runtime::service_fn(handler); 6 lambda_runtime::run(lambda_handler).await?; 7 Ok(()) 8}
We are using Tokio as our runtime, this allows us to make main async. This code tells AWS lambda how to execute our function, handler.
Handler Function: View Commit
Let's define the struct representing our input. This is the type of the request's body has been parsed from json.
1#[derive(Deserialize)] 2struct Event { 3 name: String 4}
The following code defines our handler function and parses our event.
1async fn handler(lambda_event: LambdaEvent<ApiGatewayProxyRequest>) -> Result<ApiGatewayProxyResponse, Error> { 2 let event: Event = serde_json::from_str(&lambda_event.payload.body.unwrap())?; 3
Then return our result with our response:
1return Ok(ApiGatewayProxyResponse{ 2 status_code: 200, 3 headers: Default::default(), 4 multi_value_headers: Default::default(), 5 body: Some( 6 Body::Text( 7 json!({ 8 "message": format!("Hello {}", event.name) 9 }).to_string())), 10 is_base64_encoded: Some(false), 11 }) 12}
Let's run cargo check
to check for any compile time errors
Here we are getting an error that the Deserialize macro is not in scope. We need this macro to be able to parse our request body from json to our Event struct type. Let's fix this by adding this import
1use serde::Deserialize;
This is now our imports in main.rs: And there are no more compile errors, so it is now ready to deploy!
Deploying lambda
Official Documentation: https://docs.aws.amazon.com/sdk-for-rust/latest/dg/lambda.html#lambda-step3
This requires a tool called cargo lambda, install instructions: https://www.cargo-lambda.info/guide/getting-started.html#step-1-install-cargo-lambda
I am on Linux, so to build and zip my Lambda I had to run these commands:
1pip3 install cargo-lambda 2cargo lambda build --release --output-format zip
Check out this post to see how to build your lambda if you're not using linux.
This produces a zip folder called bootstrap in the target directory:
Navigate to Lambda on the AWS management console and click create function Choose Author from scratch, and select Provide your own bootstrap on Amazon Linux 2. Keep the Architecture selected as x86_64, then select Create Function
This is the lambda's function page, here click Upload from and choose the zip folder called bootstrap in ./target/lambda/rust-lambda-tutorial/
API Gateway
To make the function accessible through API Gateway, click Add Trigger on the lambda's function page and choose API Gateway. Click Create a new API. Choose HTTP API, as we do not need to use the extra features from REST API option for this test. Finally, choose Open for the Security toggle and click Create.
We are then brought back to the Lambda's function page, under Configuration -> Triggers, we can see the endpoint of our API that points to our Lambda!
Postman Testing
Use this endpoint as our url and test the Lambda function like so:
And it works!