Skip to content

support both apigw and alb events as http::{Request,Response} #64

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jan 2, 2019
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion lambda-http/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ version = "0.1.0"
authors = ["Doug Tangren"]
edition = "2018"
description = "Rust API Gateway proxy event interfaces for AWS Lambda"
keywords = ["AWS", "Lambda", "APIGateway", "Rust", "API"]
keywords = ["AWS", "Lambda", "APIGateway", "ALB", "API"]
license = "Apache-2.0"
homepage = "https://github.com/awslabs/aws-lambda-rust-runtime"
repository = "https://github.com/awslabs/aws-lambda-rust-runtime"
Expand All @@ -30,3 +30,4 @@ serde_urlencoded = "0.5"
[dev-dependencies]
log = "^0.4"
simple_logger = "^1"

6 changes: 3 additions & 3 deletions lambda-http/src/body.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
//! Provides an API Gateway oriented request and response body entity interface
//! Provides an ALB / API Gateway oriented request and response body entity interface

use std::{borrow::Cow, ops::Deref};

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

/// Representation of http request and response bodies as supported
/// by API Gateway.
/// by API Gateway and ALBs.
///
/// These come in three flavors
/// * `Empty` ( no body )
/// * `Text` ( text data )
/// * `Binary` ( binary data )
///
/// Body types can be `Deref` and `AsRef`'d into `[u8]` types much like the `hyper` crate
/// Body types can be `Deref` and `AsRef`'d into `[u8]` types much like the [hyper crate](https://crates.io/crates/hyper)
///
/// # Examples
///
Expand Down
49 changes: 32 additions & 17 deletions lambda-http/src/ext.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! API Gateway extension methods for `http::Request` types
//! ALB and API Gateway extension methods for `http::Request` types

use failure::Fail;
use http::{header::CONTENT_TYPE, Request as HttpRequest};
Expand All @@ -8,14 +8,18 @@ use serde_urlencoded;

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

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

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

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

/// Payload deserialization errors
Expand All @@ -30,9 +34,13 @@ pub enum PayloadError {
}

