When a SMS is sent to the Twilio Number, information about the SMS is sent to our Node.js server.

Then, we extract the relevant information and publish it to a Fanout Cloud's channel. The channel information is received in a web page that shows the information in this way:

Notice how the background changes depending on the sentiment. Moreover, there are transitions when new messages appear. The design was inspired by this pen.

The gauge comes from Epoch, a real-time charting library that uses jQuery. Some would say React and jQuery should never be used together (because of the way React creates its components). We could have chosen another gauge component with better React integration, but React can play well with libraries like jQuery. Sometimes, you have no option but to use a jQuery plugin in a React application. Not just that, Epoch charts look better than others.

Finally, with a couple of modifications, we'll make this application isomorphic, or universal.

The source code of the final version of the application is available on Github.

Let's start by setting up the required components for our application.

The Marchex Sentiment Analysis add-on takes an SMS message and computes a sentiment score between 0.0 and 1.0, where 0.0 is most negative sentiment and 1.0 is the most positive sentiment:

Press the Install button and agree to the terms of the service. You'll see the following screen as confirmation:

Check the Use In Incoming SMS Message option and press the Save button.

Finally, go to your console and copy your Auth Token, you may need it later:

Ngrok

When an SMS is sent to our Twilio number, a webhook will be triggered (think of it as a callback). This means an HTTP request will be made to our server, so we'll either need to deploy our application on the cloud or keep it locally and use a service like ngrok.

Ngrok proxies external requests to your local machine by creating a secure tunnel and giving you a public URL.

It is a Go program, distributed as a single executable file (with no additional dependencies). So for now, just download it from https://ngrok.com/download and unzip the compressed file.

This will define the /sms POST route and the Twilio.webhook function, which acts as a Express middleware that determines if the request was sent by Twilio. This webhook also makes the Express response object aware of TwimlResponse objects.

However, the config.twilio object that we specify automatically defines the validate option as false, which disables this validation. If the validation is enabled (you'll need to enable it if you don't want to receive requests from anyone), this function will look to the environment variable TWILIO_AUTH_TOKEN for your Twilio auth token to validate the request.

When Twilio sends an HTTP request to your server, it includes a value in the header that is signed with your auth token. So, if you enable this option, make sure to export this variable before running the server. On Linux, for example, do it this way:

1
exportTWILIO_AUTH_TOKEN=xxx0xxx00xx0xxxxxxx0xxxx0xxxx00xxx0

Moving on, when an SMS is sent to your Twilio number, your server will get an object like the following:

The application will use Fanout's publish/subscribe service to get the SMS information in real-time. This will be done with Faye, a Bayeux-compatible client library.

Why use Fanout Cloud when we can do the same with a simple WebSocket library like Socket.IO? Well, you might not need to use WebSockets. Also, by using Fanout's infrastructure, you don't have to worry about neither scalability nor additional server to manage.

Fanout is organized by realms and channels. A realm can contain any number of channels and different realms may use the same channel names without any problem. Messages are published to channels, and messages are relayed to the subscribers of each channel for that realm.

When you create a Fanout account, one realm will be automatically created for you. In contrast, channels are created on demand at any time.

To send the object with the SMS information, we'll use the Node.js Fanout library.

At the beginning of the server.js file, import the Fanout module:

1
var Fanout =require("fanoutpub");

Before the definition of the /sms route, initialize the Fanout object passing your Realm ID and Realm Key in this way:

As said before, we'll be using the Epoch library, so here we're just defining a custom style (epoch-my-gauge-theme) for the gauge along with styles for the SMS messages.

Back to the HTML file, we're also adding:

The Epoch CSS file (epoch.min.css)

The element where the React elements will be injected (<div id="root"></div>)

The required JS files needed by Epoch, jQuery, and the D3 visualization library, required by the first one (although the lastest version of this library at the time of this writing is 4.1.1, Epoch requires version 3.X.X).

The bundle.js file built by Webpack.

The src directory will store the JavaScript code of our application. Inside it, we're going to structure the application in the following way:

messages: the array that will store the objects (with the SMS information) received via Fanout.

background: the style to show the gradient background that will change depending on the sentiment of the latest message.

sentiment: the sentiment value of the latest message.

According to the React Component Lifecycle Specification, componentDidMount() is executed once, only on the client, not on the server (remember this point when we make our application isomorphic), and it's the method to use to integrate other JavaScript frameworks, or send AJAX requests.

So let's subscribe to the Fanout channel in the componentDidMount() method (notice the / character to refer to the channel):

