In my last post, I described how an API Gateway can interact with Kinesis Firehose. This time I used the same approach to connect the API Gateway to SNS.
With this, I could simplify the access pattern for my application by exposing an internal HTTP Endpoint which then routes all requests to a corresponding SNS Topic.
So here an overview picture of what I am about to build.
The first part of the CloudFormation template is the definition of the API Gateway.
ApiGatewayRestApi:
Type: AWS::ApiGateway::RestApi
Properties:
Name: #make the name dynamic so I can instantiate this as often as necessary
Fn::Join:
- ""
- - Ref: AWS::StackName
- "-api"
As a prerequisite, I needed a role which would allow the API Gateway to actually write into the SNS Topic.
GatewayRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- apigateway.amazonaws.com
Action:
- sts:AssumeRole
Path: "/"
Policies:
- PolicyName: GatewayRolePolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- sns:Publish
Resource: "*" #grants access to all topics,
#for production use, this should be more specific
- Effect: Allow #allow logging (not essential to the solution)
Action:
- logs:PutLogEvents
- logs:CreateLogGroup
- logs:CreateLogStream
Resource: "*"
Now the difficult part is getting the method definition right. I’m using a GET method since it is simpler to call this from any browser/CLI/script environment.
The parameter mapping for SNS is derived from the AWS API documentation.
ApiGatewayGETMethod:
Type: AWS::ApiGateway::Method
Properties:
AuthorizationType: NONE
HttpMethod: GET
RequestParameters: #request parameters need to be defined for the mapping
method.request.querystring.message: false #payload of the SNS message
method.request.querystring.subject: false #subject of the SNS message
method.request.querystring.topic: false #destination topic arn
Integration:
Type: AWS
Credentials:
Fn::GetAtt: [ GatewayRole, Arn ] #use the already defined role
Uri: #required URI for using SNS service
Fn::Join:
- ""
- - "arn:aws:apigateway:"
- Ref: AWS::Region
- ":sns:action/Publish"
IntegrationHttpMethod: GET #SNS allows GET operations
RequestParameters: #parameter mapping defined by the AWS API.
integration.request.querystring.TopicArn: "method.request.querystring.topic"
integration.request.querystring.Subject: "method.request.querystring.subject"
integration.request.querystring.Message: "method.request.querystring.message"
IntegrationResponses: #map all responses to a default response.
- StatusCode: 200
ResponseTemplates: #default response
application/json: '{"status":"OK"}'
MethodResponses:
- StatusCode: 200
ResourceId: #attaching the GET method to the root resource of the API
Fn::GetAtt: [ ApiGatewayRestApi , RootResourceId ]
RestApiId: !Ref ApiGatewayRestApi
To also deploy this API within the same CloudFormation operation, I added a deployment instruction.
ApiGatewayDeployment:
Type: AWS::ApiGateway::Deployment
DependsOn: #without the depends on, the deployment is sometimes done before
#any operation is defined.
- ApiGatewayGETMethod
Properties:
RestApiId: !Ref ApiGatewayRestApi
StageName: prod
Now I can send notifications to any registered topic through the following curl command.
curl 'https://uyzf1ids8j.execute-api.eu-west-1.amazonaws.com/prod/
?topic=arn:aws:sns:eu-west-1:11111111111:test5
&subject=hello
&message=world'
Here is the overall CloudFormation template:
[api-to-sns-cf.yml template][1]
[1]:{{ site.url }}/assets/api-to-sns-cf.yml