#![deny(missing_docs)]
#[cfg(test)]
#[macro_use]
extern crate maplit;
pub use http::{self, Response};
use netlify_lambda::Handler as LambdaHandler;
pub use netlify_lambda::{self as lambda, Context};
pub use netlify_lambda_attributes::lambda;
use aws_lambda_events::encodings::Body;
use aws_lambda_events::event::apigw::ApiGatewayProxyRequest;
pub mod ext;
pub mod request;
mod response;
mod strmap;
pub use crate::{ext::RequestExt, response::IntoResponse, strmap::StrMap};
use crate::{
request::{self as lambda_request, LambdaRequest, RequestOrigin},
response::LambdaResponse,
};
use std::{
future::Future,
pin::Pin,
task::{Context as TaskContext, Poll},
};
pub(crate) type Error = Box<dyn std::error::Error + Send + Sync + 'static>;
pub type Request = http::Request<Body>;
pub trait Handler: Sized {
type Error;
type Response: IntoResponse;
type Fut: Future<Output = Result<Self::Response, Self::Error>> + 'static;
fn call(&mut self, event: Request, context: Context) -> Self::Fut;
}
impl<F, R, Fut> Handler for F
where
F: Fn(Request, Context) -> Fut,
R: IntoResponse,
Fut: Future<Output = Result<R, Error>> + Send + 'static,
{
type Response = R;
type Error = Error;
type Fut = Fut;
fn call(&mut self, event: Request, context: Context) -> Self::Fut {
(self)(event, context)
}
}
#[doc(hidden)]
pub struct TransformResponse<R, E> {
request_origin: RequestOrigin,
fut: Pin<Box<dyn Future<Output = Result<R, E>>>>,
}
impl<R, E> Future for TransformResponse<R, E>
where
R: IntoResponse,
{
type Output = Result<LambdaResponse, E>;
fn poll(mut self: Pin<&mut Self>, cx: &mut TaskContext) -> Poll<Self::Output> {
match self.fut.as_mut().poll(cx) {
Poll::Ready(result) => Poll::Ready(
result.map(|resp| LambdaResponse::from_response(&self.request_origin, resp.into_response())),
),
Poll::Pending => Poll::Pending,
}
}
}
pub fn handler<H: Handler>(handler: H) -> Adapter<H> {
Adapter { handler }
}
pub struct Adapter<H: Handler> {
handler: H,
}
impl<H: Handler> Handler for Adapter<H> {
type Response = H::Response;
type Error = H::Error;
type Fut = H::Fut;
fn call(&mut self, event: Request, context: Context) -> Self::Fut {
self.handler.call(event, context)
}
}
impl<H: Handler> LambdaHandler<LambdaRequest, LambdaResponse> for Adapter<H> {
type Error = H::Error;
type Fut = TransformResponse<H::Response, Self::Error>;
fn call(&mut self, event: LambdaRequest, context: Context) -> Self::Fut {
let request_origin = event.request_origin();
let fut = Box::pin(self.handler.call(event.into(), context));
TransformResponse { request_origin, fut }
}
}
pub fn proxy_handler<H: Handler>(handler: H) -> ProxyAdapter<H> {
ProxyAdapter { handler }
}
pub struct ProxyAdapter<H: Handler> {
handler: H,
}
impl<H: Handler> Handler for ProxyAdapter<H> {
type Response = H::Response;
type Error = H::Error;
type Fut = H::Fut;
fn call(&mut self, event: Request, context: Context) -> Self::Fut {
self.handler.call(event, context)
}
}
impl<H: Handler> LambdaHandler<ApiGatewayProxyRequest, LambdaResponse> for ProxyAdapter<H> {
type Error = H::Error;
type Fut = TransformResponse<H::Response, Self::Error>;
fn call(&mut self, event: ApiGatewayProxyRequest, context: Context) -> Self::Fut {
let request_origin = RequestOrigin::ApiGatewayV1;
let req = lambda_request::into_proxy_request(event);
let fut = Box::pin(self.handler.call(req, context));
TransformResponse { request_origin, fut }
}
}