When a message arrives, the updateMessages function is executed. Notice how the sentiment is used to calculate the percentage of the gradient for each color (I'm sure there are better algorithms to achieve it, but this does the job), and how the new message is prepended to the existing array of messages.

Notice how the div element, in which the component is rendered, is referenced with ref and this.refs. You may have seen other tutorials get the DOM element of a component by using either the ReactDOM.getDOMNode() or the ReactDOM.findDOMNode() functions. However, after React 0.14, this.refs is the recommended way to access the DOM. Remember that React works with a Virtual DOM while jQuery works with the real DOM.

We saved a reference to the Epoch gauge component (this.gauge), so when the sentiment property is updated, the gauge can be updated too (in the componentWillReceiveProps function).

First, React requires every message component in a collection to have a unique identifier defined by the key property. This helps React determine when elements are added or removed.

For example, s new elements are prepended instead of appended, we can't give the first element the index 0 as key, since this will only work the first time an element is added. In fact, for the elements added next in line, there will be an element with key 0 already. Therefore, keys are assigned this way:

1
const key =this.props.messages.length - index;

The second thing is that we use the ReactCSSTransitionGroup add-on component to animate the insertion of a new SMS message on the page. We can do the same thing by using plain CSS only, but let's figure out how to do it the React way.

First install this module with NPM:

1
npm install --save react-addons-css-transition-group

ReactCSSTransitionGroup wraps the elements that you want to animate. By default, it renders a span to wrap them, but since we're going to work with li elements, we specify the wrapper tag ul with the component property. className becomes a property of the rendered component, as any other property that doesn't belong to ReactCSSTransitionGroup.

transitionName is the prefix used to identify the CSS classes to perform the animation. Based on this, add the following CSS classes to public/css/style.css:

Now if we run the application using npm start, Webpack will bundle all the client files and you should see this page in the browser:

You can play with the application either by sending SMS messages to your Twilio number or by replaying the request with Ngrok. If you're trying the latter option, make sure that you have the webhook validation disabled. If you go to your Fanout Control Panel and then click on the Stats button, you'll see the following information:

Isomorphic React

We now have a fully functional application, but why stop here? Let's turn this application into an isomorphic one.

Isomorphic (or universal) is a term that means that the same JavaScript code can run on the client and server without modification, so the server can generate the page and serve it as plain HTML.

In essence, server-rendering is a simple concept achieved with only one function call on Node.js:

1
const appHTML =renderToString(<App />);

However, Node.js doesn't know about JSX (the syntax used by React; <App>), so what we can do is to use Webpack to build a server bundle, just like the client bundle.

This file tells Webpack to take server.js as the entry point to generate the server.bundle.js file with all its dependencies bundled together.

The target: 'node' option tells webpack not to touch any Node.js built-in modules. However, Webpack will load modules from the node_modules directory and bundle them too. To avoid this, we use the externals option. A module listed as an external won't be bundled. For more on externals, see this page.

Unfortunately, using externals assumes a browser environment, so something like require('twilio') will be turned into the global variable twilio. To keep our require statements, we need to create an object with a key/value of each module name and to prefix the value with commonjs.

Next, options are passed to node so __filename and __dirname work as expected.

Open server.js and import the React modules that we'll use (thanks to Webpack and Babel, we can now use import instead of require):

Notice that we're using src/components/index.js instead of src/app.js to render the app on the server side. The reason is that src/app.js references the DOM (Document Object Model), which is a browser concept that doesn't exist in the server.

Likewise, since componentDidMount can contain references to the DOM, it won't be executed on the server side. But don't worry, when the React app is loaded in the client (remember that the entry point in the client is still src/app.js), this function will be executed.

Also, modify /views/index.ejs so it can render the generated HTML:

1
2
3
...
<divid="root"><%- appHtml %></div>
...

In EJS, the <%- tag outputs the unescaped value of the object into the template (in contrast to the more commonly used <%=).

Make sure that you don't leave any space between the opening and closing div tag, otherwise, React will complain about the blank space.

Finally, we have to modify the start script from package.json to generate the server bundle every time the server is started. Let's organize our scripts in this way:

Conclusion

We have created a single page application with React that gets SMS information with the help of Twilio and Ngrok and shows it in real-time using Fanout Cloud. We also made it isomorphic with little modifications. Combining the right APIs, you can get simple yet powerful applications.

Remember that the code is on Github. Thanks for reading. Please leave all comments and feedback in the discussion section below. Pleasa favorite this tutorial if you found it informative!