All Articles

Building a Two-way SMS Application using Express and Africastalking API

This article was originally published on Africastalking’s Blog

Introduction

It is not uncommon today to interact with services that are triggered by SMS responses from a mobile phone. Sometimes the level of customization and swiftness with which we get these responses may cause us to imagine that someone is on the other end typing back at us. This is hardly ever the case.

In this article we will be building a similar service. An application that gives a predefined response from the server when we send messages to a unique code.

We would be making use of Express, a minimalistic Node JS framework and the Africastalking API. It will work as shown below:

Prerequisites

This article is designed to be very basic and understandable with a basic knowledge of things. However, in order to follow along seamlessly, you should have the following:

  • A good understanding of Javascript
  • Beginner/ Intermediate level understanding of Node & Express
  • Some level of familiarity with cloud-hosting services like Heroku

Requirements

The basic setup required for this project is outlined below:

  • An IDE of your choice like Visual Studio Code.
  • Node JS and Npm installed on your computer. (Download and Install here)
  • A heroku account
  • Git installed on your computer
  • An africastalking account, an API key generated via the sandbox app and a unique short code for your application.

How to generate an API key and short code on Africastalking

Basically Africastalking gives you access to telecommunication APIs as a web service. SMS is one of such services that are readily available via this platform. However we would be needing an API key to authenticate our connection from our application to the API.

Generating the API key is quite an easy process. Log into your account or create one here. You should see the below dashboard after successful login.

Click on go to sandbox app. On the dashboard, click on ‘settings’, then API KEY from the drop-down.

Generate an API key after entering your login credentials for verification and save the generated key to a secure location for future reference.

Next, click on SMS and from the drop-down select Shortcodes and then Create shortcode. You should have a screen like the one below. Insert your selected unique short code for your application and click on submit.

Woohoo!!! We have our API key and our unique short code. Let’s get started.

Project Setup

Without wasting much time let us setup our server and have it listen for requests. From your terminal (Command Line for Windows) simply navigate into the directory where you want to setup your project and run the command:

  $ npm install express-generator -g

This command will install the express generator tool which we would use in creating the skeleton of our application. The -g flag ensures that the package is installed globally (that is on your system) rather than being saved to the project only. When you’re done with this, run the following commands:

    $ express two-way-sms
    $ cd two-way-sms
    $ npm install

This will generate our basic project structure, switch into the project directory and install the necessary packages for a basic Express project. Now we have the basic project setup, its time for some actual code.

Setting up the Server

Now our application skeleton has been successfully created. We will go ahead to clean up the files and folders not needed for this tutorial and create the ones we need. The clean up is pretty simple, just delete the users.js file within the routes folder.

Now open the project in your favorite IDE. In the project’s root folder, open the file named app.js and modify it as shown below or completely replace it’s content with the following code.

    // Import installed packages
    var createError = require('http-errors');
    var express = require('express');
    var path = require('path');
    var cookieParser = require('cookie-parser');
    var logger = require('morgan');
    const bodyParser = require('body-parser');
    
    // import environmental variables from our variables.env file
    require('dotenv').config({ path: 'variables.env' });
    
    var indexRouter = require('./routes/index');
    var smsRouter = require('./routes/sms');
    var app = express();
    
    // view engine setup
    app.set('views', path.join(__dirname, 'views'));
    app.set('view engine', 'jade');
    app.use(logger('dev'));
    app.use(express.json());
    app.use(express.urlencoded({ extended: false }));
    app.use(cookieParser());
    app.use(express.static(path.join(__dirname, 'public')));
    app.use('/', indexRouter);
    app.use('/sms', smsRouter);
    
    //Handle get to /sms
    app.use(function(req, res, next) {
      res.end('This is the sms endpoint')
    });
    // catch 404 and forward to error handler
    app.use(function(req, res, next) {
      next(createError(404));
    });
    // error handler
    app.use(function(err, req, res, next) {
      // set locals, only providing error in development
      res.locals.message = err.message;
      res.locals.error = req.app.get('env') === 'development' ? err : {};
      // render the error page
      res.status(err.status || 500);
      res.render('error');
    });
    app.set('port', process.env.PORT || 8080);
    const server = app.listen(app.get('port'), () => {
      console.log(`Express running → PORT ${server.address().port}`);
    });

Wheeew!!! I bet that just threw someone off balance!

In the chunk of code above, we basically imported the relevant packages which we had installed into the project using Javascript’s require statements. Next, we configured the view engine, setup morgan to log our errors meaningfully and setup some basic Express functionality. Finally, we set our application to listen for requests on port 8080.

See! It’s not a a big deal. Now lets proceed.

If you’ve tried to start up our server yet, you’d notice that we are not quite there. Inside of the routes folder, go ahead and create a file named sms.js . This file would contain the logic that’d handle requests to the /sms route of our application. One more thing and our server would be up and running. We will install nodemon to ensure that our server automatically restarts when our files change and we’ll edit our start script correspondingly. In the terminal and inside the project directory, run the command:

    npm install nodemon --save

Next, open your package.json file and edit the scripts as shown below.

    {
      "name": "two-way-sms",
      "version": "0.0.0",
      "private": true,
      "scripts": {
        "start": "node ./app.js",
        "prod": "node ./app.js",
        "watch": "nodemon ./app.js"
      },
      "dependencies": {
        "cookie-parser": "~1.4.3",
        "debug": "~2.6.9",
        "express": "~4.16.0",
        "http-errors": "~1.6.2",
        "jade": "~1.11.0",
        "morgan": "~1.9.0"
      }
    }

