# Rust in AWS Lambda

In today's [WOD](https://www.refinery29.com/en-us/crossfit-terms), we'll learn how to deploy a Rust-lambda in AWS using CDK. We'll start relatively easy today. However, we'll explore more advanced setups using [rust](https://www.rust-lang.org/) and different AWS services in the coming months.

*   *A reference project can be found* [*here*](https://github.com/JoelRoxell/rust-lambda)
    
*   *This post is derived from this* [*original post from AWS*](https://aws.amazon.com/blogs/opensource/rust-runtime-for-aws-lambda/)
    
*   *I assume you have access to AWS & related access keys*
    

Start by installing Rust.

```bash
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
```

Then install a crate (package) that will help us during the deployment, or download the binary by following these [docs](https://www.cargo-lambda.info/guide/installation.html#installation).

```bash
cargo install cargo-lambda
```

Next, create a new project using cargo-lambda. The tool will ask for some information, then generate a template project for you.

```bash
cargo lambda new demo-1

# ? Is this function an HTTP function? Yes
# ? Which service is this function receiving events from? Amazon Api Gateway REST Api
```

Your `cargo.toml` should now look something like the following.

```ini
# cargo.toml
[package]
name = "demo-1"
version = "0.1.0"
edition = "2021"

[dependencies]
lambda_http = { version = "0.7", default-features = false, features = ["apigw_rest"] }
lambda_runtime = "0.7"
tokio = { version = "1", features = ["macros"] }
tracing = { version = "0.1", features = ["log"] }
tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
```

In brief, tokio allows us to use an async runtime and the AWS packages help us interface between our code and the Lambda runtime.

Now it's time to write our entry point (main) and add our handler.

```rust
// main.rs
use lambda_http::{run, service_fn, Body, Error, Request, RequestExt, Response};

async fn function_handler(event: Request) -> Result<Response<Body>, Error> {
    let echo = event
        .query_string_parameters()
        .first("message")
        .unwrap_or("world!")
        .to_string();
    let resp = Response::builder()
        .status(200)
        .header("content-type", "text/html")
        .body(format!("<h1>Hello {}</h1>", echo).into())
        .map_err(Box::new)?;

    Ok(resp)
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    tracing_subscriber::fmt()
        .with_max_level(tracing::Level::INFO)
        .with_target(false)
        .without_time()
        .init();

    run(service_fn(function_handler)).await
}
```

Compile our lambda and "prepare" it for deployment.

```bash
# Build the binary
cargo lambda build --release
```

The project should now look something like this.

```ini
.
├── Cargo.lock
├── Cargo.toml
├── src
│   └── main.rs
└── target
    ├── CACHEDIR.TAG
    ├── debug
    ├── lambda
    ├── release
    └── x86_64-unknown-linux-gnu
```

Make sure you have the executable where it should be...

```ini
file target/lambda/demo-1/bootstrap
# target/lambda/demo-1/bootstrap: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.0.0, stripped
```

Cheers, now everything regarding our implementation is complete. Lastly, we just need to define our infrastructure using CDK and then deploy it!

## Deploying the binary using CDK

```bash
npm install -g aws-cdk
mkdir infra && cd infra
cdk init app --language typescript
```

The project structure should now look something like this.

```plaintext
.
├── Cargo.toml
├── infra
│   ...
│   ├── lib
│   └── tsconfig.json
└── src
    └── main.rs
```

Time to write our stack definition.

```typescript
// infra/lib/infra-stack.ts
import * as cdk from 'aws-cdk-lib';
import * as apigateway from 'aws-cdk-lib/aws-apigateway';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { Construct } from 'constructs';
import { RetentionDays } from 'aws-cdk-lib/aws-logs';

export class InfraStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const api = new apigateway.RestApi(this, "api", {
      restApiName: "rust-api",
      deployOptions: {
        stageName: "dev",
      },
    });
    const helloLambda = new lambda.Function(this, "rust-hello", {
      functionName: "hello-rust",
      code: lambda.Code.fromAsset(
        "../target/lambda/demo-1"
      ),
      runtime: lambda.Runtime.PROVIDED_AL2,
      handler: "not.required",
      environment: {
        RUST_BACKTRACE: "1",
      },
      logRetention: RetentionDays.ONE_DAY,
    });
    const messages = api.root.addResource("messages");

    messages.addMethod(
      "GET",
      new apigateway.LambdaIntegration(helloLambda, { proxy: true })
    );
  }
}
```

Deploy & Test your endpoint

```bash
npm run cdk deploy && cd -

# Execute your Lambda via the created API gateway
curl https://gbbb85bvai.execute-api.eu-west-1.amazonaws.com/dev/messages
# <h1>Hello world!</h1>                                                                                                                                                             

curl https://gbbb85bvai.execute-api.eu-west-1.amazonaws.com/dev/messages\?message\=ggwp
# <h1>Hello ggwp</h1>
```

Remove the stack

`cd stack && npm run cdk destroy && cd -`

**Great**, you made it this "far". You're now a fully **certified binary-lambda-slinger**. Feel free to give us input on what you'd like to see in the future! (as long as it's related to serverless)

* * *
%%[leadfeeder]
[**Elva**](https://elva-group.com/) is a serverless-first consulting company that can help you transform or begin your AWS journey for the future.
