Skip to content

Commit 6f693fb

Browse files
softpropsdavidbarsky
authored andcommitted
Support both API Gateway and ALB events as http::{Request,Response} (#64)
* support both apigw and alb events as http::{Request,Response} * rustfmt * not specific apigw now * sentence casing
1 parent 9966ee3 commit 6f693fb

File tree

9 files changed

+289
-103
lines changed

9 files changed

+289
-103
lines changed

lambda-http/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ version = "0.1.0"
44
authors = ["Doug Tangren"]
55
edition = "2018"
66
description = "Rust API Gateway proxy event interfaces for AWS Lambda"
7-
keywords = ["AWS", "Lambda", "APIGateway", "Rust", "API"]
7+
keywords = ["AWS", "Lambda", "APIGateway", "ALB", "API"]
88
license = "Apache-2.0"
99
homepage = "https://github.com/awslabs/aws-lambda-rust-runtime"
1010
repository = "https://github.com/awslabs/aws-lambda-rust-runtime"
@@ -30,3 +30,4 @@ serde_urlencoded = "0.5"
3030
[dev-dependencies]
3131
log = "^0.4"
3232
simple_logger = "^1"
33+

lambda-http/src/body.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1-
//! Provides an API Gateway oriented request and response body entity interface
1+
//! Provides an ALB / API Gateway oriented request and response body entity interface
22
33
use std::{borrow::Cow, ops::Deref};
44

55
use base64::display::Base64Display;
66
use serde::ser::{Error as SerError, Serialize, Serializer};
77

88
/// Representation of http request and response bodies as supported
9-
/// by API Gateway.
9+
/// by API Gateway and ALBs.
1010
///
1111
/// These come in three flavors
1212
/// * `Empty` ( no body )
1313
/// * `Text` ( text data )
1414
/// * `Binary` ( binary data )
1515
///
16-
/// Body types can be `Deref` and `AsRef`'d into `[u8]` types much like the `hyper` crate
16+
/// Body types can be `Deref` and `AsRef`'d into `[u8]` types much like the [hyper crate](https://crates.io/crates/hyper)
1717
///
1818
/// # Examples
1919
///

lambda-http/src/ext.rs

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//! API Gateway extension methods for `http::Request` types
1+
//! ALB and API Gateway extension methods for `http::Request` types
22
33
use failure::Fail;
44
use http::{header::CONTENT_TYPE, Request as HttpRequest};
@@ -8,14 +8,18 @@ use serde_urlencoded;
88

99
use crate::{request::RequestContext, strmap::StrMap};
1010

11-
/// API gateway pre-parsed http query string parameters
11+
/// ALB/API gateway pre-parsed http query string parameters
1212
pub(crate) struct QueryStringParameters(pub(crate) StrMap);
1313

1414
/// API gateway pre-extracted url path parameters
15+
///
16+
/// These will always be empty for ALB requests
1517
pub(crate) struct PathParameters(pub(crate) StrMap);
1618

1719
/// API gateway configured
1820
/// [stage variables](https://docs.aws.amazon.com/apigateway/latest/developerguide/stage-variables.html)
21+
///
22+
/// These will always be empty for ALB requests
1923
pub(crate) struct StageVariables(pub(crate) StrMap);
2024

2125
/// Payload deserialization errors
@@ -30,9 +34,13 @@ pub enum PayloadError {
3034
}
3135

3236
/// Extentions for `lambda_http::Request` structs that
33-
/// provide access to [API gateway features](https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format)
37+
/// provide 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)
38+
/// and [ALB](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/lambda-functions.html)
39+
/// features.
3440
///
35-
/// In addition, you can also access a request's body in deserialized format
41+
/// # Examples
42+
///
43+
/// You can also access a request's body in deserialized format
3644
/// for payloads sent in `application/x-www-form-urlencoded` or
3745
/// `application/x-www-form-urlencoded` format
3846
///
@@ -87,16 +95,23 @@ pub trait RequestExt {
8795
/// No query parameters
8896
/// will yield an empty `StrMap`.
8997
fn query_string_parameters(&self) -> StrMap;
98+
9099
/// Return pre-extracted path parameters, parameter provided in url placeholders
91100
/// `/foo/{bar}/baz/{boom}`,
92101
/// associated with the API gateway request. No path parameters
93102
/// will yield an empty `StrMap`
103+
///
104+
/// These will always be empty for ALB triggered requests
94105
fn path_parameters(&self) -> StrMap;
106+
95107
/// Return [stage variables](https://docs.aws.amazon.com/apigateway/latest/developerguide/stage-variables.html)
96108
/// associated with the API gateway request. No stage parameters
97109
/// will yield an empty `StrMap`
110+
///
111+
/// These will always be empty for ALB triggered requests
98112
fn stage_variables(&self) -> StrMap;
99-
/// Return request context data assocaited with the API gateway request
113+
114+
/// Return request context data assocaited with the ALB or API gateway request
100115
fn request_context(&self) -> RequestContext;
101116

102117
/// Return the Result of a payload parsed into a serde Deserializeable
@@ -162,21 +177,21 @@ mod tests {
162177
use serde_derive::Deserialize;
163178
use std::collections::HashMap;
164179

165-
use crate::{GatewayRequest, RequestExt, StrMap};
180+
use crate::{LambdaRequest, RequestExt, StrMap};
166181

167182
#[test]
168183
fn requests_have_query_string_ext() {
169184
let mut headers = HeaderMap::new();
170185
headers.insert("Host", "www.rust-lang.org".parse().unwrap());
171186
let mut query = HashMap::new();
172187
query.insert("foo".to_owned(), vec!["bar".to_owned()]);
173-
let gwr: GatewayRequest<'_> = GatewayRequest {
188+
let lambda_request = LambdaRequest {
174189
path: "/foo".into(),
175190
headers,
176191
query_string_parameters: StrMap(query.clone().into()),
177-
..GatewayRequest::default()
192+
..LambdaRequest::default()
178193
};
179-
let actual = HttpRequest::from(gwr);
194+
let actual = HttpRequest::from(lambda_request);
180195
assert_eq!(actual.query_string_parameters(), StrMap(query.clone().into()));
181196
}
182197

@@ -190,13 +205,13 @@ mod tests {
190205
foo: String,
191206
baz: usize,
192207
}
193-
let gwr: GatewayRequest<'_> = GatewayRequest {
208+
let lambda_request = LambdaRequest {
194209
path: "/foo".into(),
195210
headers,
196211
body: Some("foo=bar&baz=2".into()),
197-
..GatewayRequest::default()
212+
..LambdaRequest::default()
198213
};
199-
let actual = HttpRequest::from(gwr);
214+
let actual = HttpRequest::from(lambda_request);
200215
let payload: Option<Payload> = actual.payload().unwrap_or_default();
201216
assert_eq!(
202217
payload,
@@ -212,13 +227,13 @@ mod tests {
212227
let mut headers = HeaderMap::new();
213228
headers.insert("Host", "www.rust-lang.org".parse().unwrap());
214229
headers.insert("Content-Type", "application/x-www-form-urlencoded".parse().unwrap());
215-
let gwr: GatewayRequest<'_> = GatewayRequest {
230+
let lambda_request = LambdaRequest {
216231
path: "/foo".into(),
217232
headers,
218233
body: Some("foo=bar&baz=2".into()),
219-
..GatewayRequest::default()
234+
..LambdaRequest::default()
220235
};
221-
let actual = HttpRequest::from(gwr);
236+
let actual = HttpRequest::from(lambda_request);
222237
let mut expected = HashMap::new();
223238
expected.insert("foo".to_string(), "bar".to_string());
224239
expected.insert("baz".to_string(), "2".to_string());
@@ -236,13 +251,13 @@ mod tests {
236251
foo: String,
237252
baz: usize,
238253
}
239-
let gwr: GatewayRequest<'_> = GatewayRequest {
254+
let lambda_request: LambdaRequest<'_> = LambdaRequest {
240255
path: "/foo".into(),
241256
headers,
242257
body: Some(r#"{"foo":"bar", "baz": 2}"#.into()),
243-
..GatewayRequest::default()
258+
..LambdaRequest::default()
244259
};
245-
let actual = HttpRequest::from(gwr);
260+
let actual = HttpRequest::from(lambda_request);
246261
let payload: Option<Payload> = actual.payload().unwrap_or_default();
247262
assert_eq!(
248263
payload,

lambda-http/src/lib.rs

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,26 @@
11
#![warn(missing_docs)]
22
//#![deny(warnings)]
3-
//! Enriches `lambda_runtime` with `http` types targeting API Gateway proxy events
3+
//! Enriches the `lambda_runtime` crate with [http](https://github.com/hyperium/http)
4+
//! types targeting ALB and API Gateway proxy events.
45
//!
5-
//! # Example
6+
//! Though ALB and API Gateway proxy events are separate Lambda triggers, they both share
7+
//! similar shapes that contextually map to an http request handler. From a application perspective
8+
//! the differences shouldn't matter. This crate
9+
//! abstracts over both using standard [http](https://github.com/hyperium/http) types allowing
10+
//! you to focus more on your application while giving you to the flexibility to
11+
//! transparently use whichever http trigger suits your application's needs best.
12+
//!
13+
//! # Examples
614
//!
715
//! ```rust,no_run
816
//! use lambda_http::{lambda, IntoResponse, Request, RequestExt};
917
//! use lambda_runtime::{Context, HandlerError};
1018
//!
1119
//! fn main() {
12-
//! lambda!(handler)
20+
//! lambda!(hello)
1321
//! }
1422
//!
15-
//! fn handler(
23+
//! fn hello(
1624
//! request: Request,
1725
//! _ctx: Context
1826
//! ) -> Result<impl IntoResponse, HandlerError> {
@@ -56,12 +64,12 @@ mod response;
5664
mod strmap;
5765

5866
pub use crate::{body::Body, ext::RequestExt, response::IntoResponse, strmap::StrMap};
59-
use crate::{request::GatewayRequest, response::GatewayResponse};
67+
use crate::{request::LambdaRequest, response::LambdaResponse};
6068

6169
/// Type alias for `http::Request`s with a fixed `lambda_http::Body` body
6270
pub type Request = http::Request<Body>;
6371

64-
/// Functions acting as API Gateway handlers must conform to this type.
72+
/// Functions serving as ALB and API Gateway handlers must conform to this type.
6573
pub trait Handler<R> {
6674
/// Run the handler.
6775
fn run(&mut self, event: Request, ctx: Context) -> Result<R, HandlerError>;
@@ -76,7 +84,7 @@ where
7684
}
7785
}
7886

79-
/// Creates a new `lambda_runtime::Runtime` and begins polling for API Gateway events
87+
/// Creates a new `lambda_runtime::Runtime` and begins polling for ALB and API Gateway events
8088
///
8189
/// # Arguments
8290
///
@@ -91,15 +99,16 @@ where
9199
// handler requires a mutable ref
92100
let mut func = f;
93101
lambda::start(
94-
|req: GatewayRequest<'_>, ctx: Context| {
102+
|req: LambdaRequest<'_>, ctx: Context| {
103+
let is_alb = req.request_context.is_alb();
95104
func.run(req.into(), ctx)
96-
.map(|resp| GatewayResponse::from(resp.into_response()))
105+
.map(|resp| LambdaResponse::from_response(is_alb, resp.into_response()))
97106
},
98107
runtime,
99108
)
100109
}
101110

102-
/// A macro for starting new handler's poll for API Gateway events
111+
/// A macro for starting new handler's poll for API Gateway and ALB events
103112
#[macro_export]
104113
macro_rules! lambda {
105114
($handler:expr) => {

0 commit comments

Comments
 (0)