PubSub with AWS IoT Core and React Native

Lightweight pub/sub implementation using AWS IoT Core as the communication layer (real-time messaging) between backend and a React Native frontend.

Motivation

A difficult time was had when searching for a lightweight solution to facilitate backend-frontend communication following a pubsub pattern using AWS services.

An approach via SNS/SQS/EventBridge + Lambda + DDB + API Gateway was considered, but unfortunately, factors such as the added setup time and the API Gateway soft limitations (postToConnection 10k RPS), were detrimental to its pick.

Luckily, this article was available and shed light into an implementation via the IoT family of services.

Next, this article put forward a sensible architecture, with the entire process explained, as well as providing the respective serverless demo and repository.

Thus, the IoT Core pick arose, allowing us to meet the following requirements:

  • Minimal setup and maintenance (self managed)
  • Scalable
  • Backend data publish
  • Frontend data subscription

The frontend SDK responsible for managing the WSS connection was a plus, but not a necessity.

Wrapped by IoT Core, we’ll have at our disposal a solution laying on:

  • MQTT message broker
  • WSS protocol

In this guide we won’t use MQTT as a protocol, given the necessity of a X.509 client certificate for the authentication step, in detriment of our preferred and more practical authentication method, Signature Version 4.

Signature Version 4 allows authentication via persistent security credentials associated with an IAM User or temporary security credentials provided by STS.

IoT Core client authentication

In the mobile development context, per AWS, the recommended approach would be the to use Cognito identities.

Typically, AWS IoT devices use X.509 certificates, while mobile applications use Amazon Cognito identities. Web and desktop applications use IAM or federated identities. AWS CLI commands use IAM.

Nonetheless, given the possibility of custom configurable IoT endpoints in the near future, we would prefer a future-proof approach capable of passing both the required AWS credentials for client authentication, as well as the current IoT endpoint, together in the same response.

A sensible solution that would allow us to provision the required data to establish the frontend IoT connection is entirely explained in the supramentioned article (involving a fetch from an API Gateway endpoint, that obtains the account’s IoT Core endpoint and issues an STS token from an associated IAM Role, through a Lambda function).

The same implementation, using AWS Serverless Application Model instead of serverless, can be found here.

Still, without ignoring AWS Security Credentials reference recommendations, if the objective is to quickly test the implementation, we can keep it simple by creating a specific IAM User and store the respective access key, secret key and known IoT Core endpoint client side. Afterwards, we can proceed with the forward-looking implementation, when ready to put forward a solution to staging/production.

That can be done with the following steps:

  1. Open the IAM service in the AWS web dashboard
  2. In the sidebar, under Access management, press Users
  3. Press the Add User
  4. Type the preferred User name
  5. Select Programatic access in the Access type option
  6. Press Next: Permissions
  7. Press Attach existing policies directly under Set Permissions
  8. Type AWSIoTDataAccess in the search box and select the policy
  9. Proceed through the next pages until the end where you’ll be provided with the required access key and secret key associated with the newly created IAM User.

Additionally, we need to “manually” fetch the IoT endpoint associated with the AWS account.

  1. Open the IoT Core service in the AWS web dashboard
  2. In the sidebar, press Test, followed by MQTT test client
  3. Wait until AWS finishes creating the endpoint (you should refresh the page if the state remains unchaged for a while)
  4. Press Connect as iotconsole-xxxxxxxxxx, followed by View endpoint

The AWS region, IAM User access and secret keys, as well as the IoT Core endpoint will all be used to establish the WSS connection client side, later on.

React Native dependencies

In frontend, the WSS connection will be wrapped by the aws-iot-device-sdk package.

The aws-iot-device-sdk.js package allows developers to write JavaScript applications which access the AWS IoT Platform via MQTT or MQTT over the Secure WebSocket Protocol. It can be used in Node.js environments as well as in browser applications.

Since React Native doesn’t run on Node.js, we’ll be required to follow additional steps.

First, we install the required AWS frontend SDK.

yarn add aws-iot-device-sdk

Next, we add the following package that we’ll help us fixing the missing core dependencies used by aws-iot-device-sdk.

yarn add rn-nodeify

Then, we run the actual rn-nodeify install script to add the missing core dependencies.

npx rn-nodeify --yarn --install “fs,util,path,tls,stream,buffer,global,process” --hack

Next, we import the generated shim to the project root index file (ExampleProject/index.js).

import ‘./shim’;

Lastly, we add the previsously mentioned command as a package.json postinstall script, so it runs after every dependency install.

“postinstall”: “rn-nodeify --yard --install fs,util,path,tls,stream,buffer,global,process --hack”

Code example and testing

The setup is past us. Now’s the time to test the implementation with some boilerplate code.

After replacing region, host, accesskey and secretKey, head to the AWS once again.

  1. Open the IoT Core service in the AWS web dashboard
  2. In the sidebar, press Test, followed by MQTT test client
  3. Under the Subscribe section, type your topic in Subscription topic (using our example code, “example-topic”)
  4. Press Subscribe to topic
  5. Under the Publish section, type the same topic
  6. Press Publish to topic to send the example message

By now, we should have received the message in our running RN project, through the message listener.

Otherwise, we also subscribed to the topic through the AWS dashboard, so remember to use that tool in your troubleshooting process.

Pricing

AWS IoT core is a service geared towards IoT usage, and as such, non-obvious charges are mentioned in the pricing section.

Nonetheless, Device Shadow & Registry and Rules Engine charges do not apply to us, due to our use case not interacting with that feature set.

As such, only Connectivity and Messaging charges enter our calculations. Using the US East (Ohio) region as an example, we have:

Connectivity pricing: $0.08 (per million minutes of connection)

MQTT and HTTP messaging pricing:

  • Up to 1 billion messages: $1.00 (per million messages)
  • Next 4 billion messages: $0.80 (per million messages)
  • Over 5 billion messages: $0.70 (per million messages)

Final considerations

This article doesn’t mention the backend publish segment of the process, since that part is entirely dependant on each user stack.

Some might need to publish messages directly from their Django backend using the Boto3 library, others might go with a Lambda function, behind some specific trigger, running on Node.js while using the aws-sdk package.

At the moment, configurable domains are in a beta stage, thus only being available in the US East (N. Virginia) region. Others have to stick with the single non-configurable endpoint per AWS account.

Bibliography

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store