awslabs / aws-lambda-rust-runtime

A Rust runtime for AWS Lambda
Apache License 2.0
3.36k stars 343 forks source link

Data did not match any variant of untagged enum LambdaRequest when invoking with sample JSON #655

Closed DavidSouther closed 1 year ago

DavidSouther commented 1 year ago

When invoking a lambda_http service function using the template payload from the Lambda test console, serde fails to deserialize.

Cargo.toml:

[package]
name = "project"
version = "0.1.0"
edition = "2021"

[dependencies]
anyhow = "1.0.70"
lambda_http = "0.8.0"
serde = { version = "1.0.159", features = ["derive"] }
tokio = { version = "1.27.0", features = ["macros"] }

bin/upload_err.rs:

use lambda_http::RequestPayloadExt;

#[derive(serde::Deserialize)]
pub struct UploadRequest {
    file_name: String,
}

#[tokio::main]
async fn main() -> Result<(), lambda_runtime::Error> {
    tracing_subscriber::fmt().init();
    lambda_http::run(lambda_http::service_fn(
        |request: lambda_http::Request| async move {
            let file_name = request
                .payload::<UploadRequest>()?
                .ok_or_else(|| anyhow::anyhow!("missing upload request"))?
                .file_name;
            Ok::<_, anyhow::Error>(format!(r#"{{"url": "/path/to/{file_name}"}}"#))
        },
    ))
    .await
}

example.json:

{
  "body": "{\"test\":\"body\"}",
  "resource": "/{proxy+}",
  "path": "/path/to/resource",
  "httpMethod": "POST",
  "queryStringParameters": {
    "foo": "bar"
  },
  "pathParameters": {
    "proxy": "path/to/resource"
  },
  "stageVariables": {
    "baz": "qux"
  },
  "headers": {
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
    "Accept-Encoding": "gzip, deflate, sdch",
    "Accept-Language": "en-US,en;q=0.8",
    "Cache-Control": "max-age=0",
    "CloudFront-Forwarded-Proto": "https",
    "CloudFront-Is-Desktop-Viewer": "true",
    "CloudFront-Is-Mobile-Viewer": "false",
    "CloudFront-Is-SmartTV-Viewer": "false",
    "CloudFront-Is-Tablet-Viewer": "false",
    "CloudFront-Viewer-Country": "US",
    "Host": "1234567890.execute-api.{dns_suffix}",
    "Upgrade-Insecure-Requests": "1",
    "User-Agent": "Custom User Agent String",
    "Via": "1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)",
    "X-Amz-Cf-Id": "cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA==",
    "X-Forwarded-For": "127.0.0.1, 127.0.0.2",
    "X-Forwarded-Port": "443",
    "X-Forwarded-Proto": "https"
  },
  "requestContext": {
    "accountId": "123456789012",
    "resourceId": "123456",
    "stage": "prod",
    "requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef",
    "identity": {
      "cognitoIdentityPoolId": null,
      "accountId": null,
      "cognitoIdentityId": null,
      "caller": null,
      "apiKey": null,
      "sourceIp": "127.0.0.1",
      "cognitoAuthenticationType": null,
      "cognitoAuthenticationProvider": null,
      "userArn": null,
      "userAgent": "Custom User Agent String",
      "user": null
    },
    "resourcePath": "/{proxy+}",
    "httpMethod": "POST",
    "apiId": "1234567890"
  }
}

Runner:

%cargo lambda watch

Invoke:

% cargo lambda invoke upload_er
r --data-file example.json 
Error: serde_json::error::Error

  × data did not match any variant of untagged enum LambdaRequest

Log:

2023-05-16T18:22:46.995666Z ERROR Lambda runtime invoke{requestId="ef6c5745-52ce-4b08-9119-72717c99179e" xrayTraceId="Root=1-6463c9df-b71d5c4715e826747799163f;Parent=cc2d5d821583bf7e;Sampled=1"}: lambda_runtime: Error("data did not match any variant of untagged enum LambdaRequest", line: 0, column: 0)
DavidSouther commented 1 year ago

This looks suspiciously similar to #365 and #367, which makes me think that either the example is too loose, or the definitions in lambda_http are too strict.

calavera commented 1 year ago

makes me think that either the example is too loose, or the definitions in lambda_http are too strict.

There is no specification about the payloads, so it's hard to tell. Other languages are definitely more forgiving than Rust parsing those examples. Given the payload that you have in the description, it should be easy to add a new test case in the apigw module to validate that those payloads are supported:

https://github.com/awslabs/aws-lambda-rust-runtime/blob/main/lambda-events/src/event/apigw/mod.rs#L749

github-actions[bot] commented 1 year ago

⚠️COMMENT VISIBILITY WARNING⚠️

Comments on closed issues are hard for the maintainers of this repository to see. If you need more assistance, please open a new issue that references this one. If you wish to keep having a conversation with other community members under this issue feel free to do so.

sean-krail commented 1 year ago

In my case, I ran into this data did not match any variant of untagged enum LambdaRequest error because I was using the apigw_http feature but fronting my Lambda with an APIG REST API (was originally using a Lambda Function URL). Swapping this feature with apigw_rest resolved the issue for me.