aws_smithy_http_server/request/
lambda.rs

1/*
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6//! The [`lambda_http`] types included in [`http::Request`]s when [`LambdaHandler`](crate::routing::LambdaHandler) is
7//! used. Each are given a [`FromParts`] implementation for easy use within handlers.
8
9use lambda_http::request::RequestContext;
10#[doc(inline)]
11pub use lambda_http::{
12    aws_lambda_events::apigw::{ApiGatewayProxyRequestContext, ApiGatewayV2httpRequestContext},
13    Context,
14};
15use thiserror::Error;
16
17use super::{internal_server_error, FromParts};
18use crate::{body::BoxBody, response::IntoResponse};
19
20/// The [`Context`] was not found in the [`http::Request`] extensions.
21///
22/// Use [`LambdaHandler`](crate::routing::LambdaHandler) to ensure it's present.
23#[non_exhaustive]
24#[derive(Debug, Error)]
25#[error("`Context` is not present in the `http::Request` extensions - consider using `aws_smithy_http_server::routing::LambdaHandler`")]
26pub struct MissingContext;
27
28impl<Protocol> IntoResponse<Protocol> for MissingContext {
29    fn into_response(self) -> http::Response<BoxBody> {
30        internal_server_error()
31    }
32}
33
34impl<P> FromParts<P> for Context {
35    type Rejection = MissingContext;
36
37    fn from_parts(parts: &mut http::request::Parts) -> Result<Self, Self::Rejection> {
38        parts.extensions.remove().ok_or(MissingContext)
39    }
40}
41
42#[derive(Debug, Error)]
43enum MissingGatewayContextTypeV1 {
44    #[error("`RequestContext` is not present in the `http::Request` extensions - consider using `aws_smithy_http_server::routing::LambdaHandler`")]
45    MissingRequestContext,
46    #[error("`RequestContext::ApiGatewayV2` is present in the `http::Request` extensions - consider using the `aws_smithy_http_server::request::lambda::ApiGatewayV2httpRequestContext` extractor")]
47    VersionMismatch,
48}
49
50/// The [`RequestContext::ApiGatewayV1`] was not found in the [`http::Request`] extensions.
51///
52/// Use [`LambdaHandler`](crate::routing::LambdaHandler) to ensure it's present and ensure that you're using "ApiGatewayV1".
53#[derive(Debug, Error)]
54#[error("{inner}")]
55pub struct MissingGatewayContextV1 {
56    inner: MissingGatewayContextTypeV1,
57}
58
59impl<Protocol> IntoResponse<Protocol> for MissingGatewayContextV1 {
60    fn into_response(self) -> http::Response<BoxBody> {
61        internal_server_error()
62    }
63}
64
65impl<P> FromParts<P> for ApiGatewayProxyRequestContext {
66    type Rejection = MissingGatewayContextV1;
67
68    fn from_parts(parts: &mut http::request::Parts) -> Result<Self, Self::Rejection> {
69        let context = parts.extensions.remove().ok_or(MissingGatewayContextV1 {
70            inner: MissingGatewayContextTypeV1::MissingRequestContext,
71        })?;
72        if let RequestContext::ApiGatewayV1(context) = context {
73            Ok(context)
74        } else {
75            Err(MissingGatewayContextV1 {
76                inner: MissingGatewayContextTypeV1::VersionMismatch,
77            })
78        }
79    }
80}
81
82#[derive(Debug, Error)]
83enum MissingGatewayContextTypeV2 {
84    #[error("`RequestContext` is not present in the `http::Request` extensions - consider using `aws_smithy_http_server::routing::LambdaHandler`")]
85    MissingRequestContext,
86    #[error("`RequestContext::ApiGatewayV1` is present in the `http::Request` extensions - consider using the `aws_smithy_http_server::request::lambda::ApiGatewayProxyRequestContext` extractor")]
87    VersionMismatch,
88}
89
90/// The [`RequestContext::ApiGatewayV2`] was not found in the [`http::Request`] extensions.
91///
92/// Use [`LambdaHandler`](crate::routing::LambdaHandler) to ensure it's present and ensure that you're using "ApiGatewayV2".
93#[derive(Debug, Error)]
94#[error("{inner}")]
95pub struct MissingGatewayContextV2 {
96    inner: MissingGatewayContextTypeV2,
97}
98
99impl<Protocol> IntoResponse<Protocol> for MissingGatewayContextV2 {
100    fn into_response(self) -> http::Response<BoxBody> {
101        internal_server_error()
102    }
103}
104
105impl<P> FromParts<P> for ApiGatewayV2httpRequestContext {
106    type Rejection = MissingGatewayContextV2;
107
108    fn from_parts(parts: &mut http::request::Parts) -> Result<Self, Self::Rejection> {
109        let context = parts.extensions.remove().ok_or(MissingGatewayContextV2 {
110            inner: MissingGatewayContextTypeV2::MissingRequestContext,
111        })?;
112        if let RequestContext::ApiGatewayV2(context) = context {
113            Ok(context)
114        } else {
115            Err(MissingGatewayContextV2 {
116                inner: MissingGatewayContextTypeV2::VersionMismatch,
117            })
118        }
119    }
120}