Skip to content

Instantly share code, notes, and snippets.

@jhw
Last active May 15, 2024 18:14
Show Gist options
  • Save jhw/c27fb54c71c5e3be6bc0d5e9a204225d to your computer and use it in GitHub Desktop.
Save jhw/c27fb54c71c5e3be6bc0d5e9a204225d to your computer and use it in GitHub Desktop.
APIGW demos

A collection of APIGW demos (v1 and v2)

*.pyc
__pycache__
env
tmp
AppName=sb-apigw-demo
<!DOCTYPE html>
<!-- python -m http.server -->
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CORS Test</title>
<script>
window.onload = function() {
fetch('https://apigwdemo.spaaseu.link/hello-get?message=Hello%20World')
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.text();
})
.then(data => {
document.getElementById('response').textContent = data;
})
.catch(error => {
console.log(error);
document.getElementById('response').textContent = "There was an error calling /hello-get; please see the console log for more details"
});
};
</script>
</head>
<body>
<div id="response">Loading...</div>
</body>
</html>
from botocore.exceptions import ClientError
import boto3, os, re, sys, yaml
def hungarorise(text):
return "".join([tok.capitalize()
for tok in re.split("\\-|\\_", text)])
def fetch_outputs(cf, stackname):
outputs={}
for stack in cf.describe_stacks()["Stacks"]:
if (stack["StackName"].startswith(stackname) and
"Outputs" in stack):
for output in stack["Outputs"]:
outputs[output["OutputKey"]]=output["OutputValue"]
return outputs
if __name__=="__main__":
try:
props=dict([tuple(row.split("="))
for row in open("app.props").read().split("\n")
if row!=''])
stackname=props["AppName"]
if len(sys.argv) < 3:
raise RuntimeError("please enter email, password")
email, password = sys.argv[1:3]
cf=boto3.client("cloudformation")
outputs=fetch_outputs(cf, stackname)
userpoolkey=hungarorise("app-user-pool")
if userpoolkey not in outputs:
raise RuntimeError("userpool not found")
userpool=outputs[userpoolkey]
clientkey=hungarorise("app-user-pool-web-client")
if clientkey not in outputs:
raise RuntimeError("client not found")
client=outputs[clientkey]
cognito=boto3.client("cognito-idp")
resp0=cognito.sign_up(ClientId=client,
Username=email,
Password=password)
print (yaml.safe_dump(resp0,
default_flow_style=False))
resp1=cognito.admin_confirm_sign_up(UserPoolId=userpool,
Username=email)
print (yaml.safe_dump(resp1,
default_flow_style=False))
except RuntimeError as error:
print ("Error: %s" % str(error))
except ClientError as error:
print ("Error: %s" % str(error))
#!/usr/bin/env bash
. app.props
aws cloudformation delete-stack --stack-name $AppName
from botocore.exceptions import ClientError
import boto3, os, re, sys, yaml
def hungarorise(text):
return "".join([tok.capitalize()
for tok in re.split("\\-|\\_", text)])
def fetch_outputs(cf, stackname):
outputs={}
for stack in cf.describe_stacks()["Stacks"]:
if (stack["StackName"].startswith(stackname) and
"Outputs" in stack):
for output in stack["Outputs"]:
outputs[output["OutputKey"]]=output["OutputValue"]
return outputs
if __name__=="__main__":
try:
props=dict([tuple(row.split("="))
for row in open("app.props").read().split("\n")
if row!=''])
stackname=props["AppName"]
if len(sys.argv) < 2:
raise RuntimeError("please enter email")
email=sys.argv[1]
cf=boto3.client("cloudformation")
outputs=fetch_outputs(cf, stackname)
userpoolkey=hungarorise("app-user-pool")
if userpoolkey not in outputs:
raise RuntimeError("userpool not found")
userpool=outputs[userpoolkey]
cognito=boto3.client("cognito-idp")
resp=cognito.admin_delete_user(UserPoolId=userpool,
Username=email)
print (yaml.safe_dump(resp,
default_flow_style=False))
except RuntimeError as error:
print ("Error: %s" % str(error))
except ClientError as error:
print ("Error: %s" % str(error))
#!/usr/bin/env bash
. app.props
aws cloudformation deploy --stack-name $AppName --template-file $1 --capabilities CAPABILITY_NAMED_IAM --parameter-overrides DomainName=$DOMAIN_NAME CertificateArn=$CERTIFICATE_ARN
from botocore.exceptions import ClientError
import boto3, os, re, sys
def hungarorise(text):
return "".join([tok.capitalize()
for tok in re.split("\\-|\\_", text)])
def fetch_outputs(cf, stackname):
outputs={}
for stack in cf.describe_stacks()["Stacks"]:
if (stack["StackName"].startswith(stackname) and
"Outputs" in stack):
for output in stack["Outputs"]:
outputs[output["OutputKey"]]=output["OutputValue"]
return outputs
if __name__=="__main__":
try:
props=dict([tuple(row.split("="))
for row in open("app.props").read().split("\n")
if row!=''])
stackname=props["AppName"]
cf=boto3.client("cloudformation")
outputs=fetch_outputs(cf, stackname)
bucketkey=hungarorise("app-bucket")
if bucketkey not in outputs:
raise RuntimeError("bucket not found")
bucketname=outputs[bucketkey]
s3=boto3.client("s3")
paginator=s3.get_paginator("list_objects_v2")
pages=paginator.paginate(Bucket=bucketname)
for struct in pages:
if "Contents" in struct:
for obj in struct["Contents"]:
print (obj["Key"])
s3.delete_object(Bucket=bucketname,
Key=obj["Key"])
except RuntimeError as error:
print ("Error: %s" % str(error))
except ClientError as error:
print ("Error: %s" % str(error))
<html>
<head>
<title>Hello World</title>
</head>
<body>
<div>Hello World!</div>
</body>
</html>
import boto3, re, sys
if __name__ == "__main__":
try:
if len(sys.argv) < 2:
raise RuntimeError("please enter region")
region = sys.argv[1]
if not re.search("^\\D{2}\\-\\D{4}\\-\\d{1}$", region):
raise RuntimeError("region is invalid")
acm = boto3.client("acm", region_name = region) # NB
for cert in acm.list_certificates()["CertificateSummaryList"]:
print ("--- %s ---" % (cert["DomainName"]))
print ("arn: %s" % cert["CertificateArn"])
cert_ = acm.describe_certificate(CertificateArn = cert["CertificateArn"])["Certificate"]
print ("status: %s" % cert_["Status"])
except RuntimeError as error:
print ("Error: %s" % str(error))
#!/usr/bin/env bash
. app.props
aws cloudformation describe-stack-events --stack-name $AppName --query "StackEvents[].{\"1.Timestamp\":Timestamp,\"2.Id\":LogicalResourceId,\"3.Type\":ResourceType,\"4.Status\":ResourceStatus,\"5.Reason\":ResourceStatusReason}"
#!/usr/bin/env bash
. app.props
aws cloudformation describe-stacks --stack-name $AppName --query 'Stacks[0].Outputs' --output table
#!/usr/bin/env bash
. app.props
aws cloudformation describe-stack-resources --stack-name $AppName --query "StackResources[].{\"1.Timestamp\":Timestamp,\"2.LogicalId\":LogicalResourceId,\"3.PhysicalId\":PhysicalResourceId,\"4.Type\":ResourceType,\"5.Status\":ResourceStatus}"
#!/usr/bin/env bash
aws cloudformation describe-stacks --query "Stacks[].{\"1.Name\":StackName,\"2.Status\":StackStatus}"
from botocore.exceptions import ClientError
import boto3, os, re, sys, yaml
def hungarorise(text):
return "".join([tok.capitalize()
for tok in re.split("\\-|\\_", text)])
def fetch_outputs(cf, stackname):
outputs={}
for stack in cf.describe_stacks()["Stacks"]:
if (stack["StackName"].startswith(stackname) and
"Outputs" in stack):
for output in stack["Outputs"]:
outputs[output["OutputKey"]]=output["OutputValue"]
return outputs
if __name__=="__main__":
try:
props=dict([tuple(row.split("="))
for row in open("app.props").read().split("\n")
if row!=''])
stackname=props["AppName"]
cf=boto3.client("cloudformation")
outputs=fetch_outputs(cf, stackname)
userpoolkey=hungarorise("app-user-pool")
if userpoolkey not in outputs:
raise RuntimeError("userpool not found")
userpool=outputs[userpoolkey]
cognito=boto3.client("cognito-idp")
resp=cognito.list_users(UserPoolId=userpool)
print (yaml.safe_dump(resp,
default_flow_style=False))
except RuntimeError as error:
print ("Error: %s" % str(error))
except ClientError as error:
print ("Error: %s" % str(error))

