Today I’m going to share with you how to handle AWS SNS notifications in a Ruby on Rails app. An SNS topic publishes every message it receives to every subscriber, and our app is subscribed to receive these messages via HTTP.
SNS messages come in 2 types:
- SubscriptionConfirmation: Is sent when a subscription is created to confirm that the endpoint is up an running. The confirm_subscription method handles this.
- Notification: Once the subscription is confirmed, all the following messages will be of this type. These are the messages that are sent to a topic and then fanned out to every subscriber out there.
The verify_request_authenticity method is called first to verify the authenticity of the SNS message. It checks that the message is not empty and verifies its origin using the MessageVerifier class. Finally, the create method parses the message content accordingly.
I hope this can be of great help to everyone out there. Feel free to comment if you have any questions or feedback.
# frozen_string_literal: true
# Notifications coming from SNS
class NotificationsController < ActionController::Base
before_action :verify_request_authenticity
# @url /notifications
#
# @action POST
#
# Broadcasts a SNS message to an ActionCable channel
#
#
def create
case message_body['Type']
when 'SubscriptionConfirmation'
confirm_subscription ? (head :ok) : (head :bad_request)
when 'Notification'
message = JSON.parse(message_body['Message'])
BroadcastExecutionNotificationJob.perform_later(message)
head :ok
end
end
private
def verify_request_authenticity
head :unauthorized if raw_post.blank? || !message_verifier.authentic?(raw_post)
end
def raw_post
@raw_post ||= request.raw_post
end
def message_body
@message_body ||= JSON.parse(raw_post)
end
def message_verifier
@message_verifier ||= Aws::SNS::MessageVerifier.new
end
def confirm_subscription
AWS_SNS_CLIENT.confirm_subscription(
topic_arn: message_body['TopicArn'],
token: message_body['Token']
)
true
rescue Aws::SNS::Errors::ServiceError => e
Rails.logger.info(e.message)
false
end
end
AWS_SNS_CLIENT is not defined:
the code below create the SNS client and uses it to confirm the subscription
def confirm_subscription
sns = Aws::SNS::Client.new(region: ‘us-east-1’)
sns.confirm_subscription(
topic_arn: message_body[‘TopicArn’],
token: message_body[‘Token’]
)
true
rescue Aws::SNS::Errors::ServiceError => e
Rails.logger.info(e.message)
false
end