samcli/local/events/api_event.py (291 lines of code) (raw):
"""Holds Classes for API Gateway to Lambda Events"""
import uuid
from datetime import datetime
from time import time
from typing import Any, Dict
from samcli.local.apigw.route import Route
class ContextIdentity:
def __init__(
self,
api_key=None,
user_arn=None,
cognito_authentication_type=None,
caller=None,
user_agent="Custom User Agent String",
user=None,
cognito_identity_pool_id=None,
cognito_authentication_provider=None,
source_ip="127.0.0.1",
account_id=None,
):
"""
Constructs a ContextIdentity
:param str api_key: API Key used for the request
:param str user_arn: ARN of the caller
:param str cognito_authentication_type: Auth Type used
:param str caller: Caller that make the request
:param str user_agent: User agent (Default: Custom User Agent String)
:param str user: User
:param str cognito_identity_pool_id: Identity Pool Id used
:param str cognito_authentication_provider: Auth Provider
:param str source_ip: Source Ip of the request (Default: 127.0.0.1)
:param str account_id: Account Id of the request
"""
self.api_key = api_key
self.user_arn = user_arn
self.cognito_authentication_type = cognito_authentication_type
self.caller = caller
self.user_agent = user_agent
self.user = user
self.cognito_identity_pool_id = cognito_identity_pool_id
self.cognito_authentication_provider = cognito_authentication_provider
self.source_ip = source_ip
self.account_id = account_id
def to_dict(self):
"""
Constructs an dictionary representation of the Identity Object to be used in serializing to JSON
:return: dict representing the object
"""
json_dict = {
"apiKey": self.api_key,
"userArn": self.user_arn,
"cognitoAuthenticationType": self.cognito_authentication_type,
"caller": self.caller,
"userAgent": self.user_agent,
"user": self.user,
"cognitoIdentityPoolId": self.cognito_identity_pool_id,
"cognitoAuthenticationProvider": self.cognito_authentication_provider,
"sourceIp": self.source_ip,
"accountId": self.account_id,
}
return json_dict
class RequestContext:
def __init__(
self,
resource_id="123456",
api_id="1234567890",
resource_path=None,
http_method=None,
request_id=str(uuid.uuid4()),
account_id="123456789012",
stage=None,
identity=None,
extended_request_id=None,
path=None,
protocol=None,
domain_name=None,
request_time_epoch=int(time()),
request_time=datetime.utcnow().strftime("%d/%b/%Y:%H:%M:%S +0000"),
operation_name=None,
):
"""
Constructs a RequestContext
:param str resource_id: Resource Id of the Request (Default: 123456)
:param str api_id: Api Id for the Request (Default: 1234567890)
:param str resource_path: Path for the Request
:param str http_method: HTTPMethod for the request
:param str request_id: Request Id for the request (Default: generated uuid id)
:param str account_id: Account Id of the Request (Default: 123456789012)
:param str stage: Api Gateway Stage
:param ContextIdentity identity: Identity for the Request
:param str extended_request_id:
:param str path:
:param str operation_name: Swagger operationId for the route
:param str protocol: Optional, the protocal to make the request
:param str domain_name: Optional, the name of the domain
:param int request_time_epoch: Optional, an epoch timestamp to override the request time
:param datetime request_time: Optional, a datetime object to override the request time
"""
self.resource_id = resource_id
self.api_id = api_id
self.resource_path = resource_path
self.http_method = http_method
self.request_id = request_id
self.account_id = account_id
self.stage = stage
self.identity = identity
self.extended_request_id = extended_request_id
self.path = path
self.protocol = protocol
self.domain_name = domain_name
self.request_time_epoch = request_time_epoch
self.request_time = request_time
self.operation_name = operation_name
def to_dict(self) -> Dict[str, Any]:
"""
Constructs an dictionary representation of the RequestContext Object to be used in serializing to JSON
:return: dict representing the object
"""
identity_dict = {}
if self.identity:
identity_dict = self.identity.to_dict()
json_dict = {
"resourceId": self.resource_id,
"apiId": self.api_id,
"resourcePath": self.resource_path,
"httpMethod": self.http_method,
"requestId": self.request_id,
"accountId": self.account_id,
"stage": self.stage,
"identity": identity_dict,
"extendedRequestId": self.extended_request_id,
"path": self.path,
"protocol": self.protocol,
"domainName": self.domain_name,
"requestTimeEpoch": self.request_time_epoch,
"requestTime": self.request_time,
}
if self.operation_name is not None:
json_dict["operationName"] = self.operation_name
return json_dict
class ApiGatewayLambdaEvent:
def __init__(
self,
http_method=None,
body=None,
resource=None,
request_context=None,
query_string_params=None,
multi_value_query_string_params=None,
headers=None,
multi_value_headers=None,
path_parameters=None,
stage_variables=None,
path=None,
is_base_64_encoded=False,
api_type=Route.API,
):
"""
Constructs an ApiGatewayLambdaEvent
:param str http_method: HTTPMethod of the request
:param str body: Body or data for the request
:param str resource: Resource for the reqeust
:param RequestContext request_context: RequestContext for the request
:param dict query_string_params: Query String parameters
:param dict multi_value_query_string_params: Multi-value Query String parameters
:param dict headers: dict of the request Headers
:param dict multi_value_headers: dict of the multi-value request Headers
:param dict path_parameters: Path Parameters
:param dict stage_variables: API Gateway Stage Variables
:param str path: Path of the request
:param bool is_base_64_encoded: True if the data is base64 encoded.
:param str api_type: The type of API the event is being generated for
"""
if not isinstance(query_string_params, dict) and query_string_params is not None:
raise TypeError("'query_string_params' must be of type dict or None")
if not isinstance(multi_value_query_string_params, dict) and multi_value_query_string_params is not None:
raise TypeError("'multi_value_query_string_params' must be of type dict or None")
if not isinstance(headers, dict) and headers is not None:
raise TypeError("'headers' must be of type dict or None")
if not isinstance(multi_value_headers, dict) and multi_value_headers is not None:
raise TypeError("'multi_value_headers' must be of type dict or None")
if not isinstance(path_parameters, dict) and path_parameters is not None:
raise TypeError("'path_parameters' must be of type dict or None")
if not isinstance(stage_variables, dict) and stage_variables is not None:
raise TypeError("'stage_variables' must be of type dict or None")
self.http_method = http_method
self.body = body
self.resource = resource
self.request_context = request_context
self.query_string_params = query_string_params
self.multi_value_query_string_params = multi_value_query_string_params
self.headers = headers
self.multi_value_headers = multi_value_headers
self.path_parameters = path_parameters
self.stage_variables = stage_variables
self.path = path
self.is_base_64_encoded = is_base_64_encoded
self.api_type = api_type
def to_dict(self) -> Dict[str, Any]:
"""
Constructs an dictionary representation of the ApiGatewayLambdaEvent Object to be used in serializing to JSON
Returns
-------
Dict[str, Any]
Dict representing the object
"""
request_context_dict = {}
if self.request_context:
request_context_dict = self.request_context.to_dict()
json_dict = {
"httpMethod": self.http_method,
"body": self.body if self.body else None,
"resource": self.resource,
"requestContext": request_context_dict,
"queryStringParameters": dict(self.query_string_params) if self.query_string_params else None,
"multiValueQueryStringParameters": (
dict(self.multi_value_query_string_params) if self.multi_value_query_string_params else None
),
"headers": dict(self.headers) if self.headers else None,
"multiValueHeaders": dict(self.multi_value_headers) if self.multi_value_headers else None,
"pathParameters": dict(self.path_parameters) if self.path_parameters else None,
"stageVariables": dict(self.stage_variables) if self.stage_variables else None,
"path": self.path,
"isBase64Encoded": self.is_base_64_encoded,
}
# v1 payloads and rest api payloads are identical save for the version field
if self.api_type == Route.HTTP:
json_dict["version"] = "1.0"
return json_dict
class ContextHTTP:
def __init__(
self, method=None, path=None, protocol="HTTP/1.1", source_ip="127.0.0.1", user_agent="Custom User Agent String"
):
"""
Constructs a ContextHTTP
:param str method: HTTP Method for the request
:param str path: HTTP Path for the request
:param str protocol: HTTP Protocol for the request (Default: HTTP/1.1)
:param str source_ip: Source IP for the request (Default: 127.0.0.1)
:param str user_agent: User agent (Default: Custom User Agent String)
"""
self.method = method
self.path = path
self.protocol = protocol
self.source_ip = source_ip
self.user_agent = user_agent
def to_dict(self):
"""
Constructs an dictionary representation of the HTTP Object to be used
in serializing to JSON
:return: dict representing the object
"""
json_dict = {
"method": self.method,
"path": self.path,
"protocol": self.protocol,
"sourceIp": self.source_ip,
"userAgent": self.user_agent,
}
return json_dict
class RequestContextV2:
def __init__(
self,
account_id="123456789012",
api_id="1234567890",
http=None,
request_id=str(uuid.uuid4()),
route_key=None,
stage=None,
request_time_epoch=None,
request_time=None,
domain_name="localhost",
domain_prefix="localhost",
):
"""
Constructs a RequestContext Version 2.
:param str account_id: Account Id of the Request (Default: 123456789012)
:param str api_id: Api Id for the Request (Default: 1234567890)
:param ContextHTTP http: HTTP for the request
:param str request_id: Request Id for the request (Default: generated uuid id)
:param str route_key: The route key for the route.
:param str stage: Api Gateway V2 Stage
:param int request_time_epoch: Optional, an epoch timestamp to override the request time
:param datetime request_time: Optional, a datetime object to override the request time
:param str domain_name: Optional, the name of the domain (Default: localhost)
:param str domain_prefix: Optional, the prefix of the domain (Default: localhost)
"""
self.account_id = account_id
self.api_id = api_id
self.http = http
self.request_id = request_id
self.route_key = route_key
self.stage = stage
self.request_time_epoch = request_time_epoch
self.request_time = request_time
self.domain_name = domain_name
self.domain_prefix = domain_prefix
def to_dict(self) -> Dict[str, Any]:
"""
Constructs an dictionary representation of the RequestContext Version 2
Object to be used in serializing to JSON
:return: dict representing the object
"""
http_dict = {}
if self.http:
http_dict = self.http.to_dict()
# this could get explicitly passed in as None further up the
# chain so coalescing to $default here to ensure it's never empty
if self.stage is None:
self.stage = "$default"
json_dict = {
"accountId": self.account_id,
"apiId": self.api_id,
"http": http_dict,
"requestId": self.request_id,
"routeKey": self.route_key,
"stage": self.stage,
"time": self.request_time,
"timeEpoch": self.request_time_epoch,
"domainName": "localhost",
"domainPrefix": "localhost",
}
return json_dict
class ApiGatewayV2LambdaEvent:
def __init__(
self,
route_key=None,
raw_path=None,
raw_query_string=None,
cookies=None,
headers=None,
query_string_params=None,
request_context=None,
body=None,
path_parameters=None,
stage_variables=None,
is_base_64_encoded=False,
):
"""
Constructs an ApiGatewayV2LambdaEvent.
:param str route_key: The route key for the route.
:param str raw_path: The raw path of the request.
:param str raw_query_string: The raw query string of the request.
:param list cookies: All cookie headers in the request are combined with commas and added to this field.
:param dict headers: dict of the request Headers. Duplicate headers are combined with commas.
:param dict query_string_params: Query String parameters.
:param RequestContextV2 request_context: RequestContextV2 for the request
:param str body: Body or data for the request
:param dict path_parameters: Path Parameters
:param dict stage_variables: API Gateway Stage Variables
:param bool is_base_64_encoded: True if the data is base64 encoded.
"""
if not isinstance(cookies, list) and cookies is not None:
raise TypeError("'cookies' must be of type list or None")
if not isinstance(headers, dict) and headers is not None:
raise TypeError("'headers' must be of type dict or None")
if not isinstance(query_string_params, dict) and query_string_params is not None:
raise TypeError("'query_string_params' must be of type dict or None")
if not isinstance(path_parameters, dict) and path_parameters is not None:
raise TypeError("'path_parameters' must be of type dict or None")
if not isinstance(stage_variables, dict) and stage_variables is not None:
raise TypeError("'stage_variables' must be of type dict or None")
# convert mutlivalue queries into a comma separated list per API GW documentation for format v2
converted_query_string_params = None
if query_string_params is not None:
converted_query_string_params = {}
for k, v in query_string_params.items():
if isinstance(v, str):
converted_query_string_params[k] = v
else:
converted_query_string_params[k] = ",".join(v)
self.version = "2.0"
self.route_key = route_key
self.raw_path = raw_path
self.raw_query_string = raw_query_string
self.cookies = cookies
self.headers = headers
self.query_string_params = converted_query_string_params
self.request_context = request_context
self.body = body
self.path_parameters = path_parameters
self.is_base_64_encoded = is_base_64_encoded
self.stage_variables = stage_variables
def to_dict(self) -> Dict[str, Any]:
"""
Constructs an dictionary representation of the ApiGatewayLambdaEvent
Version 2 Object to be used in serializing to JSON
Returns
-------
Dict[str, Any]
Dict representing the object
"""
request_context_dict = {}
if self.request_context:
request_context_dict = self.request_context.to_dict()
json_dict = {
"version": self.version,
"routeKey": self.route_key,
"rawPath": self.raw_path,
"rawQueryString": self.raw_query_string,
"cookies": self.cookies,
"headers": self.headers,
"requestContext": request_context_dict,
"body": self.body,
"pathParameters": self.path_parameters,
"stageVariables": self.stage_variables,
"isBase64Encoded": self.is_base_64_encoded,
}
if self.query_string_params:
json_dict["queryStringParameters"] = self.query_string_params
return json_dict