cors

  • python -m http.server

older demos

  • 3c18e2a160b766cdd63b9fa0fd202349
from botocore.exceptions import ClientError
import boto3, json, os, re, requests, sys, urllib.parse
def hungarorise(text):
return "".join([tok.capitalize()
for tok in re.split("\\-|\\_", text)])
def fetch_outputs(cf, stackname):
outputs={}
for stack in cf.describe_stacks()["Stacks"]:
if (stack["StackName"].startswith(stackname) and
"Outputs" in stack):
for output in stack["Outputs"]:
outputs[output["OutputKey"]]=output["OutputValue"]
return outputs
if __name__=="__main__":
try:
props=dict([tuple(row.split("="))
for row in open("app.props").read().split("\n")
if row!=''])
stackname=props["AppName"]
if len(sys.argv) < 4:
raise RuntimeError("please enter email, password, message")
email, password, message = sys.argv[1:4]
cf=boto3.client("cloudformation")
outputs=fetch_outputs(cf, stackname)
userpoolkey=hungarorise("app-user-pool")
if userpoolkey not in outputs:
raise RuntimeError("userpool not found")
userpool=outputs[userpoolkey]
clientkey=hungarorise("app-user-pool-admin-client")
if clientkey not in outputs:
raise RuntimeError("client not found")
client=outputs[clientkey]
cg=boto3.client("cognito-idp")
authresp=cg.admin_initiate_auth(UserPoolId=userpool,
ClientId=client,
AuthFlow='ADMIN_NO_SRP_AUTH',
AuthParameters={"USERNAME": email,
"PASSWORD": password})
token=authresp["AuthenticationResult"]["IdToken"]
url="https://apigwdemo.spaaseu.link/hello-get?message=%s" % urllib.parse.quote(message)
headers={"Authorization": "Bearer %s" % token,
"Accept": "application/json"}
print (headers)
print ()
resp=requests.get(url,
headers=headers)
print (resp.text)
except RuntimeError as error:
print ("Error: %s" % str(error))
except ClientError as error:
print ("Error: %s" % str(error))
from botocore.exceptions import ClientError
import boto3, json, os, re, requests, sys, urllib.parse
def hungarorise(text):
return "".join([tok.capitalize()
for tok in re.split("\\-|\\_", text)])
def fetch_outputs(cf, stackname):
outputs={}
for stack in cf.describe_stacks()["Stacks"]:
if (stack["StackName"].startswith(stackname) and
"Outputs" in stack):
for output in stack["Outputs"]:
outputs[output["OutputKey"]]=output["OutputValue"]
return outputs
if __name__=="__main__":
try:
props=dict([tuple(row.split("="))
for row in open("app.props").read().split("\n")
if row!=''])
stackname=props["AppName"]
if len(sys.argv) < 4:
raise RuntimeError("please enter email, password, message")
email, password, message = sys.argv[1:4]
cf=boto3.client("cloudformation")
outputs=fetch_outputs(cf, stackname)
userpoolkey=hungarorise("app-user-pool")
if userpoolkey not in outputs:
raise RuntimeError("userpool not found")
userpool=outputs[userpoolkey]
clientkey=hungarorise("app-user-pool-admin-client")
if clientkey not in outputs:
raise RuntimeError("client not found")
client=outputs[clientkey]
cg=boto3.client("cognito-idp")
authresp=cg.admin_initiate_auth(UserPoolId=userpool,
ClientId=client,
AuthFlow='ADMIN_NO_SRP_AUTH',
AuthParameters={"USERNAME": email,
"PASSWORD": password})
token=authresp["AuthenticationResult"]["IdToken"]
url="https://apigwdemo.spaaseu.link/hello-post"
headers={"Authorization": "Bearer %s" % token,
"Accept": "application/json"}
print (headers)
print ()
struct={"message": message}
resp=requests.post(url,
headers=headers,
data=json.dumps(struct))
print (resp.text)
except RuntimeError as error:
print ("Error: %s" % str(error))
except ClientError as error:
print ("Error: %s" % str(error))
from botocore.exceptions import ClientError
import boto3, os, re, sys
def hungarorise(text):
return "".join([tok.capitalize()
for tok in re.split("\\-|\\_", text)])
def fetch_outputs(cf, stackname):
outputs={}
for stack in cf.describe_stacks()["Stacks"]:
if (stack["StackName"].startswith(stackname) and
"Outputs" in stack):
for output in stack["Outputs"]:
outputs[output["OutputKey"]]=output["OutputValue"]
return outputs
if __name__=="__main__":
try:
props=dict([tuple(row.split("="))
for row in open("app.props").read().split("\n")
if row!=''])
stackname=props["AppName"]
cf=boto3.client("cloudformation")
outputs=fetch_outputs(cf, stackname)
bucketkey=hungarorise("app-bucket")
if bucketkey not in outputs:
raise RuntimeError("bucket not found")
bucketname=outputs[bucketkey]
s3=boto3.client("s3")
print (s3.put_object(Bucket=bucketname,
Key="index.html",
Body=open("index.html").read(),
ContentType="text/html"))
except RuntimeError as error:
print ("Error: %s" % str(error))
except ClientError as error:
print ("Error: %s" % str(error))
awscli
boto3
botocore
pyyaml
requests
#!/usr/bin/env bash
export AWS_DEFAULT_OUTPUT=table
export AWS_PROFILE=woldeploy
export AWS_REGION=eu-west-1
export CERTIFICATE_ARN=arn:aws:acm:us-east-1:119552584133:certificate/74aeb9e7-1db1-4ece-bbf5-9e3d4f800f36
export DOMAIN_NAME=apigwdemo.spaaseu.link

