1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
#![warn(missing_docs)] //#![deny(warnings)] //! Enriches the `lambda_runtime` crate with [http](https://github.com/hyperium/http) //! types targeting ALB and API Gateway proxy events. //! //! 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, error::HandlerError}; //! //! fn main() { //! lambda!(hello) //! } //! //! fn hello( //! request: Request, //! _ctx: Context //! ) -> Result<impl IntoResponse, HandlerError> { //! Ok(format!( //! "hello {}", //! request //! .query_string_parameters() //! .get("name") //! .unwrap_or_else(|| "stranger") //! )) //! } //! ``` //! //! You can also provide a closure directly to the `lambda!` macro //! //! ```rust,no_run //! use lambda_http::{lambda, Request, RequestExt}; //! //! fn main() { //! lambda!( //! |request: Request, context| Ok( //! format!( //! "hello {}", //! request.query_string_parameters() //! .get("name") //! .unwrap_or_else(|| "stranger") //! ) //! ) //! ) //! } //! ``` // only externed because maplit doesn't seem to play well with 2018 edition imports #[cfg(test)] #[macro_use] extern crate maplit; pub use http::{self, Response}; use lambda_runtime::{self as lambda, error::HandlerError, Context}; use tokio::runtime::Runtime as TokioRuntime; mod body; mod ext; pub mod request; mod response; mod strmap; pub use crate::{body::Body, ext::RequestExt, response::IntoResponse, strmap::StrMap}; 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 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>; } impl<F, R> Handler<R> for F where F: FnMut(Request, Context) -> Result<R, HandlerError>, { fn run(&mut self, event: Request, ctx: Context) -> Result<R, HandlerError> { (*self)(event, ctx) } } /// Creates a new `lambda_runtime::Runtime` and begins polling for ALB and API Gateway events /// /// # Arguments /// /// * `f` A type that conforms to the `Handler` interface. /// /// # Panics /// The function panics if the Lambda environment variables are not set. pub fn start<R>(f: impl Handler<R>, runtime: Option<TokioRuntime>) where R: IntoResponse, { // handler requires a mutable ref let mut func = f; lambda::start( |req: LambdaRequest<'_>, ctx: Context| { let is_alb = req.request_context.is_alb(); func.run(req.into(), ctx) .map(|resp| LambdaResponse::from_response(is_alb, resp.into_response())) }, runtime, ) } /// A macro for starting new handler's poll for API Gateway and ALB events #[macro_export] macro_rules! lambda { ($handler:expr) => { $crate::start($handler, None) }; ($handler:expr, $runtime:expr) => { $crate::start($handler, Some($runtime)) }; ($handler:ident) => { $crate::start($handler, None) }; ($handler:ident, $runtime:expr) => { $crate::start($handler, Some($runtime)) }; }