All set. Open the project directory in your terminal and run the command:

    npm run watch

You should see an output on your console that says "``Express running → PORT 8080``". Great job!

Handling SMS Requests

Recall that our application is going to receive an SMS request and respond with a predefined message. To do this, we would handle all POST and GET requests to our /sms route inside the sms.js file we created. You should have something like this:

    var express = require('express');
    var router = express.Router();
    var sms = require('../controllers/smsController')
    
    /* POST users listing. */
    router.post('/', sms.received);
    router.get('/', function(req, res, next) {
      res.render('index', { title: 'This is the SMS handling endpoint' });
    });
    module.exports = router;

At this point your server should be showing some pretty discomforting errors via the console. Notice how we require sms on the third line from a folder and file that doesnt exist yet? And then try to call a received function from it on receiving a POST request. Now let’s fix that.

First, we would install africastalking Node package via npm. We will use this to setup our major application logic next. Run the following command from terminal:

    npm install africastalking --save

Next, we would create another folder called controllers in the project root directory, and inside of it we would create a file named smsController.js . Inside of this file we will create and export a function that will handle each POST request to this route by authenticating our application and sending a corresponding response for each request. Now let’s do just that.

    // Define application constants
    const message = 'I am a fisherman. I sleep all day and work all night!'
    // Your login credentials
    const shortCode = 'insert your shortcode here'
    const username = 'sandbox'
    const apikey = 'insert your apikey here'
    const options = {
      apiKey: apikey,
      username: username
    }
    const AfricasTalking = require('africastalking')(options)
    const sms = AfricasTalking.SMS
    
    exports.received = (req, res) => {
      // select needed properties from post object
      var body = ...req.body;
      // Respond to message if from appropriate shortcode
      if (body.to == '41919') {
        sendResponse(body.from, message)
      } else {
        console.log('Something is wrong with the incoming message')
      }
    }
    function sendResponse (recipient, message) {
      var opts = {
        from: shortCode,
        to: recipient,
        message: message
      }
      sms.send(opts).then(
        console.log('Message sent successfully')
      ).catch(
        console.log('Something went wrong with message sending')
      )
    }

Notice that we passed the request and response objects to the received() function. When a person sends a message, the details of that message such as the senders number, the number it was sent to, the content of the message and more are received in the request object. Hence we manipulate that to retrieve the sender’s phone number and send back a response to the user via africastalking API.

Make sure to insert your own short *code and generated API key in the respective variables in the snippet above.***

Now we have successfully setup our application and it is ready for testing. For this there are two options;

  • Use ngrok
  • Deploy to heroku

In this article we would explore both methods.

Testing via Ngrok

Ngrok basically allows public URLs for demoing from your own machine. This means we get a public URL through which we can expose our application and route requests and responses.

First, download and install ngrok following the instructions found here.

Once you have ngrok set up on your system successfully, navigate to the folder where you have it installed and run the following command from the terminal:

    ./ngrok http 8080

We are using 8080 because that’s the port on which we are running our application. Ensure you have a reliable internet connection while you do this. If done successfully you should have some information displaying on your terminal as shown below.

The most important to us is the fowarding url. This is the URL via which we can access our application on the web. Copy this URL and proceed to the section on configuring your application’s callback URL.

Deploying to Heroku

Our deployment process is pretty straight forward. First we would edit our package.json so that heroku understands and serves our application appropriately.

Update your package.json file as shown below specifying the engines to be used.

    {
      "name": "two-way-sms",
      "version": "0.0.0",
      "private": true,
      "engines": {
        "node": "8.11.1",
        "npm": "5.0.3"
      },
      "scripts": {
        "start": "node ./app.js",
        "prod": "node ./app.js",
        "watch": "nodemon ./app.js"
      },
      "dependencies": {
        "africastalking": "^0.3.2",
        "cookie-parser": "~1.4.3",
        "debug": "~2.6.9",
        "dotenv": "^6.0.0",
        "express": "~4.16.0",
        "http-errors": "~1.6.2",
        "jade": "~1.11.0",
        "morgan": "~1.9.0",
        "nodemon": "^1.17.5"
      }
    }

Next we’d setup git and create a .gitignore file. It’s content will be simply as shown below:

    $ git init

This command will create a github repository for the project. Then update the .gitignore file to:

    node_modules

This simply excludes the large packages we installed from being uploaded to the server as heroku automatically installs these for us there using our package.json file.

Next, login to your heroku dashboard. If you do not have an account already, you could create one here. Your dashboard should look like this:

Proceed to create a new app via the button on the top right corner. Name your application, choose a region nearest to you and create the application. Next, you’d be redirected to an instruction screen like the one below on how to deploy your application.

Follow the instruction and deploy your application. Now you should have a working application deployed to heroku. Now we are almost done.

Configuring your Application’s callback URL

All that’s left now is to configure your Africastalking sandbox to work with your deployed heroku application. On your dashboard, click on SMS, select the SMS Callback URLs option and select Incoming Messages.

In the field provided, enter the URl for your hosted application and append the “/sms” route to it. Click on submit and we are all set and done.

Proceed to the africastalking simulator here to test your application using the unique short code you had selected earlier.

Conclusion

In building for the #NextBillionUsers, we must take into cognizance their needs and constraints. Good internet connection is still quite a major challenge here in Africa, however, with Africastalking’s API, developers now have the opportunity to integrate functionalities that are initiated and traversed via SMS into our web applications with ease. Thus, reaching a larger multitude.

Feel free to experiment extensively with the API using the docs here. And share your ideas and questions in the comment section below and on twitter @Africa’s Talking Ltd or with me @worldclassdev.