Skip to content

Commit cb8fbb0

Browse files
andrewpattojlizen
andauthored
feat: Add VPC Lattice as an upstream source for lambda-http (#1136)
* Added code and tests for HTTP handler for VPC lattice * fmt, clippy markdown fix * Tidied documentation * fix(lambda-http): address review feedback for VPC Lattice support --------- Co-authored-by: Jess Izen <jlizen@amazon.com>
1 parent 301e3cd commit cb8fbb0

11 files changed

Lines changed: 507 additions & 26 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
This package makes it easy to run AWS Lambda Functions written in Rust. This workspace includes multiple crates:
66

77
- [![Docs](https://docs.rs/lambda_runtime/badge.svg)](https://docs.rs/lambda_runtime) **`lambda-runtime`** is a library that provides a Lambda runtime for applications written in Rust.
8-
- [![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.
8+
- [![Docs](https://docs.rs/lambda_http/badge.svg)](https://docs.rs/lambda_http) **`lambda-http`** is a library for writing HTTP Lambda functions in Rust, with support for upstream API Gateway, ALB, Lambda Function URLs, and VPC Lattice.
99
- [![Docs](https://docs.rs/lambda-extension/badge.svg)](https://docs.rs/lambda-extension) **`lambda-extension`** is a library that makes it easy to write Lambda Runtime Extensions in Rust.
1010
- [![Docs](https://docs.rs/aws_lambda_events/badge.svg)](https://docs.rs/aws_lambda_events) **`lambda-events`** is a library with strongly-typed Lambda event structs in Rust.
1111
- [![Docs](https://docs.rs/lambda_runtime_api_client/badge.svg)](https://docs.rs/lambda_runtime_api_client) **`lambda-runtime-api-client`** is a shared library between the lambda runtime and lambda extension libraries that includes a common API client to talk with the AWS Lambda Runtime API.

lambda-events/src/event/vpc_lattice/v2.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
use crate::{
2-
custom_serde::{deserialize_headers, deserialize_nullish, http_method, serialize_multi_value_headers},
3-
encodings::Body,
4-
};
1+
use crate::custom_serde::{deserialize_headers, deserialize_nullish, http_method, serialize_multi_value_headers};
52
#[cfg(feature = "builders")]
63
use bon::Builder;
74
use http::{HeaderMap, Method};
@@ -47,7 +44,7 @@ pub struct VpcLatticeRequestV2 {
4744

4845
/// The request body
4946
#[serde(default)]
50-
pub body: Option<Body>,
47+
pub body: Option<String>,
5148

5249
/// Whether the body is base64 encoded
5350
#[serde(default, deserialize_with = "deserialize_nullish")]

lambda-http/Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@ categories = ["web-programming::http-server"]
1717
readme = "README.md"
1818

1919
[features]
20-
default = ["apigw_rest", "apigw_http", "apigw_websockets", "alb", "tracing"]
20+
default = ["apigw_rest", "apigw_http", "apigw_websockets", "alb", "vpc_lattice", "tracing"]
2121
apigw_rest = []
2222
apigw_http = []
2323
apigw_websockets = []
2424
alb = []
25+
vpc_lattice = []
2526
pass_through = []
2627
catch-all-fields = ["aws_lambda_events/catch-all-fields"]
2728
tracing = ["lambda_runtime/tracing"] # enables access to the Tracing utilities
@@ -53,7 +54,7 @@ url = "2.2"
5354
path = "../lambda-events"
5455
version = "1.1"
5556
default-features = false
56-
features = ["alb", "apigw"]
57+
features = ["alb", "apigw", "vpc_lattice"]
5758

5859
[dev-dependencies]
5960
axum-core = "0.5.4"

lambda-http/README.md

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
[![Docs](https://docs.rs/lambda_http/badge.svg)](https://docs.rs/lambda_http)
44

5-
**`lambda-http`** is an abstraction that takes payloads from different services and turns them into http objects, making it easy to write API Gateway proxy event focused Lambda functions in Rust.
5+
**`lambda-http`** is an abstraction that takes HTTP-shaped payloads from different AWS services and turns them
6+
into standard `http` objects, making it easy to write Lambda functions in Rust that serve HTTP traffic
7+
regardless of the upstream trigger.
68

79
lambda-http handler is made of:
810

@@ -14,17 +16,18 @@ We are able to handle requests from:
1416
* [API Gateway](https://docs.aws.amazon.com/apigateway/latest/developerguide/welcome.html) REST, HTTP and WebSockets API lambda integrations
1517
* AWS [ALB](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/introduction.html)
1618
* AWS [Lambda function URLs](https://docs.aws.amazon.com/lambda/latest/dg/lambda-urls.html)
19+
* AWS [VPC Lattice](https://docs.aws.amazon.com/vpc-lattice/latest/ug/lambda-functions.html)
1720

18-
Thanks to the `Request` type we can seamlessly handle proxy integrations without the worry to specify the specific service type.
21+
Thanks to the `Request` type we can seamlessly handle all of these triggers without having to write service-specific code.
1922

20-
There is also an extension for `lambda_http::Request` structs that provides access to [API gateway](https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format) and [ALB](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/lambda-functions.html) features.
23+
There is also an extension for `lambda_http::Request` structs that provides access to [API Gateway](https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format), [ALB](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/lambda-functions.html), and [VPC Lattice](https://docs.aws.amazon.com/vpc-lattice/latest/ug/lambda-functions.html) features.
2124

2225
For example some handy extensions:
2326

2427
* `query_string_parameters` - Return pre-parsed http query string parameters, parameters provided after the `?` portion of a url associated with the request
2528
* `path_parameters` - Return pre-extracted path parameters, parameter provided in url placeholders `/foo/{bar}/baz/{qux}` associated with the request
2629
* `lambda_context` - Return the Lambda context for the invocation; see the [runtime docs](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-api.html#runtimes-api-next)
27-
* `request_context` - Return the ALB/API Gateway request context
30+
* `request_context` - Return the ALB, API Gateway, or VPC Lattice request context
2831
* payload - Return the Result of a payload parsed into a type that implements `serde::Deserialize`
2932

3033
See the `lambda_http::RequestPayloadExt` and `lambda_http::RequestExt` traits for more extensions.
@@ -238,16 +241,17 @@ If you don't want to receive the stage as part of the path, you can set the envi
238241

239242
## Feature flags
240243

241-
`lambda_http` is a wrapper for HTTP events coming from three different services, Amazon Load Balancer (ALB), Amazon Api Gateway (APIGW), and AWS Lambda Function URLs. Amazon Api Gateway can also send events from three different endpoints, REST APIs, HTTP APIs, and WebSockets. `lambda_http` transforms events from all these sources into native `http::Request` objects, so you can incorporate Rust HTTP semantics into your Lambda functions.
244+
`lambda_http` is a wrapper for HTTP events coming from four different AWS services: Application Load Balancer (ALB), API Gateway, Lambda Function URLs, and VPC Lattice. API Gateway can send events from three different endpoint types: REST APIs, HTTP APIs, and WebSockets. `lambda_http` transforms events from all these sources into native `http::Request` objects, so you can incorporate Rust HTTP semantics into your Lambda functions.
242245

243246
By default, `lambda_http` compiles your function to support any of those services. This increases the compile time of your function because we have to generate code for all the sources. In reality, you'll usually put a Lambda function only behind one of those sources. You can choose which source to generate code for with feature flags.
244247

245-
The available features flags for `lambda_http` are the following:
248+
The available feature flags for `lambda_http` are the following:
246249

247250
- `alb`: for events coming from [Amazon Elastic Load Balancer](https://aws.amazon.com/elasticloadbalancing/).
248-
- `apigw_rest`: for events coming from [Amazon API Gateway Rest APIs](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-rest-api.html).
251+
- `apigw_rest`: for events coming from [Amazon API Gateway REST APIs](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-rest-api.html).
249252
- `apigw_http`: for events coming from [Amazon API Gateway HTTP APIs](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api.html) and [AWS Lambda Function URLs](https://docs.aws.amazon.com/lambda/latest/dg/lambda-urls.html).
250253
- `apigw_websockets`: for events coming from [Amazon API Gateway WebSockets](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api.html).
254+
- `vpc_lattice`: for events coming from [AWS VPC Lattice](https://docs.aws.amazon.com/vpc-lattice/latest/ug/lambda-functions.html).
251255

252256
If you only want to support one of these sources, you can disable the default features, and enable only the source that you care about in your package's `Cargo.toml` file. Substitute the dependency line for `lambda_http` for the snippet below, changing the feature that you want to enable:
253257

lambda-http/src/deserializer.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ use aws_lambda_events::apigw::ApiGatewayProxyRequest;
77
use aws_lambda_events::apigw::ApiGatewayV2httpRequest;
88
#[cfg(feature = "apigw_websockets")]
99
use aws_lambda_events::apigw::ApiGatewayWebsocketProxyRequest;
10+
#[cfg(feature = "vpc_lattice")]
11+
use aws_lambda_events::vpc_lattice::VpcLatticeRequestV2;
12+
1013
use serde::{de::Error, Deserialize};
1114
use serde_json::value::RawValue;
1215

@@ -39,6 +42,10 @@ impl<'de> Deserialize<'de> for LambdaRequest {
3942
if let Ok(res) = serde_json::from_str::<ApiGatewayWebsocketProxyRequest>(data) {
4043
return Ok(LambdaRequest::WebSocket(res));
4144
}
45+
#[cfg(feature = "vpc_lattice")]
46+
if let Ok(res) = serde_json::from_str::<VpcLatticeRequestV2>(data) {
47+
return Ok(LambdaRequest::VpcLatticeV2(res));
48+
}
4249
#[cfg(feature = "pass_through")]
4350
if PASS_THROUGH_ENABLED {
4451
return Ok(LambdaRequest::PassThrough(data.to_string()));
@@ -136,6 +143,22 @@ mod tests {
136143
}
137144
}
138145

146+
#[test]
147+
fn test_deserialize_vpc_lattice() {
148+
let data = include_bytes!("../../lambda-events/src/fixtures/example-vpc-lattice-v2-request.json");
149+
150+
let req: LambdaRequest = serde_json::from_slice(data).expect("failed to deserialize vpc lattice data");
151+
match req {
152+
LambdaRequest::VpcLatticeV2(req) => {
153+
assert_eq!(
154+
"arn:aws:vpc-lattice:ap-southeast-2:123456789012:targetgroup/tg-6d0ecf831eec9f09",
155+
req.request_context.target_group_arn
156+
);
157+
}
158+
other => panic!("unexpected request variant: {other:?}"),
159+
}
160+
}
161+
139162
#[test]
140163
#[cfg(feature = "pass_through")]
141164
fn test_deserialize_bedrock_agent() {

lambda-http/src/lib.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
#![cfg_attr(docsrs, feature(doc_cfg))]
33
//#![deny(warnings)]
44
//! Enriches the `lambda` crate with [`http`](https://github.com/hyperium/http)
5-
//! types targeting AWS [ALB](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/introduction.html), [API Gateway](https://docs.aws.amazon.com/apigateway/latest/developerguide/welcome.html) REST and HTTP API lambda integrations.
5+
//! types targeting AWS
6+
//! * [ALB](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/introduction.html)
7+
//! * [API Gateway](https://docs.aws.amazon.com/apigateway/latest/developerguide/welcome.html) REST and HTTP API lambda integrations
8+
//! * [VPC Lattice](https://docs.aws.amazon.com/vpc-lattice/latest/ug/lambda-functions.html)
69
//!
710
//! This crate abstracts over all of these trigger events using standard [`http`](https://github.com/hyperium/http) types minimizing the mental overhead
811
//! of understanding the nuances and variation between trigger details allowing you to focus more on your application while also giving you to the maximum flexibility to

0 commit comments

Comments
 (0)