Search code examples
rustaws-lambdaaws-sdk-rust

How do I serialize an AWS HTTP request in a lambda using Rust


I'm following this AWS Tutorial to access a DynamoDB using https requests. Using the provided JavaScript example does work, so the API Gateway configuration seems to work. I can send requests using curl and get the items of the table: curl -v https://xxxxxxxx.execute-api.us-west-2.amazonaws.com/items.

However, I'm struggling to build the lambda in rust. This is my not working example:

use lambda_runtime::{service_fn, Error, LambdaEvent};
use serde::{Deserialize, Serialize};

#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct Event {
    pub request_context: RequestContext,
}

#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct RequestContext {
    pub event_type: EventType,
    pub route_key: String,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "UPPERCASE")]
pub enum EventType {
    Connect,
    Disconnect,
}

#[derive(Serialize)]
struct Response {
    req_id: String,
    msg: String,
}

pub(crate) async fn my_handler(event: LambdaEvent<Event>) -> Result<Response, Error> {
    let result = event.payload.request_context.route_key;
    let resp = Response {
        req_id: event.context.request_id,
        msg: format!("{}", result),
    };
    Ok(resp)
}

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

The error I got is {"message":"Internal Server Error"}. I need to access the routeKey, as they do in the provided JavaScript example:

exports.handler = async (event, context) => {
  let body;
  let statusCode = 200;
  const headers = {
    "Content-Type": "application/json"
  };
try {
    switch (event.routeKey) {
      case "DELETE /items/{id}":
      break;
       /// do something
      default:
      break;
}
//...
}

I suggest the error is based on the struct, which can not be serialized?

Edit: The actual payload, using println!("payload: {}", event.payload)with an LambdaEvent<Event>.

payload: 
{
    "headers": {
        "accept": "*/*",
        "content-length": "0",
        "host": "xxxxxx.execute-api.us-west-2.amazonaws.com",
        "user-agent": "curl/7.81.0",
        "x-amzn-trace-id": "Root=x-xxxxxxx-xxxxxxxx",
        "x-forwarded-for": "xx.xxx.xxxx.xxx",
        "x-forwarded-port": "443",
        "x-forwarded-proto": "https"
    },
    "isBase64Encoded": false,
    "rawPath": "/items",
    "rawQueryString": "",
    "requestContext": {
        "accountId": "xxxxxxxxxx",
        "apiId": "xxxxxxxxxx",
        "domainName": "xxxxxxxxx.execute-api.us-west-2.amazonaws.com",
        "domainPrefix": "xxxxxxxx",
        "http": {
            "method": "GET",
            "path": "/items",
            "protocol": "HTTP/1.1",
            "sourceIp": "xx.xxxx.xxx.xx",
            "userAgent": "curl/7.81.0"
        },
        "requestId": "xxxxxxxxxxx",
        "routeKey": "GET /items",
        "stage": "$default",
        "time": "01/Dec/2022:08:07:39 +0000",
        "timeEpoch": 1669882059705
    },
    "routeKey": "GET /items",
    "version": "2.0"
}

Solution

  • The payload you posted has no eventType field. That's likely the cause of the error.