AWS SNS – What You Should Know About it + a NodeJS Implementation


Image by unsplash

Hi there! In the past few weeks I’ve been working on the backend of a mobile chat application, or, what I like to call WhatsApp 2. The customer requested a way to send a push notification to the users when new messages arrived in a specific chat. One way to achieve this is by using the AWS Simple Notification Service (SNS).

In this article, I’ll explain how to use SNS with NodeJS and discuss some things you should be aware of, so let’s get started!

This article expects you to have previous knowledge on AWS, a AWS account and know how to use its SDK. If you don’t, here’s a helpful link getting started with AWS.

Push Notifications

If you know a little bit about push notifications services, you might be wondering how exactly can SNS send them? Well, SNS by itself is not the one responsible for it. For Android devices, I’ve been using the Firebase Cloud Messaging (FCM) and for IOS, the Apple Push Notification Service (APNs).

So, what is the point of using SNS? With Amazon SNS, you’ll be able to subscribe different devices to endpoints using the device token provided by each notification service. This way you can use SNS as an interface for each notification service, sending direct messages through them. You can also subscribe endpoints to topics, allowing you to send notifications to multiple devices at once.

For registering devices in SNS you’ll need to provide each device token, these are generated by assigning the device to its notification service. Endpoints are all registered in a Platform Application and each platform has its own push notification service, double check for compatibilty before registering the device notification service in an application.

I’m already talking about endpoints and there’s not even any code examples!? Yes, you can use the SNS dashboard to do pretty much everything you need. So, feel free to play around with it before coding anything, it will help you to understand how SNS works.

AWS SNS and NodeJS

Using SNS with NodeJS is very straightforward, you’ll only need the aws-skd package and you are ready to go! To avoid duplicated code, we can abstract the SNS infrastructure in its own module and implement some of the methods we’ll need.

By having the SDK in hands, initializing the SNS client is very simple:

class MySNS {
    constructor() {
        this.SNS = new AWS.SNS();
    }
}

As I mentioned earlier, we’ll need to register our endpoints using the device token:

async registerEndPoint(deviceToke, applicationARN) {
    const params = {
        Token: deviceToken,
        PlatformApplicationArn: applicationARN
    };

    const { EndpointArn } = await this.SNS.createPlatformEndpoint(params).promise();

    return EndpointArn;
}

These “ARNs” are URI‘s that SNS uses to keep track of Platform Applications, Endpoints, and Topics. You can see the values through the dashboard and they should look like this:

arn:aws:sns:us-east-0:000000000000:app/GCM/MyApplication

The Endpoints ARN will be the same application ARN but followed by an UUID.

I’m returning the EndpointArn to store it in my database. You must keep this value since SNS, and other amazon services, are awful to search for specific registers. Also, use Redis or any other cache to access it since it will be needed often to send notifications.

For sending messages to a specific Endpoint, you’ll need to provide the EndpointArn and the Message object, that you’ll be sent as a string. Make sure that the message object follows your notification service payload pattern, or else it will not work at all. Here’s how to implement it:

publish(endpointARN, message) {
    const params = {
        TargetArn: endpoint,
        MessageStructure: 'json',
        Message: JSON.stringify(message)
    };

    return this.SNS.publish(params).promise();
}

To trigger the Android push notification, your message object should look like this:

{
    "GCM": {
        "notification": {
            "android": {},
            "title": "Notification Title",
            "body": "Notification Body"
        }
    }
}

You can also send more data within this object which it’s used to replace WebSocket when the app is running in the background. In some providers, you can even specify if the device is going to play a specific sound or how it’s going to be displayed. Make sure to read your notification provider documentation to understand what you can or can not do.

What can go wrong?

So far, you’ve got everything right, but the notifications may not be showing up! The main cause of this problem, supposing that your implementation is correct, could be your endpoint being deactivated by SNS. This happens when your notification provider responds with your device token no longer being valid, or if it was unable to deliver notifications multiple times.

Depending on your emulator, the Endpoint deactivation can be completely random, we’ve noticed it more often while using the BlueStack emulator. On the Android Studio emulator, it happened from time to time. On a real device, the problem hasn’t been noticed at all. Even when the Endpoint is not disabled, the notification may not show up on emulators, keep that in mind when testing your application.

An easy way to keep the Endpoint fresh and up to date is to recreate the endpoint on the sign-in process and deleting the current one if there’s any. If you do so, make sure to also remove the Endpoint from a Topic, in case it’s has been subscribed to one. You can also force the Endpoint to be re-enabled before trying to send a direct message to it, take the following code as an example:

enableEndpoint(endpointARN) {
    const params = {
      EndpointArn: endpointARN,
      Attributes: {
        Enabled: 'true'
      }
    };

    return this.SNS.setEndpointAttributes(params).promise();
}

If you’re not already familiar with push notifications, it is worth mentioning that they will only show up if your app is on the background, but, the app will keep receiving the notification data. To render the notification from within the app, you’ll need to implement your own front-end solution.

Conclusion

Despite being very easy to use, I’ve struggled a lot while trying to understand and use SNS, it’s really easy to step on an edge case or face some issue that hasn’t been documented. The main problem of dealing with SNS is that it depends on a lot of other services and debugging it might not be so straightforward. I hope you found this article useful and that it serves you as a good introduction of how to use SNS with NodeJS, as well as making your experience developing with it a lot easier than mine!

References

We are hiring new talents. Do you want to work with us? become@codeminer42.com