why deepstreamHub? compare us getting started feature roadmap faq
use cases pricing
products
developers
company
blog contact

This guide will take you through integrating with deepstreamHub with Amazon Web Service's Simple Notification Service.

With SNS we can send the same message to Smartphones, Email inboxes and VoIP clients, however there's currently no easy way to send these messages to web browsers.

In this quick guide we'll show you how to do this with deepstreamHub, we'll be using the JavaScript client SDK and the AWS client sdk for NodeJs.

Create a free account and get your API key

The basic setup

In this tutorial, we’ll build a “sns-provider”, a node process that subscribes to a SNS topic and forwards its messages as deepstream events. For this to work, our provider needs to:

-Authenticate against AWS

-Become a SNS HTTP endpoint

-Subscribe to a SNS topic

-Connect to deepstream

-Forward incoming messages as deepstream events

This looks like a lot, but we'll be able to accomplish with a relatively small amount of code. If you prefer diving right into the code, check out the github repo. Here's a high level overview of what our setup will look like.

setup-overview

For brevities sake, this tutorial skimps on security. AWS security is extremely powerful, but also complex enough to have whole books written about it. We’ll be using http instead of https and temporary security tokens (which is a good idea), but store them as plain text in our code (which is not). This tutorial also assumes that you're already familiar with deepstream's basic concepts. If not, quickly head over to the getting started tutorial - don't worry, I'll wait.

Let’s get started: Creating a topic.

We’ll start by creating a topic via the AWS console. Topics are the fundamental concept for message routing in a pub-sub architecture: Many subscribers listen to a topic and are notified whenever something publishes a message on that topic. Basically, it’s like JavaScript events, but you have to create a topic before you can subscribe. Let’s create a topic called “news” via the console:

create-sns-topic

Create the http server

Next up, we'll create a simple HTTP server. Why? The way SNS notifies your application of incoming messages is via HTTP. For this to work, your application needs to:

-Start a HTTP server

-Subscribe to a topic and tell SNS which URL it should send updates to

-Receive a “do you really want to receive updates?” message on that URL

-Confirm that message

And from there on, it receives all updates as incoming http requests. A few things to note about these requests:

-All incoming requests are POST requests

-The message data is JSON encoded

-Each message contains a " x-amz-sns-message-type” header that tells you which kind of message it is (e.g. “SubscriptionConfirmation” or “Notification”)

With this in mind, we can create an HTTP server like the following:

const server = new http.Server()
server.on('request', (request, response) => {
  request.setEncoding( 'utf8' )

  //concatenate POST data
  var msgBody = ''
  request.on('data', (data) => {
    msgBody += data
  })
  request.on( 'end', function(){
    var msgData = JSON.parse(msgBody)
    var msgType = request.headers['x-amz-sns-message-type']
    handleIncomingMessage(msgType, msgData)
  })

  // SNS doesn't care about our response as long as it comes
  // with a HTTP statuscode of 200
  response.end('OK')
})

server.listen(3000)

We'll also need to make this HTTP server accessible via the internet, we'd recommend running something like ngrok HTTP 3000 to accomplish this.

Subscribing to a topic

Using the AWS-SDK for Node.js, subscribing to a topic is as easy as:

const AWS = require('aws-sdk')
const sns = new AWS.SNS()

sns.subscribe({
    Protocol: 'http',
    // You don't just subscribe to "news", but the whole Amazon Resource Name (ARN)
    TopicArn: 'arn:aws:sns:eu-central-1:277026727916:news',
    Endpoint: 'http://your-endpoint-url.com'
}, (error, data) => {
    console.log(error || data)
})

But for this to work, we need to get two security steps out of the way first: Permission a user to use SNS and add its credentials to the Node SDK.

Here's how to permission a user via the AWS console:

attaching-SNS-policy

Next, we need to create a security token for this user. Using the AWS command line tool this is as simple as:

aws sts get-session-token

This will display a set of credentials that we can use to configure our SDK.

const AWS = require('aws-sdk')
AWS.config.update({
  "secretAccessKey": "...",
  "sessionToken": "...",
  "accessKeyId": "...",
  "region": "eu-central-1"
})
const sns = new AWS.SNS()

As mentioned before, embedding your credentials into the code might be easy, but it isn't safe. Have a look at the config documentation to find a better way to store credentials.

Confirming your subscription

Great, now our call to sns.subscribe should work. A few milliseconds after we've made it, our express server should receive a message, asking it to confirm the subscription. To process it, it's time to fill in the handleIncomingMessage(msgType, msgData) method from the HTTP server snippet.

const handleIncomingMessage = (msgType, msgData) => {
    if( msgType === 'SubscriptionConfirmation') {
        //confirm the subscription.
        sns.confirmSubscription({
            Token: msgData.Token,
            TopicArn: msgData.TopicArn
        }, onAwsResponse );
    } else if ( msgType === 'Notification' ) {
        // That's where the actual messages will arrive
    } else {
        console.log( 'Unexpected message type ' + msgType );
    }
}

All that's left now is to connect our SNS-provider to the deepstream server:

const deepstream = require('deepstream.io-client-js')
const client = deepstream('<Your app URL>')
client.login()

Forwarding SNS messages as deepstream events

Ok, time for the last piece of the puzzle. Every time we receive a message from SNS, we want to forward it as a deepstream event. (Events are deepstream's pub-sub mechanism. They work exactly like a JavaScript event emitter, distributed across many clients).

Each SNS message has a "Subject" and a "Message" - both of which are plain text. This leaves us with a couple of choices: We could use the topic as an event name, send JSON as the message body or come up with a totally different mechanism. But for now, let's keep things simple: Every time we receive a message, we'll use the Subject as an event-name and send the message content as event-data... or in code, inside our handleIncomingMessage method:

else if (msgType === 'Notification') {
    client.event.emit(msgData.Subject, msgData.Message)
}

Subscribing to this event from a browser is now as easy as:

client.event.subscribe('someEvent', (data) => {
    console.log(data)
})

And that's it. Thanks for holding out with me for so long. Be sure to check out the other guides and integrations we have, or check out building something more substantial with deepstreamHub via an example app.