/// Extentions for `lambda_http::Request` structs that
/// 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)
/// 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)
/// and [ALB](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/lambda-functions.html)
/// features.
///
/// # Examples
///
/// In addition, you can also access a request's body in deserialized format
/// You can also access a request's body in deserialized format
/// for payloads sent in `application/x-www-form-urlencoded` or
/// `application/x-www-form-urlencoded` format
///
Expand Down Expand Up @@ -87,16 +95,23 @@ pub trait RequestExt {
/// No query parameters
/// will yield an empty `StrMap`.
fn query_string_parameters(&self) -> StrMap;

/// Return pre-extracted path parameters, parameter provided in url placeholders
/// `/foo/{bar}/baz/{boom}`,
/// associated with the API gateway request. No path parameters
/// will yield an empty `StrMap`
///
/// These will always be empty for ALB triggered requests
fn path_parameters(&self) -> StrMap;

/// Return [stage variables](https://docs.aws.amazon.com/apigateway/latest/developerguide/stage-variables.html)
/// associated with the API gateway request. No stage parameters
/// will yield an empty `StrMap`
///
/// These will always be empty for ALB triggered requests
fn stage_variables(&self) -> StrMap;
/// Return request context data assocaited with the API gateway request

/// Return request context data assocaited with the ALB or API gateway request
fn request_context(&self) -> RequestContext;

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

use crate::{GatewayRequest, RequestExt, StrMap};
use crate::{LambdaRequest, RequestExt, StrMap};

#[test]
fn requests_have_query_string_ext() {
let mut headers = HeaderMap::new();
headers.insert("Host", "www.rust-lang.org".parse().unwrap());
let mut query = HashMap::new();
query.insert("foo".to_owned(), vec!["bar".to_owned()]);
let gwr: GatewayRequest<'_> = GatewayRequest {
let lambda_request = LambdaRequest {
path: "/foo".into(),
headers,
query_string_parameters: StrMap(query.clone().into()),
..GatewayRequest::default()
..LambdaRequest::default()
};
let actual = HttpRequest::from(gwr);
let actual = HttpRequest::from(lambda_request);
assert_eq!(actual.query_string_parameters(), StrMap(query.clone().into()));
}

Expand All @@ -190,13 +205,13 @@ mod tests {
foo: String,
baz: usize,
}
let gwr: GatewayRequest<'_> = GatewayRequest {
let lambda_request = LambdaRequest {
path: "/foo".into(),
headers,
body: Some("foo=bar&baz=2".into()),
..GatewayRequest::default()
..LambdaRequest::default()
};
let actual = HttpRequest::from(gwr);
let actual = HttpRequest::from(lambda_request);
let payload: Option<Payload> = actual.payload().unwrap_or_default();
assert_eq!(
payload,
Expand All @@ -212,13 +227,13 @@ mod tests {
let mut headers = HeaderMap::new();
headers.insert("Host", "www.rust-lang.org".parse().unwrap());
headers.insert("Content-Type", "application/x-www-form-urlencoded".parse().unwrap());
let gwr: GatewayRequest<'_> = GatewayRequest {
let lambda_request = LambdaRequest {
path: "/foo".into(),
headers,
body: Some("foo=bar&baz=2".into()),
..GatewayRequest::default()
..LambdaRequest::default()
};
let actual = HttpRequest::from(gwr);
let actual = HttpRequest::from(lambda_request);
let mut expected = HashMap::new();
expected.insert("foo".to_string(), "bar".to_string());
expected.insert("baz".to_string(), "2".to_string());
Expand All @@ -236,11 +251,11 @@ mod tests {
foo: String,
baz: usize,
}
let gwr: GatewayRequest<'_> = GatewayRequest {
let gwr: LambdaRequest<'_> = LambdaRequest {
path: "/foo".into(),
headers,
body: Some(r#"{"foo":"bar", "baz": 2}"#.into()),
..GatewayRequest::default()
..LambdaRequest::default()
};
let actual = HttpRequest::from(gwr);
let payload: Option<Payload> = actual.payload().unwrap_or_default();
Expand Down
29 changes: 19 additions & 10 deletions lambda-http/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
#![warn(missing_docs)]
//#![deny(warnings)]
//! Enriches `lambda_runtime` with `http` types targeting API Gateway proxy events
//! Enriches the `lambda_runtime` crate with [http](https://github.com/hyperium/http)
//! types targeting ALB and API Gateway proxy events.
//!
//! # Example
//! Though ALB and API Gateway proxy events are separate Lambda triggers, they both share
//! similar shapes that contextually map to an http request handler. From a application perspective
//! the differences shouldn't matter. This crate
//! abstracts over both using standard [http](https://github.com/hyperium/http) types allowing
//! you to focus more on your application while giving you to the flexibility to
//! transparently use whichever http trigger suits your application's needs best.
//!
//! # Examples
//!
//! ```rust,no_run
//! use lambda_http::{lambda, IntoResponse, Request, RequestExt};
//! use lambda_runtime::{Context, HandlerError};
//!
//! fn main() {
//! lambda!(handler)
//! lambda!(hello)
//! }
//!
//! fn handler(
//! fn hello(
//! request: Request,
//! _ctx: Context
//! ) -> Result<impl IntoResponse, HandlerError> {
Expand Down Expand Up @@ -56,12 +64,12 @@ mod response;
mod strmap;

pub use crate::{body::Body, ext::RequestExt, response::IntoResponse, strmap::StrMap};
use crate::{request::GatewayRequest, response::GatewayResponse};
use crate::{request::LambdaRequest, response::LambdaResponse};

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

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

/// Creates a new `lambda_runtime::Runtime` and begins polling for API Gateway events
/// Creates a new `lambda_runtime::Runtime` and begins polling for ALB and API Gateway events
///
/// # Arguments
///
Expand All @@ -91,15 +99,16 @@ where
// handler requires a mutable ref
let mut func = f;
lambda::start(
|req: GatewayRequest<'_>, ctx: Context| {
|req: LambdaRequest<'_>, ctx: Context| {
let is_alb = req.request_context.is_alb();
func.run(req.into(), ctx)
.map(|resp| GatewayResponse::from(resp.into_response()))
.map(|resp| LambdaResponse::from_response(is_alb, resp.into_response()))
},
runtime,
)
}

/// A macro for starting new handler's poll for API Gateway events
/// A macro for starting new handler's poll for API Gateway and ALB events
#[macro_export]
macro_rules! lambda {
($handler:expr) => {
Expand Down
Loading