This package makes it easy to run AWS Lambda Functions written in Rust. This workspace includes two crates:
lambda-runtime-client
is a client SDK for the Lambda Runtime APIs. You probably don't need to use this crate directly!lambda-runtime
is a library that makes it easy to write Lambda functions in Rust.
The code below creates a simple function that receives an event with a greeting
and name
field and returns a GreetingResponse
message for the given name and greeting. Notice: to run these examples, we require a minimum Rust version of 1.30.
extern crate lambda_runtime as lambda;
extern crate serde_derive;
extern crate log;
extern crate simple_logger;
use serde_derive::{Serialize, Deserialize};
use lambda::{lambda, Context, error::HandlerError};
use log::error;
use std::error::Error;
#[derive(Serialize, Deserialize)]
struct GreetingEvent {
greeting: String,
name: String,
}
#[derive(Serialize, Deserialize)]
struct GreetingResponse {
message: String,
}
fn main() -> Result<(), Box<dyn Error>> {
simple_logger::init_with_level(log::Level::Debug).unwrap();
lambda!(my_handler);
Ok(())
}
fn my_handler(event: GreetingEvent, ctx: Context) -> Result<GreetingResponse, HandlerError> {
if event.name == "" {
error!("Empty name in request {}", ctx.aws_request_id);
return Err(ctx.new_error("Empty name"));
}
Ok(GreetingResponse {
message: format!("{}, {}!", event.greeting, event.name),
})
}
The code above is the same as the basic example in the lambda-runtime
crate. To deploy the basic sample as a Lambda function, we first build it with cargo
. Since Lambda uses Amazon Linux, you'll need to target your executable for an x86_64-linux
platform.
$ cargo build -p lambda_runtime --example basic --release
For a custom runtime, AWS Lambda looks for an executable called boostrap
in the deployment package zip. Rename the generated basic
executable to bootstrap
and add it to a zip archive.
$ cp ./target/release/examples/basic ./bootstrap && zip lambda.zip bootstrap && rm bootstrap
Now that we have a deployment package (lambda.zip
), we can use the AWS CLI to create a new Lambda function. Make sure to replace the execution role with an existing role in your account!
$ aws lambda create-function --function-name rustTest \
--handler doesnt.matter \
--zip-file file://./rust.zip \
--runtime provided \
--role arn:aws:iam::XXXXXXXXXXXXX:role/your_lambda_execution_role \
--environment Variables={RUST_BACKTRACE=1} \
--tracing-config Mode=Active
You can now test the function using the AWS CLI or the AWS Lambda console
$ aws lambda invoke --function-name rustTest \
--payload '{"firstName": "world"}' \
output.json
$ cat output.json # Prints: {"message":"Hello, world!"}
Defines the RuntimeClient
trait and provides its HttpRuntimeClient
implementation. The client fetches events and returns output as Vec<u8>
.
For error reporting to the runtime APIs the library defines the RuntimeApiError
trait and the ErrorResponse
object. Custom errors for the APIs should implement the to_response() -> ErrorResponse
method of the RuntimeApiError
trait.
This library makes it easy to create Rust executables for AWS lambda. The library defines a lambda!()
macro. Call the lambda!()
macro from your main method with a function that matches the Handler
type:
pub type Handler<E, O> = fn(E, Context) -> Result<O, error::HandlerError>;
Optionally, you can pass your own instance of Tokio runtime to the lambda!()
macro. See our with_custom_runtime.rs
example
To serialize and deserialize events and responses, we suggest using the use the serde
library. To receive custom events, annotate your structure with Serde's macros:
extern crate serde;
extern crate serde_derive;
extern crate serde_json;
use serde_derive::{Serialize, Deserialize};
use serde_json::json;
use std::error::Error;
#[derive(Serialize, Deserialize)]
pub struct NewIceCreamEvent {
pub flavors: Vec<String>,
}
#[derive(Serialize, Deserialize)]
pub struct NewIceCreamResponse {
pub flavors_added_count: usize,
}
fn main() -> Result<(), Box<Error>> {
let flavors = json!({
"flavors": [
"Nocciola",
"抹茶",
"आम"
]
});
let event: NewIceCreamEvent = serde_json::from_value(flavors)?;
let response = NewIceCreamResponse {
flavors_added_count: event.flavors.len(),
};
serde_json::to_string(&response)?;
Ok(())
}