Skip to content

Bring README up to date with master branch #247

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jan 29, 2021
Merged
86 changes: 21 additions & 65 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,58 +2,38 @@

This package makes it easy to run AWS Lambda Functions written in Rust. This workspace includes multiple crates:

- [![Docs](https://docs.rs/lambda_runtime_client/badge.svg)](https://docs.rs/lambda_runtime_client) **`lambda-runtime-client`** is a client SDK for the Lambda Runtime APIs. You probably don't need to use this crate directly!
- [![Docs](https://docs.rs/lambda_runtime/badge.svg)](https://docs.rs/lambda_runtime) **`lambda-runtime`** is a library that makes it easy to write Lambda functions in Rust.
- [![Docs](https://docs.rs/lambda/badge.svg)](https://docs.rs/lambda) **`lambda`** is a library that provides a Lambda runtime for applications written in Rust.
- [![Docs](https://docs.rs/lambda_http/badge.svg)](https://docs.rs/lambda_http) **`lambda-http`** is a library that makes it easy to write API Gateway proxy event focused Lambda functions in Rust.

## Example function

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.31.
The code below creates a simple function that receives an event with a `firstName` field and returns a message to the caller. Notice: this crate is tested against latest stable Rust.

```rust,no_run
use std::error::Error;

use lambda_runtime::{error::HandlerError, lambda, Context};
use log::{self, error};
use serde_derive::{Deserialize, Serialize};
use simple_error::bail;
use simple_logger;

#[derive(Deserialize)]
struct CustomEvent {
#[serde(rename = "firstName")]
first_name: String,
}
use lambda::{handler_fn, Context};
use serde_json::{json, Value};

#[derive(Serialize)]
struct CustomOutput {
message: String,
}

fn main() -> Result<(), Box<dyn Error>> {
simple_logger::init_with_level(log::Level::Debug)?;
lambda!(my_handler);
type Error = Box<dyn std::error::Error + Send + Sync + 'static>;

#[tokio::main]
async fn main() -> Result<(), Error> {
let func = handler_fn(func);
lambda::run(func).await?;
Ok(())
}

fn my_handler(e: CustomEvent, c: Context) -> Result<CustomOutput, HandlerError> {
if e.first_name == "" {
error!("Empty first name in request {}", c.aws_request_id);
bail!("Empty first name");
}
async fn func(event: Value, _: Context) -> Result<Value, Error> {
let first_name = event["firstName"].as_str().unwrap_or("world");

Ok(CustomOutput {
message: format!("Hello, {}!", e.first_name),
})
Ok(json!({ "message": format!("Hello, {}!", first_name) }))
}
```

The code above is the same as the [basic example](https://github.com/awslabs/aws-lambda-rust-runtime/tree/master/lambda-runtime/examples/basic.rs) in the `lambda-runtime` crate.
The code above is the same as the [basic example](https://github.com/awslabs/aws-lambda-rust-runtime/blob/master/lambda/examples/hello-without-macro.rs) in the `lambda` crate.

### Deployment

There are currently multiple ways of building this package: manually, and with the [Serverless framework](https://serverless.com/framework/).
There are currently multiple ways of building this package: manually with the AWS CLI, and with the [Serverless framework](https://serverless.com/framework/).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's maybe include the SAM CLI with the Makefile approach and (hopefully) aws/aws-lambda-builders#174, once that is merged.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll see... :) I'll try to keep a some light pressure on that. Ultimately SAM is the most likely AWS-suggested approach to expect with SAM being the tool AWS pushes. Not having a SAM story is worse than not having some SAM story. I agree with the adding SAM + Makefile example being useful

s551228258327922884_p1702_i14_w300

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd much more believe in terraform ;d, could add an example with that

Copy link
Contributor

@rimutaka rimutaka Jul 29, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd much more believe in terraform ;d, could add an example with that

I prefer TF too, but if AWS prefers SAM then what most people will use anyway.
@Veetaha if you do make an example, can we put it in examples folder with a mention and a link to it from README to keep it concise?

Copy link

@brainstorm brainstorm Sep 15, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm using CDK for deployment of Rust lambdas these days. Switched to SAM now

If people adopt SAM as a Rust-lambda "blueprint project", there I'll go too... My current DX fail with Rust lambdas is that I've been unable to find a lightweight and properly documented way to debug Rust lambdas locally... EDIT: this could work for the time being, I guess: https://github.com/rimutaka/lambda-debug-proxy

My ideal scenario: not having to deal with docker (i.e: lambci) and my VSCode session having all the variable values, watchpoints and backtraces I would normally have for "regular local binaries", ideally with proper observability all the way down to FFI (C bindgen) crates.

Am I dreaming or is this available today and I've missed it? :)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Essentially I would like something like this for Rust+SAM+lambdas: https://pawelgrzybek.com/attach-visual-studio-code-debugger-to-sam-serverless-application-model-local-endpoint/ ... does anybody has such a setup? @rimutaka ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@brainstorm, That debug-proxy works for me just fine and I use CLI/TF for deployment.


#### AWS CLI

Expand Down Expand Up @@ -93,7 +73,7 @@ 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!"}
$ cat output.json # Prints: {"message": "Hello, world!"}
```

**Note:** `--cli-binary-format raw-in-base64-out` is a required
Expand Down Expand Up @@ -167,34 +147,14 @@ $ unzip -o \
# Ctrl-D to yield control back to your function
```

## lambda-runtime-client

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.
## `lambda`

## lambda-runtime
`lambda` is a library for authoring reliable and performant Rust-based AWS Lambda functions. At a high level, it provides a few major components:

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 an implementation the `Handler` type:
- `Handler`, a trait that defines interactions between customer-authored code and this library.
- `lambda::run`, function that runs an `Handler`.

```rust
pub trait Handler<E, O> {
/// Run the handler.
fn run(
&mut self,
event: E,
ctx: Context
) -> Result<O, HandlerError>;
}
```

`Handler` provides a default implementation that enables you to provide a Rust closure or function pointer to the `lambda!()` macro.

Optionally, you can pass your own instance of Tokio runtime to the `lambda!()` macro:
```
let rt = tokio::runtime::Runtime::new()?;
lambda!(my_handler, rt);
```
The function `handler_fn` converts a rust function or closure to `Handler`, which can then be run by `lambda::run`.

## AWS event objects

Expand All @@ -205,11 +165,7 @@ This project does not currently include Lambda event struct definitions though w
To serialize and deserialize events and responses, we suggest using the use the [`serde`](https://github.com/serde-rs/serde) library. To receive custom events, annotate your structure with Serde's macros:

```rust
extern crate serde;
extern crate serde_derive;
extern crate serde_json;

use serde_derive::{Serialize, Deserialize};
use serde::{Serialize, Deserialize};
use serde_json::json;
use std::error::Error;

Expand Down
6 changes: 4 additions & 2 deletions lambda/examples/hello-without-macro.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use lambda::{handler_fn, Context};
use serde_json::Value;
use serde_json::{json, Value};

type Error = Box<dyn std::error::Error + Send + Sync + 'static>;

Expand All @@ -11,5 +11,7 @@ async fn main() -> Result<(), Error> {
}

async fn func(event: Value, _: Context) -> Result<Value, Error> {
Ok(event)
let first_name = event["firstName"].as_str().unwrap_or("world");

Ok(json!({ "message": format!("Hello, {}!", first_name) }))
}