def rest_api(self, event_streams, event_replayer): rest_api = _api_gtw.RestApi(self, "{}RestApi".format(self.stack_id)) rest_api.add_usage_plan("RestApiUsagePlan", api_key=_api_gtw.ApiKey(self, "TestApiKey"), api_stages=[ _api_gtw.UsagePlanPerApiStage( api=rest_api, stage=rest_api.deployment_stage) ]) api_role = _iam.Role( self, "RestApiRole", assumed_by=_iam.ServicePrincipal('apigateway.amazonaws.com')) api_role.add_to_policy( _iam.PolicyStatement( actions=['firehose:PutRecord'], resources=[stream.attr_arn for stream in event_streams])) for stream in event_streams: stream_resource = rest_api.root.add_resource( path_part=stream.delivery_stream_name.lower(), ) stream_resource.add_method( 'POST', api_key_required=True, integration=_api_gtw.Integration( type=_api_gtw.IntegrationType.AWS, uri= "arn:aws:apigateway:eu-west-1:firehose:action/PutRecord", integration_http_method='POST', options=_api_gtw.IntegrationOptions( credentials_role=api_role, passthrough_behavior=_api_gtw.PassthroughBehavior. NEVER, request_parameters={ 'integration.request.header.Content-Type': "'application/x-amz-json-1.1'" }, request_templates={ 'application/json': json.dumps({ "DeliveryStreamName": stream.delivery_stream_name, "Record": { "Data": "$util.base64Encode($input.body)" } }) }, integration_responses=[ _api_gtw.IntegrationResponse(status_code="200") ])), method_responses=[_api_gtw.MethodResponse(status_code="200")]) replay = stream_resource.add_resource(path_part='replay') replay.add_method( http_method='POST', integration=_api_gtw.LambdaIntegration(event_replayer), method_responses=[ _api_gtw.MethodResponse(status_code="202"), _api_gtw.MethodResponse(status_code="400") ])
def __init__(self, scope: core.Construct, construct_id: str, apigw_role: _iam.Role, eventBus: _events.EventBus, **kwargs): super().__init__(scope, construct_id, **kwargs) integrationOptions = \ _apigw.IntegrationOptions( credentials_role=apigw_role, request_parameters={ "integration.request.header.X-Amz-Target": "'AWSEvents.PutEvents'", "integration.request.header.Content-Type": "'application/x-amz-json-1.1'", }, request_templates={ "application/json":'#set($language=$input.params(\'language\'))\n{"Entries": [{"Source": "com.amazon.alexa.$language", "Detail": ' + \ '"$util.escapeJavaScript($input.body)",' + \ ' "Resources": ["resource1", "resource2"], "DetailType": "myDetailType", "EventBusName": "' + eventBus.event_bus_name + '"}]}' }, integration_responses=[_apigw.IntegrationResponse( status_code="200", response_templates={"application/json": ""}, )] ) # Integration API Gateway with EventBridge integrationEventBridge = _apigw.Integration( type=_apigw.IntegrationType("AWS"), integration_http_method="POST", options=integrationOptions, uri= f"arn:aws:apigateway:{os.environ['CDK_DEFAULT_REGION']}:events:path//" ) myApi = _apigw.RestApi(self, construct_id) # myApi.root.add_method("POST", # integrationEventBridge, # method_responses=[ # _apigw.MethodResponse( # status_code="200" # ) # ] # ) languageResource = myApi.root.add_resource("{language}") languageResource.add_method( "POST", integrationEventBridge, method_responses=[_apigw.MethodResponse(status_code="200")], request_models={"application/json": self.getModel(myApi)}, request_validator=_apigw.RequestValidator( self, "myValidator", rest_api=myApi, validate_request_body=True))
def __init__(self, scope: core.Construct, id: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) ### # Let's create our own Event Bus for this rather than using default ### bus = events.EventBus(self, 'DestinedEventBus', event_bus_name='the-destined-lambda') ### # Destinations need invoked Asynchronously so let's use SNS ### topic = sns.Topic(self, 'theDestinedLambdaTopic', display_name='The Destined Lambda CDK Pattern Topic') ### # Lambda configured with success and failure destinations # Note the actual lambda has no EventBridge code inside it ### destined_lambda = _lambda.Function( self, "destinedLambda", runtime=_lambda.Runtime.NODEJS_12_X, handler="destinedLambda.handler", code=_lambda.Code.from_asset("lambda_fns"), retry_attempts=0, on_success=destinations.EventBridgeDestination(event_bus=bus), on_failure=destinations.EventBridgeDestination(event_bus=bus)) topic.add_subscription( subscriptions.LambdaSubscription(destined_lambda)) ### # This is a lambda that will be called by onSuccess for destinedLambda # It simply prints the event it receives to the cloudwatch logs ### success_lambda = _lambda.Function( self, "successLambda", runtime=_lambda.Runtime.NODEJS_12_X, handler="success.handler", code=_lambda.Code.from_asset("lambda_fns"), timeout=core.Duration.seconds(3)) ### # EventBridge Rule to send events to our success lambda # Notice how we can still do event filtering based on the json payload returned by the destined lambda ### success_rule = events.Rule( self, 'successRule', event_bus=bus, description= 'all success events are caught here and logged centrally', event_pattern=events.EventPattern( detail={ "requestContext": { "condition": ["Success"] }, "responsePayload": { "source": ["cdkpatterns.the-destined-lambda"], "action": ["message"] } })) success_rule.add_target(targets.LambdaFunction(success_lambda)) ### # This is a lambda that will be called by onFailure for destinedLambda # It simply prints the event it receives to the cloudwatch logs. # Notice how it includes the message that came into destined lambda to make it fail so you have # everything you need to do retries or manually investigate ### failure_lambda = _lambda.Function( self, "failureLambda", runtime=_lambda.Runtime.NODEJS_12_X, handler="failure.handler", code=_lambda.Code.from_asset("lambda_fns"), timeout=core.Duration.seconds(3)) ### # EventBridge Rule to send events to our failure lambda ### failure_rule = events.Rule( self, 'failureRule', event_bus=bus, description= 'all failure events are caught here and logged centrally', event_pattern=events.EventPattern( detail={"responsePayload": { "errorType": ["Error"] }})) failure_rule.add_target(targets.LambdaFunction(failure_lambda)) ### # API Gateway Creation # This is complicated because it transforms the incoming json payload into a query string url # this url is used to post the payload to sns without a lambda inbetween ### gateway = api_gw.RestApi( self, 'theDestinedLambdaAPI', deploy_options=api_gw.StageOptions( metrics_enabled=True, logging_level=api_gw.MethodLoggingLevel.INFO, data_trace_enabled=True, stage_name='prod')) # Give our gateway permissions to interact with SNS api_gw_sns_role = iam.Role( self, 'ApiGatewaySNSRole', assumed_by=iam.ServicePrincipal('apigateway.amazonaws.com')) topic.grant_publish(api_gw_sns_role) # shortening the lines of later code schema = api_gw.JsonSchema schema_type = api_gw.JsonSchemaType # Because this isn't a proxy integration, we need to define our response model response_model = gateway.add_model( 'ResponseModel', content_type='application/json', model_name='ResponseModel', schema=schema( schema=api_gw.JsonSchemaVersion.DRAFT4, title='pollResponse', type=schema_type.OBJECT, properties={'message': schema(type=schema_type.STRING)})) error_response_model = gateway.add_model( 'ErrorResponseModel', content_type='application/json', model_name='ErrorResponseModel', schema=schema(schema=api_gw.JsonSchemaVersion.DRAFT4, title='errorResponse', type=schema_type.OBJECT, properties={ 'state': schema(type=schema_type.STRING), 'message': schema(type=schema_type.STRING) })) request_template = "Action=Publish&" + \ "TargetArn=$util.urlEncode('" + topic.topic_arn + "')&" + \ "Message=please $input.params().querystring.get('mode')&" + \ "Version=2010-03-31" # This is the VTL to transform the error response error_template = { "state": 'error', "message": "$util.escapeJavaScript($input.path('$.errorMessage'))" } error_template_string = json.dumps(error_template, separators=(',', ':')) # This is how our gateway chooses what response to send based on selection_pattern integration_options = api_gw.IntegrationOptions( credentials_role=api_gw_sns_role, request_parameters={ 'integration.request.header.Content-Type': "'application/x-www-form-urlencoded'" }, request_templates={"application/json": request_template}, passthrough_behavior=api_gw.PassthroughBehavior.NEVER, integration_responses=[ api_gw.IntegrationResponse( status_code='200', response_templates={ "application/json": json.dumps({"message": 'Message added to SNS topic'}) }), api_gw.IntegrationResponse( selection_pattern="^\[Error\].*", status_code='400', response_templates={ "application/json": error_template_string }, response_parameters={ 'method.response.header.Content-Type': "'application/json'", 'method.response.header.Access-Control-Allow-Origin': "'*'", 'method.response.header.Access-Control-Allow-Credentials': "'true'" }) ]) # Add an SendEvent endpoint onto the gateway gateway.root.add_resource('SendEvent') \ .add_method('GET', api_gw.Integration(type=api_gw.IntegrationType.AWS, integration_http_method='POST', uri='arn:aws:apigateway:us-east-1:sns:path//', options=integration_options ), method_responses=[ api_gw.MethodResponse(status_code='200', response_parameters={ 'method.response.header.Content-Type': True, 'method.response.header.Access-Control-Allow-Origin': True, 'method.response.header.Access-Control-Allow-Credentials': True }, response_models={ 'application/json': response_model }), api_gw.MethodResponse(status_code='400', response_parameters={ 'method.response.header.Content-Type': True, 'method.response.header.Access-Control-Allow-Origin': True, 'method.response.header.Access-Control-Allow-Credentials': True }, response_models={ 'application/json': error_response_model }), ] )
def __init__(self, scope: core.Construct, id: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) api_name='voncv' cert_arn='arn:aws:acm:us-east-1:921279086507:certificate/1cdc5fa6-0978-4c3c-96fa-ced4188b4fd0' # Example automatically generated. See https://github.com/aws/jsii/issues/826 cert = acm.Certificate.from_certificate_arn(self,"cert",cert_arn) domain_name='voncv.sema4.com' domain_obj=api.DomainNameOptions(certificate=cert, domain_name=domain_name) #domain_name_obj=api.DefaultDomainMappingOptions( domain_name=domain_obj1, mapping_key=None) integration_uri='http://voncwesprod.sema4.com:3000' #classaws_cdk.aws_apigateway.HttpIntegration(url, *, http_method=None, options=None, proxy=None) #base_api=api.HttpApi(self, 'rootapi', api_name=api_name, cors_preflight=None, create_default_stage=None, default_domain_mapping=domain_name_obj) # , default_integration=None) base_api = api.RestApi(self, "RestApi",rest_api_name=api_name,domain_name=domain_obj, deploy=False ) integration_response_200=api.IntegrationResponse(status_code='200') integration_response_400=api.IntegrationResponse(status_code='400',selection_pattern='400') integration_response_401=api.IntegrationResponse(status_code='401',selection_pattern='401') integration_response_404=api.IntegrationResponse(status_code='400',selection_pattern='404') integration_response_405=api.IntegrationResponse(status_code='401',selection_pattern='405') integration_response_500=api.IntegrationResponse(status_code='401',selection_pattern='500') integration_response_all=[integration_response_200, integration_response_400, integration_response_401, integration_response_404, integration_response_405, integration_response_500 ] integration_options=api.IntegrationOptions(integration_responses=integration_response_all) #method_reponse=api.IntegrationOptions(integration_responses=integration_response_all) mr=[ api.MethodResponse(status_code='200'), api.MethodResponse(status_code='400'), api.MethodResponse(status_code='401'), api.MethodResponse(status_code='404'), api.MethodResponse(status_code='405'), api.MethodResponse(status_code='500') ] integration=api.Integration(type=api.IntegrationType.HTTP,integration_http_method='POST',uri=integration_uri,options=integration_options) control = base_api.root.add_resource('control') control_get=control.add_method('POST',integration) control_controlid=control.add_resource('{controlid}') control_controlid_post=control_controlid.add_method('POST',integration) control_controlid_sample=control_controlid.add_resource('sample') control_controlid_sample_sampleid=control_controlid_sample.add_resource('sampleid') control_controlid_sample_sampleid_get=control_controlid_sample_sampleid.add_method('GET',integration,method_responses=mr) control_controlid_sample_sampleid_pipelineoutput=control_controlid_sample_sampleid.add_resource('pipeline_output') control_controlid_sample_sampleid_pipelineoutput_post=control_controlid_sample_sampleid_pipelineoutput.add_method('POST',integration) getalllpatients = base_api.root.add_resource('getallpatients') getalllpatients_get=getalllpatients.add_method('GET',integration) patient = base_api.root.add_resource('patient') patient_post = patient.add_method('GET',integration) patient_get = patient.add_method('POST',integration) patientid=patient.add_resource('patientid') patient_put=patientid.add_method('PUT',integration) patient_get=patientid.add_method('GET',integration) patient_case=patientid.add_resource('case') patient_case_post=patient_case.add_method('POST',integration) patient_case_caseid=patient_case.add_resource('caseid') patient_case_caseid_get= patient_case_caseid.add_method('GET',integration) patient_case_caseid_put= patient_case_caseid.add_method('PUT',integration) patient_case_caseid_close=patient_case_caseid.add_resource('close') patient_case_caseid_close_post=patient_case_caseid_close.add_method('PUT',integration) patient_case_caseid_curate=patient_case_caseid.add_resource('curate') patient_case_caseid_curate_post=patient_case_caseid_curate.add_method('POST',integration) patient_case_caseid_fail=patient_case_caseid.add_resource('fail') patient_case_caseid_fail_post=patient_case_caseid_fail.add_method('POST',integration) patient_case_caseid_reopen=patient_case_caseid.add_resource('reopen') patient_case_caseid_reopen_post=patient_case_caseid_reopen.add_method('POST',integration) patient_case_caseid_sample=patient_case_caseid.add_resource('sample') patient_case_caseid_sample_sampleid=patient_case_caseid_sample.add_resource('sampleid') patient_case_caseid_sample_sampleid_get=patient_case_caseid_sample_sampleid.add_method('GET',integration) patient_case_caseid_sample_sampleid_fail=patient_case_caseid_sample_sampleid.add_resource('fail') patient_case_caseid_sample_sampleid_fail_post=patient_case_caseid_sample_sampleid_fail.add_method('POST',integration) patient_case_caseid_sample_sampleid_pipelineoutput=patient_case_caseid_sample_sampleid.add_resource('pipeline-output') patient_case_caseid_sample_sampleid_pipelineoutput_post=patient_case_caseid_sample_sampleid_pipelineoutput.add_method('POST',integration) patient_case_caseid_variant=patient_case_caseid.add_resource('variant') patient_case_caseid_variant_post=patient_case_caseid.add_method('POST',integration)
def __init__(self, scope: core.Construct, id: str, stack_log_level: str, back_end_api_name: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) # Create Serverless Event Processor using Lambda): # Read Lambda Code): try: with open( "api_with_stage_variables/stacks/back_end/lambda_src/serverless_greeter.py", mode="r") as f: greeter_fn_code = f.read() except OSError as e: print("Unable to read Lambda Function Code") raise e greeter_fn = _lambda.Function( self, "secureGreeterFn", function_name=f"greeter_fn_{id}", runtime=_lambda.Runtime.PYTHON_3_7, handler="index.lambda_handler", code=_lambda.InlineCode(greeter_fn_code), timeout=core.Duration.seconds(15), reserved_concurrent_executions=20, environment={ "LOG_LEVEL": f"{stack_log_level}", "Environment": "Production", "ANDON_CORD_PULLED": "False", "RANDOM_SLEEP_ENABLED": "False" }, description= "A simple greeter function, which responds with a timestamp") greeter_fn_version = greeter_fn.latest_version greeter_fn_version_alias = _lambda.Alias( self, "greeterFnMystiqueAutomationAlias", alias_name="MystiqueAutomation", version=greeter_fn_version) greeter_fn_dev_alias = _lambda.Alias(self, "greeterFnDevAlias", alias_name="dev", version=greeter_fn_version) greeter_fn_test_alias = _lambda.Alias(self, "greeterFnTestAlias", alias_name="test", version=greeter_fn_version) greeter_fn_prod_alias = _lambda.Alias(self, "greeterFnProdAlias", alias_name="prod", version=greeter_fn_version) # Create Custom Loggroup # /aws/lambda/function-name greeter_fn_lg = _logs.LogGroup( self, "greeterFnLoggroup", log_group_name=f"/aws/lambda/{greeter_fn.function_name}", retention=_logs.RetentionDays.ONE_WEEK, removal_policy=core.RemovalPolicy.DESTROY) # %% # Create API Gateway wa_api = _apigw.RestApi( self, "backEnd01Api", rest_api_name=f"{back_end_api_name}", # deploy_options=wa_api_dev_stage_options, retain_deployments=False, deploy=False, endpoint_types=[_apigw.EndpointType.EDGE], description= f"{GlobalArgs.OWNER}: API Best Practices. Stage Variables for APIs. This stack deploys an API and integrates with Lambda using Stage Variables." ) wa_api_logs = _logs.LogGroup( self, "waApiLogs", log_group_name=f"/aws/apigateway/{back_end_api_name}/access_logs", removal_policy=core.RemovalPolicy.DESTROY, retention=_logs.RetentionDays.ONE_DAY) ###################################### ## CONFIG FOR API STAGE : DEV ## ###################################### dev_wa_api_deploy = _apigw.Deployment( self, "devDeploy", api=wa_api, description=f"{GlobalArgs.OWNER}: Deployment of 'dev' Api Stage", retain_deployments=False) dev_api_stage = _apigw.Stage( self, "devStage", deployment=dev_wa_api_deploy, stage_name="miztiik-dev", throttling_rate_limit=10, throttling_burst_limit=100, # Log full requests/responses data data_trace_enabled=True, # Enable Detailed CloudWatch Metrics metrics_enabled=True, logging_level=_apigw.MethodLoggingLevel.INFO, access_log_destination=_apigw.LogGroupLogDestination(wa_api_logs), variables={"lambdaAlias": "dev"}) # wa_api.deployment_stage = dev_api_stage test_wa_api_deploy = _apigw.Deployment( self, "testDeploy", api=wa_api, description=f"{GlobalArgs.OWNER}: Deployment of 'test' Api Stage", retain_deployments=False) test_api_stage = _apigw.Stage( self, "testStage", deployment=test_wa_api_deploy, stage_name="miztiik-test", throttling_rate_limit=10, throttling_burst_limit=100, # Log full requests/responses data data_trace_enabled=True, # Enable Detailed CloudWatch Metrics metrics_enabled=True, logging_level=_apigw.MethodLoggingLevel.INFO, access_log_destination=_apigw.LogGroupLogDestination(wa_api_logs), variables={"lambdaAlias": "test"}) wa_api.deployment_stage = test_api_stage prod_wa_api_deploy = _apigw.Deployment( self, "prodDeploy", api=wa_api, description=f"{GlobalArgs.OWNER}: Deployment of 'prod' Api Stage", retain_deployments=False) prod_api_stage = _apigw.Stage( self, "prodStage", deployment=prod_wa_api_deploy, stage_name="miztiik-prod", throttling_rate_limit=10, throttling_burst_limit=100, # Log full requests/responses data data_trace_enabled=True, # Enable Detailed CloudWatch Metrics metrics_enabled=True, logging_level=_apigw.MethodLoggingLevel.INFO, access_log_destination=_apigw.LogGroupLogDestination(wa_api_logs), variables={"lambdaAlias": "prod"}) prod_api_stage.node.add_dependency(test_api_stage) wa_api.deployment_stage = prod_api_stage wa_api_res = wa_api.root.add_resource("wa-api") greeter = wa_api_res.add_resource("greeter") backend_stage_uri = (f"arn:aws:apigateway:" f"{core.Aws.REGION}" f":lambda:path/2015-03-31/functions/" f"{greeter_fn.function_arn}" f":" f"${{stageVariables.lambdaAlias}}" f"/invocations") greeter_method_get = greeter.add_method( http_method="GET", request_parameters={ "method.request.header.InvocationType": True, "method.request.path.mystique": True }, # integration=_apigw.LambdaIntegration( # # handler=greeter_fn, # handler=backend_stage_uri, # proxy=True # ) integration=_apigw.Integration( type=_apigw.IntegrationType.AWS_PROXY, integration_http_method="GET", uri=backend_stage_uri)) # "arn:aws:apigateway:eu-west-2:lambda:path/2015-03-31/functions/arn:aws:lambda:eu-west-2:614517326458:function:${stageVariables.preflightFunction}/invocations", # https://lambda.us-east-1.amazonaws.com/2015-03-31/functions/arn:aws:lambda:us-east-1:230023004178:function:greeter_fn_well-architected-api:${stageVariable.lambdaAlias}/invocations # We need to manually add permissions for the stages to invoke # CDK By default adds permission only for the last .deployment_stage ##################################################################### ## CDK BUG: CONDITIONS DOES NOT TAKE EFFECT IN SERVICE PRINCIPAL ## ##################################################################### """ greeter_fn.grant_invoke( _iam.ServicePrincipal( service="apigateway.amazonaws.com", conditions={ "ArnLike": {"aws:SourceArn": "this-does-not-work"} } ) ) """ greeter_fn.add_permission( "allowStageInvocation", principal=_iam.ServicePrincipal("apigateway.amazonaws.com"), # source_arn=f"arn:aws:execute-api:{core.Aws.REGION}:{core.Aws.ACCOUNT_ID}:{wa_api.rest_api_id}/{dev_api_stage.stage_name}/{greeter_method_get.resource.path}" source_arn=greeter_method_get.method_arn.replace( wa_api.deployment_stage.stage_name, "*"), action="lambda:InvokeFunction", ) greeter_fn_dev_alias.add_permission( "greeter_fn_devAliasApiPerms", principal=_iam.ServicePrincipal("apigateway.amazonaws.com"), action="lambda:InvokeFunction", source_arn=greeter_method_get.method_arn.replace( wa_api.deployment_stage.stage_name, "*"), ) greeter_fn_test_alias.add_permission( "greeter_fn_testAliasApiPerms", principal=_iam.ServicePrincipal("apigateway.amazonaws.com"), action="lambda:InvokeFunction", source_arn=greeter_method_get.method_arn.replace( wa_api.deployment_stage.stage_name, "*"), ) greeter_fn_prod_alias.add_permission( "greeter_fn_prodAliasApiPerms", principal=_iam.ServicePrincipal("apigateway.amazonaws.com"), action="lambda:InvokeFunction", source_arn=greeter_method_get.method_arn.replace( wa_api.deployment_stage.stage_name, "*"), ) # Outputs output_0 = core.CfnOutput( self, "AutomationFrom", value=f"{GlobalArgs.SOURCE_INFO}", description= "To know more about this automation stack, check out our github page." ) output_1 = core.CfnOutput( self, "WaApiUrl", value=f"{greeter.url}", description= "Use an utility like curl from the same VPC as the API to invoke it." )
def __init__(self, scope: core.Construct, id: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) # DynamoDB Table # Streaming is enabled to send the whole new object down the pipe table = dynamo_db.Table(self, "TheDynamoStreamer", partition_key=dynamo_db.Attribute( name="message", type=dynamo_db.AttributeType.STRING), stream=dynamo_db.StreamViewType.NEW_IMAGE) # defines an AWS Lambda resource subscriber_lambda = _lambda.Function( self, "DynamoLambdaHandler", runtime=_lambda.Runtime.PYTHON_3_8, handler="lambda.handler", code=_lambda.Code.from_asset("lambda_fns/subscribe")) subscriber_lambda.add_event_source( _event.DynamoEventSource( table=table, starting_position=_lambda.StartingPosition.LATEST)) # API Gateway Creation gateway = api_gw.RestApi( self, 'DynamoStreamerAPI', deploy_options=api_gw.StageOptions( metrics_enabled=True, logging_level=api_gw.MethodLoggingLevel.INFO, data_trace_enabled=True, stage_name='prod')) # Give our gateway permissions to interact with dynamodb api_gw_dynamo_role = iam.Role( self, 'DefaultLambdaHanderRole', assumed_by=iam.ServicePrincipal('apigateway.amazonaws.com')) table.grant_read_write_data(api_gw_dynamo_role) # shortening the lines of later code schema = api_gw.JsonSchema schema_type = api_gw.JsonSchemaType # Because this isn't a proxy integration, we need to define our response model response_model = gateway.add_model( 'ResponseModel', content_type='application/json', model_name='ResponseModel', schema=schema( schema=api_gw.JsonSchemaVersion.DRAFT4, title='pollResponse', type=schema_type.OBJECT, properties={'message': schema(type=schema_type.STRING)})) error_response_model = gateway.add_model( 'ErrorResponseModel', content_type='application/json', model_name='ErrorResponseModel', schema=schema(schema=api_gw.JsonSchemaVersion.DRAFT4, title='errorResponse', type=schema_type.OBJECT, properties={ 'state': schema(type=schema_type.STRING), 'message': schema(type=schema_type.STRING) })) # This is the VTL to transform our incoming JSON to a Dynamo Insert Query request_template = { "TableName": table.table_name, "Item": { "message": { "S": "$input.path('$.message')" } } } request_template_string = json.dumps(request_template, separators=(',', ':')) # This is the VTL to transform the error response error_template = { "state": 'error', "message": "$util.escapeJavaScript($input.path('$.errorMessage'))" } error_template_string = json.dumps(error_template, separators=(',', ':')) # This is how our gateway chooses what response to send based on selection_pattern integration_options = api_gw.IntegrationOptions( credentials_role=api_gw_dynamo_role, request_templates={"application/json": request_template_string}, passthrough_behavior=api_gw.PassthroughBehavior.NEVER, integration_responses=[ api_gw.IntegrationResponse( status_code='200', response_templates={ "application/json": json.dumps({"message": 'item added to db'}) }), api_gw.IntegrationResponse( selection_pattern="^\[BadRequest\].*", status_code='400', response_templates={ "application/json": error_template_string }, response_parameters={ 'method.response.header.Content-Type': "'application/json'", 'method.response.header.Access-Control-Allow-Origin': "'*'", 'method.response.header.Access-Control-Allow-Credentials': "'true'" }) ]) # Add an InsertItem endpoint onto the gateway gateway.root.add_resource('InsertItem') \ .add_method('POST', api_gw.Integration(type=api_gw.IntegrationType.AWS, integration_http_method='POST', uri='arn:aws:apigateway:us-east-1:dynamodb:action/PutItem', options=integration_options ), method_responses=[ api_gw.MethodResponse(status_code='200', response_parameters={ 'method.response.header.Content-Type': True, 'method.response.header.Access-Control-Allow-Origin': True, 'method.response.header.Access-Control-Allow-Credentials': True }, response_models={ 'application/json': response_model }), api_gw.MethodResponse(status_code='400', response_parameters={ 'method.response.header.Content-Type': True, 'method.response.header.Access-Control-Allow-Origin': True, 'method.response.header.Access-Control-Allow-Credentials': True }, response_models={ 'application/json': error_response_model }), ] )
def __init__(self, scope: core.Construct, id: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) ## Create S3 Bucket. We'll populate it seperately. bucket_name="{}-s3-ecs-apigw-test".format(core.Aws.ACCOUNT_ID) bucket = s3.Bucket(self, "s3-ecs-apigw-test", bucket_name=bucket_name, versioned=True, public_read_access=False ) ## Create ECS Cluster, Taks and Service ### Create the VPC for the demo vpc = ec2.Vpc(self, "MyVpc", max_azs=3) ### Create the ECS Cluster cluster = ecs.Cluster(self, "ecs-apigw-test-cluster", cluster_name="ecs-apigw-test-cluster", container_insights=True, vpc=vpc) ### Using the Network LoadBalance Fargate patterm, this wills create the container definition, the task definition, the service and the Network load balancer for it. ecs_deploy = ecsp.NetworkLoadBalancedFargateService(self, "ecs-apigw-test", cluster=cluster, cpu=512, desired_count=2, public_load_balancer=False, memory_limit_mib=2048, task_image_options=ecsp.NetworkLoadBalancedTaskImageOptions( image=ecs.ContainerImage.from_registry("strm/helloworld-http") ), health_check_grace_period=core.Duration.minutes(5) ) ### Have to add an Ingress rule to allow traffic through. This applies the CIDR of the VPC. ecs_deploy.service.connections.security_groups[0].add_ingress_rule( ec2.Peer.ipv4(vpc.vpc_cidr_block), ec2.Port( protocol=ec2.Protocol.TCP, string_representation="", from_port=80, to_port=80 ) ) ## Create API Gateway resources ### Create the VPC Link to the Network Load Balancer vpc_link =apigw.VpcLink(self, "ecs-test-vpc-link", targets = [ecs_deploy.load_balancer]) ### Create the API api = apigw.RestApi(self, "ecs-s3-test-api", rest_api_name="ECS S3 Test API", description="Test API for distributing traffic to S3 and ECS", binary_media_types=["image/png"]) ### Create the execution role for the API methods. rest_api_role = iam.Role( self, "RestAPIRole", assumed_by=iam.ServicePrincipal("apigateway.amazonaws.com"), managed_policies=[iam.ManagedPolicy.from_aws_managed_policy_name("AmazonS3ReadOnlyAccess")]) ### Generic Method Response that can be used with each API method method_response = apigw.MethodResponse(status_code="200", response_parameters={"method.response.header.Content-Type": True}) ### Root URI root_integration_response = apigw.IntegrationResponse( status_code="200", response_templates={"text/html": "$input.path('$')"}, response_parameters={"method.response.header.Content-Type": "'text/html'"}) root_integration_options = apigw.IntegrationOptions( credentials_role=rest_api_role, integration_responses=[root_integration_response], request_templates={"application/json": "Action=SendMessage&MessageBody=$input.body"}, passthrough_behavior=apigw.PassthroughBehavior.NEVER, request_parameters={ "integration.request.header.Content-Type": "'application/x-www-form-urlencoded'"}) root_resource_s3_integration = apigw.AwsIntegration( service="s3", integration_http_method="GET", subdomain=bucket_name, path="index.html", options=root_integration_options) root_method = api.root.add_method("GET", root_resource_s3_integration, method_responses=[method_response]) ### API URI api_integration = apigw.Integration( type=apigw.IntegrationType.HTTP_PROXY, uri="http://{}".format(ecs_deploy.load_balancer.load_balancer_dns_name), integration_http_method="GET", options={ "connection_type": apigw.ConnectionType.VPC_LINK, "vpc_link": vpc_link } ) apis = api.root.add_resource("apis") apii = apis.add_resource("{api}") # apis = api.root.add_resource("apis") apii_get = apii.add_method("GET", api_integration, method_responses=[method_response], request_parameters={ "method.request.path.api": True,}) ## Add Images URI image_integration_response = apigw.IntegrationResponse( status_code="200", content_handling=apigw.ContentHandling.CONVERT_TO_BINARY, # response_templates={"text/html": "$input.path('$')"}, response_parameters={"method.response.header.Content-Type": "'image/png'"}) image_integration_options = apigw.IntegrationOptions( credentials_role=rest_api_role, integration_responses=[image_integration_response], request_templates={"application/json": "Action=SendMessage&MessageBody=$input.body"}, passthrough_behavior=apigw.PassthroughBehavior.NEVER, request_parameters={ "integration.request.header.Content-Type": "'application/x-www-form-urlencoded'", "integration.request.path.image": "method.request.path.image"}) images_resource_s3_integration = apigw.AwsIntegration( service="s3", integration_http_method="GET", subdomain=bucket_name, path="images/{image}", options=image_integration_options) images_resource = api.root.add_resource("images") image_resource = images_resource.add_resource("{image}") images_get = image_resource.add_method("GET", images_resource_s3_integration, method_responses=[method_response], request_parameters={ "method.request.path.image": True,}) ## Fall Through folder = api.root.add_resource("{folder}") item = folder.add_resource("{item}") integration_response = apigw.IntegrationResponse( status_code="200", response_templates={"text/html": "$input.path('$')"}, response_parameters={"method.response.header.Content-Type": "'text/html'"}) s3_proxy_integration_options = apigw.IntegrationOptions( credentials_role=rest_api_role, integration_responses=[integration_response], request_templates={"application/json": "Action=SendMessage&MessageBody=$input.body"}, passthrough_behavior=apigw.PassthroughBehavior.NEVER, request_parameters={ "integration.request.header.Content-Type": "'application/x-www-form-urlencoded'", "integration.request.path.item": "method.request.path.item", "integration.request.path.folder": "method.request.path.folder"}) s3_proxy_resource_s3_integration = apigw.AwsIntegration( service="s3", integration_http_method="GET", subdomain=bucket_name, path="{folder}/{item}", options=s3_proxy_integration_options) item_get = item.add_method("GET", s3_proxy_resource_s3_integration, method_responses=[method_response], request_parameters={ "method.request.path.item": True, "method.request.path.folder": True } )
def __init__(self, scope: core.Construct, id: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) my_api = apigw.RestApi( self, "SageMakerAPI", default_cors_preflight_options=apigw.CorsOptions( allow_origins=["*"], allow_headers=["*"], allow_methods=["*"])) endpoint_name = self.node.try_get_context("endpoint_name") options = apigw.IntegrationOptions( credentials_role=iam.Role( self, "SMInvoke", assumed_by=iam.ServicePrincipal("apigateway"), inline_policies={ "FullSageMaker": iam.PolicyDocument(statements=[ iam.PolicyStatement(actions=["*"], resources=["*"]) ]) }), integration_responses=[ apigw.IntegrationResponse( status_code="200", response_templates={"application/json": ""}, response_parameters={ "method.response.header.Access-Control-Allow-Headers": "'*'", "method.response.header.Access-Control-Allow-Methods": "'*'", "method.response.header.Access-Control-Allow-Origin": "'*'" }) ]) integration = apigw.Integration( type=apigw.IntegrationType.AWS, uri= "arn:aws:apigateway:us-east-1:runtime.sagemaker:path/endpoints/{}/invocations" .format(self.node.try_get_context("endpoint_name")), integration_http_method="POST", options=options) apigw.Method( self, "PostRoot", http_method="POST", resource=my_api.root, integration=integration, options=apigw.MethodOptions(method_responses=[ apigw.MethodResponse( status_code="200", response_parameters={ "method.response.header.Access-Control-Allow-Methods": True, "method.response.header.Access-Control-Allow-Headers": True, "method.response.header.Access-Control-Allow-Origin": True }) ]))
def __init__(self, scope: core.Construct, construct_id: str, **kwargs) -> None: super().__init__(scope, construct_id, **kwargs) # Create two VPCs - one to host our private website, the other to act as a client website_vpc = Vpc( self, "WEBSITEVPC", cidr="10.0.0.0/16", ) client_vpc = Vpc( self, "ClientVPC", cidr="10.1.0.0/16", ) # Create a bastion host in the client API which will act like our client workstation bastion = BastionHostLinux( self, "WEBClient", vpc=client_vpc, instance_name='my-bastion', instance_type=InstanceType('t3.micro'), machine_image=AmazonLinuxImage(), subnet_selection=SubnetSelection(subnet_type=SubnetType.PRIVATE), security_group=SecurityGroup( scope=self, id='bastion-sg', security_group_name='bastion-sg', description= 'Security group for the bastion, no inbound open because we should access' ' to the bastion via AWS SSM', vpc=client_vpc, allow_all_outbound=True)) # Set up a VPC peering connection between client and API VPCs, and adjust # the routing table to allow connections back and forth VpcPeeringHelper(self, 'Peering', website_vpc, client_vpc) # Create VPC endpoints for API gateway vpc_endpoint = InterfaceVpcEndpoint( self, 'APIGWVpcEndpoint', vpc=website_vpc, service=InterfaceVpcEndpointAwsService.APIGATEWAY, private_dns_enabled=True, ) vpc_endpoint.connections.allow_from(bastion, Port.tcp(443)) endpoint_id = vpc_endpoint.vpc_endpoint_id api_policy = iam.PolicyDocument(statements=[ iam.PolicyStatement(principals=[iam.AnyPrincipal()], actions=['execute-api:Invoke'], resources=['execute-api:/*'], effect=iam.Effect.DENY, conditions={ "StringNotEquals": { "aws:SourceVpce": endpoint_id } }), iam.PolicyStatement(principals=[iam.AnyPrincipal()], actions=['execute-api:Invoke'], resources=['execute-api:/*'], effect=iam.Effect.ALLOW) ]) # Create an s3 bucket to hold the content content_bucket = s3.Bucket(self, "ContentBucket", removal_policy=core.RemovalPolicy.DESTROY) # Upload our static content to the bucket s3dep.BucketDeployment(self, "DeployWithInvalidation", sources=[s3dep.Source.asset('website')], destination_bucket=content_bucket) # Create a private API GW in the API VPC api = apigw.RestApi(self, 'PrivateS3Api', endpoint_configuration=apigw.EndpointConfiguration( types=[apigw.EndpointType.PRIVATE], vpc_endpoints=[vpc_endpoint]), policy=api_policy) # Create a role to allow API GW to access our S3 bucket contents role = iam.Role( self, "Role", assumed_by=iam.ServicePrincipal("apigateway.amazonaws.com")) role.add_to_policy( iam.PolicyStatement(effect=iam.Effect.ALLOW, resources=[ content_bucket.bucket_arn, content_bucket.bucket_arn + '/*' ], actions=["s3:Get*"])) # Create a proxy resource that captures all non-root resource requests resource = api.root.add_resource("{proxy+}") # Create an integration with S3 resource_integration = apigw.Integration( type=apigw.IntegrationType.AWS, integration_http_method='GET', options=apigw.IntegrationOptions( request_parameters= { # map the proxy parameter so we can pass the request path "integration.request.path.proxy": "method.request.path.proxy" }, integration_responses=[ apigw.IntegrationResponse( status_code='200', response_parameters= { # map the content type of the S3 object back to the HTTP response "method.response.header.Content-Type": "integration.response.header.Content-Type" }) ], credentials_role=role), # reference the bucket content we want to retrieve uri='arn:aws:apigateway:eu-west-1:s3:path/%s/{proxy}' % (content_bucket.bucket_name)) # handle the GET request and map it to our new integration resource.add_method( "GET", resource_integration, method_responses=[ apigw.MethodResponse(status_code='200', response_parameters={ "method.response.header.Content-Type": False }) ], request_parameters={"method.request.path.proxy": True}) # Handle requests to the root of our site # Create another integration with S3 - this time with no proxy parameter resource_integration = apigw.Integration( type=apigw.IntegrationType.AWS, integration_http_method='GET', options=apigw.IntegrationOptions( integration_responses=[ apigw.IntegrationResponse( status_code='200', response_parameters= { # map the content type of the S3 object back to the HTTP response "method.response.header.Content-Type": "integration.response.header.Content-Type" }) ], credentials_role=role), # reference the bucket content we want to retrieve uri='arn:aws:apigateway:eu-west-1:s3:path/%s/index.html' % (content_bucket.bucket_name)) # handle the GET request and map it to our new integration api.root.add_method("GET", resource_integration, method_responses=[ apigw.MethodResponse( status_code='200', response_parameters={ "method.response.header.Content-Type": False }) ])
def __init__(self, scope: core.Construct, id: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) ### # SNS Topic Creation # Our API Gateway posts messages directly to this ### topic = sns.Topic(self, 'theBigFanTopic', display_name='The Big Fan CDK Pattern Topic') ### # SQS Subscribers creation for our SNS Topic # 2 subscribers, one for messages with a status of created one for any other message ### # Status:created SNS Subscriber Queue created_status_queue = sqs.Queue( self, 'BigFanTopicStatusCreatedSubscriberQueue', visibility_timeout=core.Duration.seconds(300), queue_name='BigFanTopicStatusCreatedSubscriberQueue') # Only send messages to our created_status_queue with a status of created created_filter = sns.SubscriptionFilter.string_filter( whitelist=['created']) topic.add_subscription( subscriptions.SqsSubscription( created_status_queue, raw_message_delivery=True, filter_policy={'status': created_filter})) # Any other status SNS Subscriber Queue other_status_queue = sqs.Queue( self, 'BigFanTopicAnyOtherStatusSubscriberQueue', visibility_timeout=core.Duration.seconds(300), queue_name='BigFanTopicAnyOtherStatusSubscriberQueue') # Only send messages to our other_status_queue that do not have a status of created other_filter = sns.SubscriptionFilter.string_filter( blacklist=['created']) topic.add_subscription( subscriptions.SqsSubscription( other_status_queue, raw_message_delivery=True, filter_policy={'status': other_filter})) ### # Creation of Lambdas that subscribe to above SQS queues ### # Created status queue lambda sqs_created_status_subscriber = _lambda.Function( self, "SQSCreatedStatusSubscribeLambdaHandler", runtime=_lambda.Runtime.NODEJS_12_X, handler="createdStatus.handler", code=_lambda.Code.from_asset("lambda_fns/subscribe")) created_status_queue.grant_consume_messages( sqs_created_status_subscriber) sqs_created_status_subscriber.add_event_source( _event.SqsEventSource(created_status_queue)) # Any other status queue lambda sqs_other_status_subscriber = _lambda.Function( self, "SQSAnyOtherStatusSubscribeLambdaHandler", runtime=_lambda.Runtime.NODEJS_12_X, handler="anyOtherStatus.handler", code=_lambda.Code.from_asset("lambda_fns/subscribe")) other_status_queue.grant_consume_messages(sqs_other_status_subscriber) sqs_other_status_subscriber.add_event_source( _event.SqsEventSource(other_status_queue)) ### # API Gateway Creation # This is complicated because it transforms the incoming json payload into a query string url # this url is used to post the payload to sns without a lambda inbetween ### gateway = api_gw.RestApi( self, 'theBigFanAPI', deploy_options=api_gw.StageOptions( metrics_enabled=True, logging_level=api_gw.MethodLoggingLevel.INFO, data_trace_enabled=True, stage_name='prod')) # Give our gateway permissions to interact with SNS api_gw_sns_role = iam.Role( self, 'DefaultLambdaHanderRole', assumed_by=iam.ServicePrincipal('apigateway.amazonaws.com')) topic.grant_publish(api_gw_sns_role) # shortening the lines of later code schema = api_gw.JsonSchema schema_type = api_gw.JsonSchemaType # Because this isn't a proxy integration, we need to define our response model response_model = gateway.add_model( 'ResponseModel', content_type='application/json', model_name='ResponseModel', schema=schema( schema=api_gw.JsonSchemaVersion.DRAFT4, title='pollResponse', type=schema_type.OBJECT, properties={'message': schema(type=schema_type.STRING)})) error_response_model = gateway.add_model( 'ErrorResponseModel', content_type='application/json', model_name='ErrorResponseModel', schema=schema(schema=api_gw.JsonSchemaVersion.DRAFT4, title='errorResponse', type=schema_type.OBJECT, properties={ 'state': schema(type=schema_type.STRING), 'message': schema(type=schema_type.STRING) })) request_template = "Action=Publish&" + \ "TargetArn=$util.urlEncode('" + topic.topic_arn + "')&" + \ "Message=$util.urlEncode($input.path('$.message'))&" + \ "Version=2010-03-31&" + \ "MessageAttributes.entry.1.Name=status&" + \ "MessageAttributes.entry.1.Value.DataType=String&" + \ "MessageAttributes.entry.1.Value.StringValue=$util.urlEncode($input.path('$.status'))" # This is the VTL to transform the error response error_template = { "state": 'error', "message": "$util.escapeJavaScript($input.path('$.errorMessage'))" } error_template_string = json.dumps(error_template, separators=(',', ':')) # This is how our gateway chooses what response to send based on selection_pattern integration_options = api_gw.IntegrationOptions( credentials_role=api_gw_sns_role, request_parameters={ 'integration.request.header.Content-Type': "'application/x-www-form-urlencoded'" }, request_templates={"application/json": request_template}, passthrough_behavior=api_gw.PassthroughBehavior.NEVER, integration_responses=[ api_gw.IntegrationResponse( status_code='200', response_templates={ "application/json": json.dumps({"message": 'message added to topic'}) }), api_gw.IntegrationResponse( selection_pattern="^\[Error\].*", status_code='400', response_templates={ "application/json": error_template_string }, response_parameters={ 'method.response.header.Content-Type': "'application/json'", 'method.response.header.Access-Control-Allow-Origin': "'*'", 'method.response.header.Access-Control-Allow-Credentials': "'true'" }) ]) # Add an SendEvent endpoint onto the gateway gateway.root.add_resource('SendEvent') \ .add_method('POST', api_gw.Integration(type=api_gw.IntegrationType.AWS, integration_http_method='POST', uri='arn:aws:apigateway:us-east-1:sns:path//', options=integration_options ), method_responses=[ api_gw.MethodResponse(status_code='200', response_parameters={ 'method.response.header.Content-Type': True, 'method.response.header.Access-Control-Allow-Origin': True, 'method.response.header.Access-Control-Allow-Credentials': True }, response_models={ 'application/json': response_model }), api_gw.MethodResponse(status_code='400', response_parameters={ 'method.response.header.Content-Type': True, 'method.response.header.Access-Control-Allow-Origin': True, 'method.response.header.Access-Control-Allow-Credentials': True }, response_models={ 'application/json': error_response_model }), ] )
def __init__(self, scope: core.Construct, id: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) ### # SNS Topic Creation # Our API Gateway posts messages directly to this ### topic = sns.Topic(self, 'TheXRayTracerSnsFanOutTopic', display_name='The XRay Tracer Fan Out Topic') self.sns_topic_arn = topic.topic_arn ### # API Gateway Creation # This is complicated because it is a direct SNS integration through VTL not a proxy integration # Tracing is enabled for X-Ray ### gateway = api_gw.RestApi( self, 'xrayTracerAPI', deploy_options=api_gw.StageOptions( metrics_enabled=True, logging_level=api_gw.MethodLoggingLevel.INFO, data_trace_enabled=True, tracing_enabled=True, stage_name='prod')) # Give our gateway permissions to interact with SNS api_gw_sns_role = iam.Role( self, 'ApiGatewaySNSRole', assumed_by=iam.ServicePrincipal('apigateway.amazonaws.com')) topic.grant_publish(api_gw_sns_role) # shortening the lines of later code schema = api_gw.JsonSchema schema_type = api_gw.JsonSchemaType # Because this isn't a proxy integration, we need to define our response model response_model = gateway.add_model( 'ResponseModel', content_type='application/json', model_name='ResponseModel', schema=schema( schema=api_gw.JsonSchemaVersion.DRAFT4, title='pollResponse', type=schema_type.OBJECT, properties={'message': schema(type=schema_type.STRING)})) error_response_model = gateway.add_model( 'ErrorResponseModel', content_type='application/json', model_name='ErrorResponseModel', schema=schema(schema=api_gw.JsonSchemaVersion.DRAFT4, title='errorResponse', type=schema_type.OBJECT, properties={ 'state': schema(type=schema_type.STRING), 'message': schema(type=schema_type.STRING) })) request_template = "Action=Publish&" + \ "TargetArn=$util.urlEncode('" + topic.topic_arn + "')&" + \ "Message=$util.urlEncode($context.path)&" + \ "Version=2010-03-31" # This is the VTL to transform the error response error_template = { "state": 'error', "message": "$util.escapeJavaScript($input.path('$.errorMessage'))" } error_template_string = json.dumps(error_template, separators=(',', ':')) # This is how our gateway chooses what response to send based on selection_pattern integration_options = api_gw.IntegrationOptions( credentials_role=api_gw_sns_role, request_parameters={ 'integration.request.header.Content-Type': "'application/x-www-form-urlencoded'" }, request_templates={"application/json": request_template}, passthrough_behavior=api_gw.PassthroughBehavior.NEVER, integration_responses=[ api_gw.IntegrationResponse( status_code='200', response_templates={ "application/json": json.dumps({"message": 'message added to topic'}) }), api_gw.IntegrationResponse( selection_pattern="^\[Error\].*", status_code='400', response_templates={ "application/json": error_template_string }, response_parameters={ 'method.response.header.Content-Type': "'application/json'", 'method.response.header.Access-Control-Allow-Origin': "'*'", 'method.response.header.Access-Control-Allow-Credentials': "'true'" }) ]) method_responses = [ api_gw.MethodResponse( status_code='200', response_parameters={ 'method.response.header.Content-Type': True, 'method.response.header.Access-Control-Allow-Origin': True, 'method.response.header.Access-Control-Allow-Credentials': True }, response_models={'application/json': response_model}), api_gw.MethodResponse( status_code='400', response_parameters={ 'method.response.header.Content-Type': True, 'method.response.header.Access-Control-Allow-Origin': True, 'method.response.header.Access-Control-Allow-Credentials': True }, response_models={'application/json': error_response_model}), ] # Add a / endpoint onto the gateway gateway.root \ .add_method('GET', api_gw.Integration(type=api_gw.IntegrationType.AWS, integration_http_method='POST', uri='arn:aws:apigateway:us-east-1:sns:path//', options=integration_options ), method_responses=method_responses ) # Add a {proxy+} endpoint onto the gateway gateway.root.add_resource('{proxy+}') \ .add_method('GET', api_gw.Integration(type=api_gw.IntegrationType.AWS, integration_http_method='POST', uri='arn:aws:apigateway:us-east-1:sns:path//', options=integration_options ), method_responses=method_responses )
def __init__(self, scope: cdk.Construct, construct_id: str, **kwargs) -> None: super().__init__(scope, construct_id, **kwargs) # Create a Lambda function # Code in ./src directory lambda_fn = lambda_.Function( self, "MyFunction", runtime=lambda_.Runtime.PYTHON_3_9, handler="index.handler", code=lambda_.Code.from_asset(os.path.join(DIRNAME, "src")) ) #Input parameter for custom domain name created for API Gateway, ex: apis.example.com custom_domain_name = cdk.CfnParameter(self, "customdomainname", type="String", description="The custom domain name for AWS REST API Gateway") #Input parameter for ACM certificate arn certificate_arn = cdk.CfnParameter(self, "certificatearn", type="String", description="The ACM certificate ARN for custom domain name") #Input parameter for s3 bucket name that has truststore pem file truststore_bucket = cdk.CfnParameter(self, "truststorebucket", type="String", description="The S3 trustsore uri for custom domain name") #Input parameter for public hosted zone id public_zone_id = cdk.CfnParameter(self, "publiczoneid", type="String", description="The public hosted zone id to create a record for custom domain name") #Input parameter for public hosted zone id public_zone_name = cdk.CfnParameter(self, "publiczonename", type="String", description="The public hosted zone name to create a record for custom domain name") # Create the Rest API rest_api = apigateway.RestApi( self, "TLSRestAPI", endpoint_types=[apigateway.EndpointType.REGIONAL], description="RestAPI Gateway to verify mutual TLS", deploy=False, retain_deployments=False, disable_execute_api_endpoint=True ) # Create the custom domain api_domain = apigateway.DomainName( self, "MyDomainName", domain_name=custom_domain_name.value_as_string, certificate=acm.Certificate.from_certificate_arn(self, "cert", certificate_arn.value_as_string), mtls=apigateway.MTLSConfig( bucket=s3.Bucket.from_bucket_name(self, "Bucket", truststore_bucket.value_as_string), key="/truststore.pem" ), security_policy=apigateway.SecurityPolicy.TLS_1_2 ) # Create API deployment deployment = apigateway.Deployment( self, "Deployment", api=rest_api, retain_deployments=False ) # Create prod Stage for deployment stage = apigateway.Stage( self, "prod", deployment=deployment, ) # Create API mapping to custom domain base_path_mapping = apigateway.BasePathMapping(self, "MyBasePathMapping", domain_name=api_domain, rest_api=rest_api, stage=stage ) #Get public hosted zone object public_zone = route53.HostedZone.from_hosted_zone_attributes(self, "publiczone", hosted_zone_id=public_zone_id.value_as_string,zone_name=public_zone_name.value_as_string) #Create A record for custom domain name in public hosted zone #Record name will be taken from custom domain name, ex: for apis.example.com, record name will be apis record = route53.ARecord(self, 'MyAliasRecord', zone=public_zone, record_name=cdk.Fn.select(0,cdk.Fn.split('.',custom_domain_name.value_as_string)), target=route53.RecordTarget.from_alias(targets.ApiGatewayDomain(api_domain)) ) rest_api.deployment_stage = stage # Create URI for lambda function stage_uri = f"arn:aws:apigateway:{cdk.Aws.REGION}:lambda:path/2015-03-31/functions/{lambda_fn.function_arn}/invocations" # Create Lambda Integration integration = apigateway.Integration( type=apigateway.IntegrationType.AWS_PROXY, integration_http_method="POST", uri=stage_uri ) # Create APIGW Method method = rest_api.root.add_method("GET", integration) # Add Lambda permissions lambda_fn.add_permission( "lambdaPermission", action="lambda:InvokeFunction", principal=iam.ServicePrincipal("apigateway.amazonaws.com"), source_arn=method.method_arn.replace( rest_api.deployment_stage.stage_name, "*" ) ) # OUTPUTS cdk.CfnOutput(self, "LambdaFunction", export_name="MyLambdaFunction", value=lambda_fn.function_arn) cdk.CfnOutput(self, "ApigwId", export_name="MyAPIGWID", value=rest_api.rest_api_id) cdk.CfnOutput(self, "CustomDomainName", export_name="MyCustomDomain", value=api_domain.domain_name) cdk.CfnOutput(self, "CustomDomainHostedZone", export_name="MyCustomeZone", value=api_domain.domain_name_alias_hosted_zone_id) cdk.CfnOutput(self, "CustomDomainAlias", export_name="MyCustomAlias", value=api_domain.domain_name_alias_domain_name)
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: super().__init__(scope, construct_id, **kwargs) # Create a Lambda function # Code in ./src directory lambda_fn = lambda_.Function(self, "MyFunction", runtime=lambda_.Runtime.PYTHON_3_9, handler="index.handler", code=lambda_.Code.from_asset( os.path.join(DIRNAME, "src"))) # Function version version = lambda_fn.current_version # Create function alias alias = lambda_.Alias(self, "LambdaAlias", alias_name="Prod", version=version) # Create the Rest API rest_api = apigateway.RestApi( self, "RestApi", endpoint_types=[apigateway.EndpointType.REGIONAL], deploy=False, retain_deployments=False) # Create initial deployment deployment = apigateway.Deployment(self, "Deployment", api=rest_api, retain_deployments=False) # Create prod Stage stage = apigateway.Stage(self, "prod", deployment=deployment, variables={"lambdaAlias": "Prod"}) rest_api.deployment_stage = stage # Create URI for lambda alias stage_uri = f"arn:aws:apigateway:{Aws.REGION}:lambda:path/2015-03-31/functions/{lambda_fn.function_arn}:${{stageVariables.lambdaAlias}}/invocations" # Create Lambda Integration integration = apigateway.Integration( type=apigateway.IntegrationType.AWS_PROXY, integration_http_method="POST", uri=stage_uri) # Create APIGW Method method = rest_api.root.add_method("GET", integration) # Add Lambda permissions lambda_fn.add_permission( "lambdaPermission", action="lambda:InvokeFunction", principal=iam.ServicePrincipal("apigateway.amazonaws.com"), source_arn=method.method_arn.replace( rest_api.deployment_stage.stage_name, "*")) # Add permissions for Prod alias alias.add_permission( "aliasPermission", action="lambda:InvokeFunction", principal=iam.ServicePrincipal("apigateway.amazonaws.com"), source_arn=method.method_arn.replace( rest_api.deployment_stage.stage_name, "*")) # OUTPUTS CfnOutput(self, "LambdaFunction", export_name="MyLambdaFunction", value=lambda_fn.function_arn) CfnOutput(self, "ApigwId", export_name="MyAPIGWID", value=rest_api.rest_api_id) CfnOutput(self, "MethodArn", export_name="MyMethodArn", value=method.method_arn) CfnOutput(self, "StageName", export_name="MyStageName", value=rest_api.deployment_stage.stage_name)