short

thoughts

  • remove POST stuff?

done

  • website
  • private api
  • check with renamed endpoint
  • remove v1 suffixes
  • cors test
  • check domains and certificates
{
"Outputs": {
"AppIdentityPool": {
"Value": {
"Ref": "AppIdentityPool"
}
},
"AppRestApi": {
"Value": {
"Ref": "AppRestApi"
}
},
"AppUserPool": {
"Value": {
"Ref": "AppUserPool"
}
},
"AppUserPoolAdminClient": {
"Value": {
"Ref": "AppUserPoolAdminClient"
}
},
"AppUserPoolWebClient": {
"Value": {
"Ref": "AppUserPoolWebClient"
}
}
},
"Parameters": {
"CertificateArn": {
"Type": "String"
},
"DomainName": {
"Type": "String"
}
},
"Resources": {
"AppAuthorizer": {
"Properties": {
"IdentitySource": "method.request.header.Authorization",
"Name": {
"Fn::Sub": "app-authorizer-${AWS::StackName}"
},
"ProviderARNs": [
{
"Fn::GetAtt": [
"AppUserPool",
"Arn"
]
}
],
"RestApiId": {
"Ref": "AppRestApi"
},
"Type": "COGNITO_USER_POOLS"
},
"Type": "AWS::ApiGateway::Authorizer"
},
"AppBasePathMapping": {
"DependsOn": [
"AppDomainName"
],
"Properties": {
"DomainName": {
"Ref": "DomainName"
},
"RestApiId": {
"Ref": "AppRestApi"
},
"Stage": "prod"
},
"Type": "AWS::ApiGateway::BasePathMapping"
},
"AppDeployment": {
"DependsOn": [
"AppHelloGetPrivateLambdaMethod",
"AppHelloGetCorsMethod",
"AppHelloPostPrivateLambdaMethod",
"AppHelloPostCorsMethod"
],
"Properties": {
"RestApiId": {
"Ref": "AppRestApi"
}
},
"Type": "AWS::ApiGateway::Deployment"
},
"AppDomainName": {
"Properties": {
"CertificateArn": {
"Ref": "CertificateArn"
},
"DomainName": {
"Ref": "DomainName"
}
},
"Type": "AWS::ApiGateway::DomainName"
},
"AppGatewayResponse4xx": {
"Properties": {
"ResponseParameters": {
"gatewayresponse.header.Access-Control-Allow-Headers": "'*'",
"gatewayresponse.header.Access-Control-Allow-Origin": "'*'"
},
"ResponseType": "DEFAULT_4XX",
"RestApiId": {
"Ref": "AppRestApi"
}
},
"Type": "AWS::ApiGateway::GatewayResponse"
},
"AppGatewayResponse5xx": {
"Properties": {
"ResponseParameters": {
"gatewayresponse.header.Access-Control-Allow-Headers": "'*'",
"gatewayresponse.header.Access-Control-Allow-Origin": "'*'"
},
"ResponseType": "DEFAULT_5XX",
"RestApiId": {
"Ref": "AppRestApi"
}
},
"Type": "AWS::ApiGateway::GatewayResponse"
},
"AppHelloGetCorsMethod": {
"Properties": {
"AuthorizationType": "NONE",
"HttpMethod": "OPTIONS",
"Integration": {
"IntegrationResponses": [
{
"ResponseParameters": {
"method.response.header.Access-Control-Allow-Headers": "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Sec'",
"method.response.header.Access-Control-Allow-Methods": "'GET,OPTIONS'",
"method.response.header.Access-Control-Allow-Origin": "'*'"
},
"ResponseTemplates": {
"application/json": ""
},
"StatusCode": 200
}
],
"PassthroughBehavior": "WHEN_NO_MATCH",
"RequestTemplates": {
"application/json": "{\"statusCode\": 200}"
},
"Type": "MOCK"
},
"MethodResponses": [
{
"ResponseModels": {
"application/json": "Empty"
},
"ResponseParameters": {
"method.response.header.Access-Control-Allow-Headers": false,
"method.response.header.Access-Control-Allow-Methods": false,
"method.response.header.Access-Control-Allow-Origin": false
},
"StatusCode": 200
}
],
"ResourceId": {
"Ref": "AppHelloGetResource"
},
"RestApiId": {
"Ref": "AppRestApi"
}
},
"Type": "AWS::ApiGateway::Method"
},
"AppHelloGetFunction": {
"Properties": {
"Code": {
"ZipFile": "def handler(event, context):\n message=event[\"queryStringParameters\"][\"message\"]\n return {\"statusCode\": 200,\n \"headers\": {\"Content-Type\": \"text/plain\",\n \"Access-Control-Allow-Origin\": \"*\",\n \"Access-Control-Allow-Headers\": \"Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Amz-User-Agent\",\n \"Access-Control-Allow-Methods\": \"OPTIONS,GET\"},\n \"body\": f\"you sent '{message}' via GET\"}"
},
"Handler": "index.handler",
"MemorySize": 512,
"Role": {
"Fn::GetAtt": [
"AppHelloGetRole",
"Arn"
]
},
"Runtime": "python3.10",
"Timeout": 5
},
"Type": "AWS::Lambda::Function"
},
"AppHelloGetParameterRequestValidator": {
"Properties": {
"RestApiId": {
"Ref": "AppRestApi"
},
"ValidateRequestBody": false,
"ValidateRequestParameters": true
},
"Type": "AWS::ApiGateway::RequestValidator"
},
"AppHelloGetPermission": {
"Properties": {
"Action": "lambda:InvokeFunction",
"FunctionName": {
"Ref": "AppHelloGetFunction"
},
"Principal": "apigateway.amazonaws.com",
"SourceArn": {
"Fn::Sub": "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${AppRestApi}/${AppStage}/GET/hello-get"
}
},
"Type": "AWS::Lambda::Permission"
},
"AppHelloGetPolicy": {
"Properties": {
"PolicyDocument": {
"Statement": [
{
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"s3:GetObject"
],
"Effect": "Allow",
"Resource": "*"
}
],
"Version": "2012-10-17"
},
"PolicyName": {
"Fn::Sub": "app-hello-get-policy-${AWS::StackName}"
},
"Roles": [
{
"Ref": "AppHelloGetRole"
}
]
},
"Type": "AWS::IAM::Policy"
},
"AppHelloGetPrivateLambdaMethod": {
"Properties": {
"AuthorizationType": "COGNITO_USER_POOLS",
"AuthorizerId": {
"Ref": "AppAuthorizer"
},
"HttpMethod": "GET",
"Integration": {
"IntegrationHttpMethod": "POST",
"Type": "AWS_PROXY",
"Uri": {
"Fn::Sub": [
"arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${arn}/invocations",
{
"arn": {
"Fn::GetAtt": [
"AppHelloGetFunction",
"Arn"
]
}
}
]
}
},
"RequestParameters": {
"method.request.querystring.message": true
},
"RequestValidatorId": {
"Ref": "AppHelloGetParameterRequestValidator"
},
"ResourceId": {
"Ref": "AppHelloGetResource"
},
"RestApiId": {
"Ref": "AppRestApi"
}
},
"Type": "AWS::ApiGateway::Method"
},
"AppHelloGetResource": {
"Properties": {
"ParentId": {
"Fn::GetAtt": [
"AppRestApi",
"RootResourceId"
]
},
"PathPart": "hello-get",
"RestApiId": {
"Ref": "AppRestApi"
}
},
"Type": "AWS::ApiGateway::Resource"
},
"AppHelloGetRole": {
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": [
"sts:AssumeRole"
],
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
}
}
],
"Version": "2012-10-17"
}
},
"Type": "AWS::IAM::Role"
},
"AppHelloPostCorsMethod": {
"Properties": {
"AuthorizationType": "NONE",
"HttpMethod": "OPTIONS",
"Integration": {
"IntegrationResponses": [
{
"ResponseParameters": {
"method.response.header.Access-Control-Allow-Headers": "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Sec'",
"method.response.header.Access-Control-Allow-Methods": "'POST,OPTIONS'",
"method.response.header.Access-Control-Allow-Origin": "'*'"
},
"ResponseTemplates": {
"application/json": ""
},
"StatusCode": 200
}
],
"PassthroughBehavior": "WHEN_NO_MATCH",
"RequestTemplates": {
"application/json": "{\"statusCode\": 200}"
},
"Type": "MOCK"
},
"MethodResponses": [
{
"ResponseModels": {
"application/json": "Empty"
},
"ResponseParameters": {
"method.response.header.Access-Control-Allow-Headers": false,
"method.response.header.Access-Control-Allow-Methods": false,
"method.response.header.Access-Control-Allow-Origin": false
},
"StatusCode": 200
}
],
"ResourceId": {
"Ref": "AppHelloPostResource"
},
"RestApiId": {
"Ref": "AppRestApi"
}
},
"Type": "AWS::ApiGateway::Method"
},
"AppHelloPostFunction": {
"Properties": {
"Code": {
"ZipFile": "import json\ndef handler(event, context):\n body=json.loads(event[\"body\"])\n message=body[\"message\"]\n return {\"statusCode\": 200,\n \"headers\": {\"Content-Type\": \"text/plain\",\n \"Access-Control-Allow-Origin\": \"*\",\n \"Access-Control-Allow-Headers\": \"Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Amz-User-Agent\",\n \"Access-Control-Allow-Methods\": \"OPTIONS,POST\"},\n \"body\": f\"you sent '{message}' via POST\"}"
},
"Handler": "index.handler",
"MemorySize": 512,
"Role": {
"Fn::GetAtt": [
"AppHelloPostRole",
"Arn"
]
},
"Runtime": "python3.10",
"Timeout": 5
},
"Type": "AWS::Lambda::Function"
},
"AppHelloPostModel": {
"Properties": {
"ContentType": "application/json",
"Name": "AppHelloPostModel",
"RestApiId": {
"Ref": "AppRestApi"
},
"Schema": {
"$schema": "http://json-schema.org/draft-04/schema#",
"additionalProperties": false,
"properties": {
"message": {
"type": "string"
}
},
"required": [
"message"
],
"type": "object"
}
},
"Type": "AWS::ApiGateway::Model"
},
"AppHelloPostPermission": {
"Properties": {
"Action": "lambda:InvokeFunction",
"FunctionName": {
"Ref": "AppHelloPostFunction"
},
"Principal": "apigateway.amazonaws.com",
"SourceArn": {
"Fn::Sub": "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${AppRestApi}/${AppStage}/POST/hello-post"
}
},
"Type": "AWS::Lambda::Permission"
},
"AppHelloPostPolicy": {
"Properties": {
"PolicyDocument": {
"Statement": [
{
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Effect": "Allow",
"Resource": "*"
}
],
"Version": "2012-10-17"
},
"PolicyName": {
"Fn::Sub": "app-hello-post-policy-${AWS::StackName}"
},
"Roles": [
{
"Ref": "AppHelloPostRole"
}
]
},
"Type": "AWS::IAM::Policy"
},
"AppHelloPostPrivateLambdaMethod": {
"Properties": {
"AuthorizationType": "COGNITO_USER_POOLS",
"AuthorizerId": {
"Ref": "AppAuthorizer"
},
"HttpMethod": "POST",
"Integration": {
"IntegrationHttpMethod": "POST",
"Type": "AWS_PROXY",
"Uri": {
"Fn::Sub": [
"arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${arn}/invocations",
{
"arn": {
"Fn::GetAtt": [
"AppHelloPostFunction",
"Arn"
]
}
}
]
}
},
"RequestModels": {
"application/json": "AppHelloPostModel"
},
"RequestValidatorId": {
"Ref": "AppHelloPostSchemaRequestValidator"
},
"ResourceId": {
"Ref": "AppHelloPostResource"
},
"RestApiId": {
"Ref": "AppRestApi"
}
},
"Type": "AWS::ApiGateway::Method"
},
"AppHelloPostResource": {
"Properties": {
"ParentId": {
"Fn::GetAtt": [
"AppRestApi",
"RootResourceId"
]
},
"PathPart": "hello-post",
"RestApiId": {
"Ref": "AppRestApi"
}
},
"Type": "AWS::ApiGateway::Resource"
},
"AppHelloPostRole": {
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": [
"sts:AssumeRole"
],
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
}
}
],
"Version": "2012-10-17"
}
},
"Type": "AWS::IAM::Role"
},
"AppHelloPostSchemaRequestValidator": {
"Properties": {
"RestApiId": {
"Ref": "AppRestApi"
},
"ValidateRequestBody": true,
"ValidateRequestParameters": false
},
"Type": "AWS::ApiGateway::RequestValidator"
},
"AppIdentityPool": {
"Properties": {
"AllowUnauthenticatedIdentities": true,
"CognitoIdentityProviders": [
{
"ClientId": {
"Ref": "AppUserPoolWebClient"
},
"ProviderName": {
"Fn::GetAtt": [
"AppUserPool",
"ProviderName"
]
}
}
]
},
"Type": "AWS::Cognito::IdentityPool"
},
"AppIdentityPoolAuthorizedPolicy": {
"Properties": {
"PolicyDocument": {
"Statement": [
{
"Action": [
"cognito-sync:*"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"cognito-identity:*"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"lambda:InvokeFunction"
],
"Effect": "Allow",
"Resource": "*"
}
],
"Version": "2012-10-17"
},
"PolicyName": {
"Fn::Sub": "app-identity-pool-authorized-policy-${AWS::StackName}"
},
"Roles": [
{
"Ref": "AppIdentityPoolAuthorizedRole"
}
]
},
"Type": "AWS::IAM::Policy"
},
"AppIdentityPoolAuthorizedRole": {
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": [
"sts:AssumeRoleWithWebIdentity"
],
"Condition": {
"ForAnyValue:StringLike": {
"cognito-identity.amazonaws.com:amr": "authorized"
},
"StringEquals": {
"cognito-identity.amazonaws.com:aud": {
"Ref": "AppIdentityPool"
}
}
},
"Effect": "Allow",
"Principal": {
"Federated": "cognito-identity.amazonaws.com"
}
}
],
"Version": "2012-10-17"
}
},
"Type": "AWS::IAM::Role"
},
"AppIdentityPoolRoleAttachment": {
"Properties": {
"IdentityPoolId": {
"Ref": "AppIdentityPool"
},
"Roles": {
"authenticated": {
"Fn::GetAtt": [
"AppIdentityPoolAuthorizedRole",
"Arn"
]
},
"unauthenticated": {
"Fn::GetAtt": [
"AppIdentityPoolUnauthorizedRole",
"Arn"
]
}
}
},
"Type": "AWS::Cognito::IdentityPoolRoleAttachment"
},
"AppIdentityPoolUnauthorizedPolicy": {
"Properties": {
"PolicyDocument": {
"Statement": [
{
"Action": [
"cognito-sync:*"
],
"Effect": "Allow",
"Resource": "*"
}
],
"Version": "2012-10-17"
},
"PolicyName": {
"Fn::Sub": "app-identity-pool-unauthorized-policy-${AWS::StackName}"
},
"Roles": [
{
"Ref": "AppIdentityPoolUnauthorizedRole"
}
]
},
"Type": "AWS::IAM::Policy"
},
"AppIdentityPoolUnauthorizedRole": {
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": [
"sts:AssumeRoleWithWebIdentity"
],
"Condition": {
"ForAnyValue:StringLike": {
"cognito-identity.amazonaws.com:amr": "unauthorized"
},
"StringEquals": {
"cognito-identity.amazonaws.com:aud": {
"Ref": "AppIdentityPool"
}
}
},
"Effect": "Allow",
"Principal": {
"Federated": "cognito-identity.amazonaws.com"
}
}
],
"Version": "2012-10-17"
}
},
"Type": "AWS::IAM::Role"
},
"AppRecordSet": {
"Properties": {
"AliasTarget": {
"DNSName": {
"Fn::GetAtt": [
"AppDomainName",
"DistributionDomainName"
]
},
"EvaluateTargetHealth": false,
"HostedZoneId": {
"Fn::GetAtt": [
"AppDomainName",
"DistributionHostedZoneId"
]
}
},
"HostedZoneName": {
"Fn::Sub": [
"${prefix}.${suffix}.",
{
"prefix": {
"Fn::Select": [
1,
{
"Fn::Split": [
".",
{
"Ref": "DomainName"
}
]
}
]
},
"suffix": {
"Fn::Select": [
2,
{
"Fn::Split": [
".",
{
"Ref": "DomainName"
}
]
}
]
}
}
]
},
"Name": {
"Ref": "DomainName"
},
"Type": "A"
},
"Type": "AWS::Route53::RecordSet"
},
"AppRestApi": {
"Properties": {
"Name": {
"Fn::Sub": "app-rest-api-${AWS::StackName}"
}
},
"Type": "AWS::ApiGateway::RestApi"
},
"AppStage": {
"Properties": {
"DeploymentId": {
"Ref": "AppDeployment"
},
"RestApiId": {
"Ref": "AppRestApi"
},
"StageName": "prod"
},
"Type": "AWS::ApiGateway::Stage"
},
"AppUserPool": {
"Properties": {
"AutoVerifiedAttributes": [
"email"
],
"Policies": {
"PasswordPolicy": {
"MinimumLength": 8,
"RequireLowercase": true,
"RequireNumbers": true,
"RequireSymbols": true,
"RequireUppercase": true
}
},
"Schema": [
{
"AttributeDataType": "String",
"Mutable": true,
"Name": "email",
"Required": true,
"StringAttributeConstraints": {
"MinLength": "1"
}
}
],
"UsernameAttributes": [
"email"
]
},
"Type": "AWS::Cognito::UserPool"
},
"AppUserPoolAdminClient": {
"Properties": {
"ExplicitAuthFlows": [
"ALLOW_ADMIN_USER_PASSWORD_AUTH",
"ALLOW_REFRESH_TOKEN_AUTH"
],
"PreventUserExistenceErrors": "ENABLED",
"UserPoolId": {
"Ref": "AppUserPool"
}
},
"Type": "AWS::Cognito::UserPoolClient"
},
"AppUserPoolWebClient": {
"Properties": {
"ExplicitAuthFlows": [
"ALLOW_USER_SRP_AUTH",
"ALLOW_REFRESH_TOKEN_AUTH"
],
"PreventUserExistenceErrors": "ENABLED",
"UserPoolId": {
"Ref": "AppUserPool"
}
},
"Type": "AWS::Cognito::UserPoolClient"
}
}
}
{
"Outputs": {
"AppRestApi": {
"Value": {
"Ref": "AppRestApi"
}
}
},
"Parameters": {
"CertificateArn": {
"Type": "String"
},
"DomainName": {
"Type": "String"
}
},
"Resources": {
"AppBasePathMapping": {
"DependsOn": [
"AppDomainName"
],
"Properties": {
"DomainName": {
"Ref": "DomainName"
},
"RestApiId": {
"Ref": "AppRestApi"
},
"Stage": "prod"
},
"Type": "AWS::ApiGateway::BasePathMapping"
},
"AppDeployment": {
"DependsOn": [
"AppHelloGetPublicLambdaMethod",
"AppHelloGetCorsMethod",
"AppHelloPostPublicLambdaMethod",
"AppHelloPostCorsMethod"
],
"Properties": {
"RestApiId": {
"Ref": "AppRestApi"
}
},
"Type": "AWS::ApiGateway::Deployment"
},
"AppDomainName": {
"Properties": {
"CertificateArn": {
"Ref": "CertificateArn"
},
"DomainName": {
"Ref": "DomainName"
}
},
"Type": "AWS::ApiGateway::DomainName"
},
"AppGatewayResponse4xx": {
"Properties": {
"ResponseParameters": {
"gatewayresponse.header.Access-Control-Allow-Headers": "'*'",
"gatewayresponse.header.Access-Control-Allow-Origin": "'*'"
},
"ResponseType": "DEFAULT_4XX",
"RestApiId": {
"Ref": "AppRestApi"
}
},
"Type": "AWS::ApiGateway::GatewayResponse"
},
"AppGatewayResponse5xx": {
"Properties": {
"ResponseParameters": {
"gatewayresponse.header.Access-Control-Allow-Headers": "'*'",
"gatewayresponse.header.Access-Control-Allow-Origin": "'*'"
},
"ResponseType": "DEFAULT_5XX",
"RestApiId": {
"Ref": "AppRestApi"
}
},
"Type": "AWS::ApiGateway::GatewayResponse"
},
"AppHelloGetCorsMethod": {
"Properties": {
"AuthorizationType": "NONE",
"HttpMethod": "OPTIONS",
"Integration": {
"IntegrationResponses": [
{
"ResponseParameters": {
"method.response.header.Access-Control-Allow-Headers": "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Sec'",
"method.response.header.Access-Control-Allow-Methods": "'GET,OPTIONS'",
"method.response.header.Access-Control-Allow-Origin": "'*'"
},
"ResponseTemplates": {
"application/json": ""
},
"StatusCode": 200
}
],
"PassthroughBehavior": "WHEN_NO_MATCH",
"RequestTemplates": {
"application/json": "{\"statusCode\": 200}"
},
"Type": "MOCK"
},
"MethodResponses": [
{
"ResponseModels": {
"application/json": "Empty"
},
"ResponseParameters": {
"method.response.header.Access-Control-Allow-Headers": false,
"method.response.header.Access-Control-Allow-Methods": false,
"method.response.header.Access-Control-Allow-Origin": false
},
"StatusCode": 200
}
],
"ResourceId": {
"Ref": "AppHelloGetResource"
},
"RestApiId": {
"Ref": "AppRestApi"
}
},
"Type": "AWS::ApiGateway::Method"
},
"AppHelloGetFunction": {
"Properties": {
"Code": {
"ZipFile": "def handler(event, context):\n message=event[\"queryStringParameters\"][\"message\"]\n return {\"statusCode\": 200,\n \"headers\": {\"Content-Type\": \"text/plain\",\n \"Access-Control-Allow-Origin\": \"*\",\n \"Access-Control-Allow-Headers\": \"Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Amz-User-Agent\",\n \"Access-Control-Allow-Methods\": \"OPTIONS,GET\"},\n \"body\": f\"you sent '{message}' via GET\"}"
},
"Handler": "index.handler",
"MemorySize": 512,
"Role": {
"Fn::GetAtt": [
"AppHelloGetRole",
"Arn"
]
},
"Runtime": "python3.10",
"Timeout": 5
},
"Type": "AWS::Lambda::Function"
},
"AppHelloGetParameterRequestValidator": {
"Properties": {
"RestApiId": {
"Ref": "AppRestApi"
},
"ValidateRequestBody": false,
"ValidateRequestParameters": true
},
"Type": "AWS::ApiGateway::RequestValidator"
},
"AppHelloGetPermission": {
"Properties": {
"Action": "lambda:InvokeFunction",
"FunctionName": {
"Ref": "AppHelloGetFunction"
},
"Principal": "apigateway.amazonaws.com",
"SourceArn": {
"Fn::Sub": "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${AppRestApi}/${AppStage}/GET/hello-get"
}
},
"Type": "AWS::Lambda::Permission"
},
"AppHelloGetPolicy": {
"Properties": {
"PolicyDocument": {
"Statement": [
{
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"s3:GetObject"
],
"Effect": "Allow",
"Resource": "*"
}
],
"Version": "2012-10-17"
},
"PolicyName": {
"Fn::Sub": "app-hello-get-policy-${AWS::StackName}"
},
"Roles": [
{
"Ref": "AppHelloGetRole"
}
]
},
"Type": "AWS::IAM::Policy"
},
"AppHelloGetPublicLambdaMethod": {
"Properties": {
"AuthorizationType": "NONE",
"HttpMethod": "GET",
"Integration": {
"IntegrationHttpMethod": "POST",
"Type": "AWS_PROXY",
"Uri": {
"Fn::Sub": [
"arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${arn}/invocations",
{
"arn": {
"Fn::GetAtt": [
"AppHelloGetFunction",
"Arn"
]
}
}
]
}
},
"RequestParameters": {
"method.request.querystring.message": true
},
"RequestValidatorId": {
"Ref": "AppHelloGetParameterRequestValidator"
},
"ResourceId": {
"Ref": "AppHelloGetResource"
},
"RestApiId": {
"Ref": "AppRestApi"
}
},
"Type": "AWS::ApiGateway::Method"
},
"AppHelloGetResource": {
"Properties": {
"ParentId": {
"Fn::GetAtt": [
"AppRestApi",
"RootResourceId"
]
},
"PathPart": "hello-get",
"RestApiId": {
"Ref": "AppRestApi"
}
},
"Type": "AWS::ApiGateway::Resource"
},
"AppHelloGetRole": {
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": [
"sts:AssumeRole"
],
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
}
}
],
"Version": "2012-10-17"
}
},
"Type": "AWS::IAM::Role"
},
"AppHelloPostCorsMethod": {
"Properties": {
"AuthorizationType": "NONE",
"HttpMethod": "OPTIONS",
"Integration": {
"IntegrationResponses": [
{
"ResponseParameters": {
"method.response.header.Access-Control-Allow-Headers": "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Sec'",
"method.response.header.Access-Control-Allow-Methods": "'POST,OPTIONS'",
"method.response.header.Access-Control-Allow-Origin": "'*'"
},
"ResponseTemplates": {
"application/json": ""
},
"StatusCode": 200
}
],
"PassthroughBehavior": "WHEN_NO_MATCH",
"RequestTemplates": {
"application/json": "{\"statusCode\": 200}"
},
"Type": "MOCK"
},
"MethodResponses": [
{
"ResponseModels": {
"application/json": "Empty"
},
"ResponseParameters": {
"method.response.header.Access-Control-Allow-Headers": false,
"method.response.header.Access-Control-Allow-Methods": false,
"method.response.header.Access-Control-Allow-Origin": false
},
"StatusCode": 200
}
],
"ResourceId": {
"Ref": "AppHelloPostResource"
},
"RestApiId": {
"Ref": "AppRestApi"
}
},
"Type": "AWS::ApiGateway::Method"
},
"AppHelloPostFunction": {
"Properties": {
"Code": {
"ZipFile": "import json\ndef handler(event, context):\n body=json.loads(event[\"body\"])\n message=body[\"message\"]\n return {\"statusCode\": 200,\n \"headers\": {\"Content-Type\": \"text/plain\",\n \"Access-Control-Allow-Origin\": \"*\",\n \"Access-Control-Allow-Headers\": \"Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Amz-User-Agent\",\n \"Access-Control-Allow-Methods\": \"OPTIONS,POST\"},\n \"body\": f\"you sent '{message}' via POST\"}"
},
"Handler": "index.handler",
"MemorySize": 512,
"Role": {
"Fn::GetAtt": [
"AppHelloPostRole",
"Arn"
]
},
"Runtime": "python3.10",
"Timeout": 5
},
"Type": "AWS::Lambda::Function"
},
"AppHelloPostModel": {
"Properties": {
"ContentType": "application/json",
"Name": "AppHelloPostModel",
"RestApiId": {
"Ref": "AppRestApi"
},
"Schema": {
"$schema": "http://json-schema.org/draft-04/schema#",
"additionalProperties": false,
"properties": {
"message": {
"type": "string"
}
},
"required": [
"message"
],
"type": "object"
}
},
"Type": "AWS::ApiGateway::Model"
},
"AppHelloPostPermission": {
"Properties": {
"Action": "lambda:InvokeFunction",
"FunctionName": {
"Ref": "AppHelloPostFunction"
},
"Principal": "apigateway.amazonaws.com",
"SourceArn": {
"Fn::Sub": "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${AppRestApi}/${AppStage}/POST/hello-post"
}
},
"Type": "AWS::Lambda::Permission"
},
"AppHelloPostPolicy": {
"Properties": {
"PolicyDocument": {
"Statement": [
{
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Effect": "Allow",
"Resource": "*"
}
],
"Version": "2012-10-17"
},
"PolicyName": {
"Fn::Sub": "app-hello-post-policy-${AWS::StackName}"
},
"Roles": [
{
"Ref": "AppHelloPostRole"
}
]
},
"Type": "AWS::IAM::Policy"
},
"AppHelloPostPublicLambdaMethod": {
"Properties": {
"AuthorizationType": "NONE",
"HttpMethod": "POST",
"Integration": {
"IntegrationHttpMethod": "POST",
"Type": "AWS_PROXY",
"Uri": {
"Fn::Sub": [
"arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${arn}/invocations",
{
"arn": {
"Fn::GetAtt": [
"AppHelloPostFunction",
"Arn"
]
}
}
]
}
},
"RequestModels": {
"application/json": "AppHelloPostModel"
},
"RequestValidatorId": {
"Ref": "AppHelloPostSchemaRequestValidator"
},
"ResourceId": {
"Ref": "AppHelloPostResource"
},
"RestApiId": {
"Ref": "AppRestApi"
}
},
"Type": "AWS::ApiGateway::Method"
},
"AppHelloPostResource": {
"Properties": {
"ParentId": {
"Fn::GetAtt": [
"AppRestApi",
"RootResourceId"
]
},
"PathPart": "hello-post",
"RestApiId": {
"Ref": "AppRestApi"
}
},
"Type": "AWS::ApiGateway::Resource"
},
"AppHelloPostRole": {
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": [
"sts:AssumeRole"
],
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
}
}
],
"Version": "2012-10-17"
}
},
"Type": "AWS::IAM::Role"
},
"AppHelloPostSchemaRequestValidator": {
"Properties": {
"RestApiId": {
"Ref": "AppRestApi"
},
"ValidateRequestBody": true,
"ValidateRequestParameters": false
},
"Type": "AWS::ApiGateway::RequestValidator"
},
"AppRecordSet": {
"Properties": {
"AliasTarget": {
"DNSName": {
"Fn::GetAtt": [
"AppDomainName",
"DistributionDomainName"
]
},
"EvaluateTargetHealth": false,
"HostedZoneId": {
"Fn::GetAtt": [
"AppDomainName",
"DistributionHostedZoneId"
]
}
},
"HostedZoneName": {
"Fn::Sub": [
"${prefix}.${suffix}.",
{
"prefix": {
"Fn::Select": [
1,
{
"Fn::Split": [
".",
{
"Ref": "DomainName"
}
]
}
]
},
"suffix": {
"Fn::Select": [
2,
{
"Fn::Split": [
".",
{
"Ref": "DomainName"
}
]
}
]
}
}
]
},
"Name": {
"Ref": "DomainName"
},
"Type": "A"
},
"Type": "AWS::Route53::RecordSet"
},
"AppRestApi": {
"Properties": {
"Name": {
"Fn::Sub": "app-rest-api-${AWS::StackName}"
}
},
"Type": "AWS::ApiGateway::RestApi"
},
"AppStage": {
"Properties": {
"DeploymentId": {
"Ref": "AppDeployment"
},
"RestApiId": {
"Ref": "AppRestApi"
},
"StageName": "prod"
},
"Type": "AWS::ApiGateway::Stage"
}
}
}
{
"Outputs": {
"AppBucket": {
"Value": {
"Ref": "AppBucket"
}
},
"AppRestApi": {
"Value": {
"Ref": "AppRestApi"
}
}
},
"Parameters": {
"CertificateArn": {
"Type": "String"
},
"DomainName": {
"Type": "String"
}
},
"Resources": {
"AppBasePathMapping": {
"DependsOn": [
"AppDomainName"
],
"Properties": {
"DomainName": {
"Ref": "DomainName"
},
"RestApiId": {
"Ref": "AppRestApi"
},
"Stage": "prod"
},
"Type": "AWS::ApiGateway::BasePathMapping"
},
"AppBucket": {
"Properties": {
"NotificationConfiguration": {
"EventBridgeConfiguration": {
"EventBridgeEnabled": true
}
}
},
"Type": "AWS::S3::Bucket"
},
"AppDeployment": {
"DependsOn": [
"AppProxyMethod",
"AppRedirectMethod"
],
"Properties": {
"RestApiId": {
"Ref": "AppRestApi"
}
},
"Type": "AWS::ApiGateway::Deployment"
},
"AppDomainName": {
"Properties": {
"CertificateArn": {
"Ref": "CertificateArn"
},
"DomainName": {
"Ref": "DomainName"
}
},
"Type": "AWS::ApiGateway::DomainName"
},
"AppPolicy": {
"Properties": {
"PolicyDocument": {
"Statement": [
{
"Action": [
"s3:GetObject"
],
"Effect": "Allow",
"Resource": {
"Fn::Sub": "arn:aws:s3:::${AppBucket}/*"
}
}
],
"Version": "2012-10-17"
},
"PolicyName": {
"Fn::Sub": "app-policy-${AWS::StackName}"
},
"Roles": [
{
"Ref": "AppRole"
}
]
},
"Type": "AWS::IAM::Policy"
},
"AppProxyMethod": {
"Properties": {
"AuthorizationType": "NONE",
"HttpMethod": "GET",
"Integration": {
"Credentials": {
"Fn::GetAtt": [
"AppRole",
"Arn"
]
},
"IntegrationHttpMethod": "ANY",
"IntegrationResponses": [
{
"ResponseParameters": {
"method.response.header.Content-Type": "integration.response.header.Content-Type"
},
"StatusCode": 200
},
{
"SelectionPattern": "404",
"StatusCode": 404
}
],
"PassthroughBehavior": "WHEN_NO_MATCH",
"RequestParameters": {
"integration.request.path.proxy": "method.request.path.proxy"
},
"Type": "AWS",
"Uri": {
"Fn::Sub": "arn:aws:apigateway:${AWS::Region}:s3:path/${AppBucket}/{proxy}"
}
},
"MethodResponses": [
{
"ResponseParameters": {
"method.response.header.Content-Type": true
},
"StatusCode": 200
},
{
"StatusCode": 404
}
],
"RequestParameters": {
"method.request.path.proxy": true
},
"ResourceId": {
"Ref": "AppResource"
},
"RestApiId": {
"Ref": "AppRestApi"
}
},
"Type": "AWS::ApiGateway::Method"
},
"AppRecordSet": {
"Properties": {
"AliasTarget": {
"DNSName": {
"Fn::GetAtt": [
"AppDomainName",
"DistributionDomainName"
]
},
"EvaluateTargetHealth": false,
"HostedZoneId": {
"Fn::GetAtt": [
"AppDomainName",
"DistributionHostedZoneId"
]
}
},
"HostedZoneName": {
"Fn::Sub": [
"${prefix}.${suffix}.",
{
"prefix": {
"Fn::Select": [
1,
{
"Fn::Split": [
".",
{
"Ref": "DomainName"
}
]
}
]
},
"suffix": {
"Fn::Select": [
2,
{
"Fn::Split": [
".",
{
"Ref": "DomainName"
}
]
}
]
}
}
]
},
"Name": {
"Ref": "DomainName"
},
"Type": "A"
},
"Type": "AWS::Route53::RecordSet"
},
"AppRedirectMethod": {
"Properties": {
"AuthorizationType": "NONE",
"HttpMethod": "GET",
"Integration": {
"IntegrationResponses": [
{
"ResponseParameters": {
"method.response.header.Location": {
"Fn::Sub": "'https://${DomainName}/index.html'"
}
},
"ResponseTemplates": {
"application/json": "{}"
},
"StatusCode": 302
}
],
"RequestTemplates": {
"application/json": "{\"statusCode\" : 302}"
},
"Type": "MOCK"
},
"MethodResponses": [
{
"ResponseParameters": {
"method.response.header.Location": true
},
"StatusCode": 302
}
],
"ResourceId": {
"Fn::GetAtt": [
"AppRestApi",
"RootResourceId"
]
},
"RestApiId": {
"Ref": "AppRestApi"
}
},
"Type": "AWS::ApiGateway::Method"
},
"AppResource": {
"Properties": {
"ParentId": {
"Fn::GetAtt": [
"AppRestApi",
"RootResourceId"
]
},
"PathPart": "{proxy+}",
"RestApiId": {
"Ref": "AppRestApi"
}
},
"Type": "AWS::ApiGateway::Resource"
},
"AppRestApi": {
"Properties": {
"Name": {
"Fn::Sub": "app-rest-api-${AWS::StackName}"
}
},
"Type": "AWS::ApiGateway::RestApi"
},
"AppRole": {
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": [
"sts:AssumeRole"
],
"Effect": "Allow",
"Principal": {
"Service": "apigateway.amazonaws.com"
}
}
],
"Version": "2012-10-17"
}
},
"Type": "AWS::IAM::Role"
},
"AppStage": {
"Properties": {
"DeploymentId": {
"Ref": "AppDeployment"
},
"RestApiId": {
"Ref": "AppRestApi"
},
"StageName": "prod"
},
"Type": "AWS::ApiGateway::Stage"
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment