We use cookies and other tracking technologies to improve your browsing experience on our site, analyze site traffic, and understand where our audience is coming from. To find out more, please read our privacy policy.

By choosing 'I Accept', you consent to our use of cookies and other tracking technologies.

We use cookies and other tracking technologies to improve your browsing experience on our site, analyze site traffic, and understand where our audience is coming from. To find out more, please read our privacy policy.

By choosing 'I Accept', you consent to our use of cookies and other tracking technologies. Less

We use cookies and other tracking technologies... More

Login or register
to publish this job!

Login or register
to save this job!

Login or register
to save interesting jobs!

Login or register
to get access to all your job applications!

Login or register to start contributing with an article!

Login or register
to see more jobs from this company!

Login or register
to boost this post!

Show some love to the author of this blog by giving their post some rocket fuel 🚀.

Login or register to search for your ideal job!

Login or register to start working on this issue!

Login or register
to save articles!

Login to see the application

Engineers who find a new job through WorksHub average a 15% increase in salary 🚀

You will be redirected back to this page right after signin

Blog hero image

Creating a USSD application with NodeJS and Redis [Part 1]

Moses Odhiambo 14 June, 2021 | 4 min read

Building USSD applications in NodeJS may seem straightforward and even a library away from getting everything up and running. After building several USSD applications with different libraries and not getting what I wanted, I came up with a custom solution. Hopefully, this can be helpful to you.

Several considerations need to be made when building an effective USSD solution. They include:

  1. Menu Management — Manage how each screen is presented to the user and ensure dynamic menu builds.
  2. Session Management — Manage how information is passed across different menus as the user traverses the application.
  3. Dynamic Configuration — USSD applications should have multi-language support, support for different Mobile Network Operators(MNOs) requirements and should be highly customizable.

Lets build the solution

In this article we will build a USSD app with NodeJS and Redis. Redis is an open source in-memory data structure store, it will be used for session management.

Project Requirements:

Install NodeJS  
Install typescript globally **npm install -g typescript** and **npm install -g ts-node  
**[Install a Redis server](https://redis.io/download)

Let’s set up the project:

mkdir ussd-project  
cd ussd-project   
npm init -y  
tsc --init

Update tsconfig.json file with the following

{
  "compilerOptions": {
        "module": "commonjs",
        "resolveJsonModule": true,
        "esModuleInterop": true,
        "target": "es6",
        "noImplicitAny": false,
        "sourceMap": false,
        "outDir": "build"
  },
  "exclude": [
      "node_modules",
      "**/*.spec.ts",
      "**/*.test.ts",
      "./src/**/__tests__/*.ts"
  ],
  "include": [
      "src/**/*.ts"]
}

Install the following packages on the project:

npm i express nodemon redis  
npm i [@types/express](http://twitter.com/types/express) [@types/node](http://twitter.com/types/node) [@types/redis](http://twitter.com/types/redis) -D

Add nodemon.json file on the project base

{
    "restartable": "rs",
    "ignore": [".git", "node_modules/", "build/", "coverage/"],
    "watch": ["src/"],
    "env": {
      "NODE_ENV": "development"
    },
    "ext": "js,json,ts"
  }

Update scripts on your package.json folder as shown:

"scripts": {  
"start": "ts-node src/app.ts",  
"live": "nodemon --config nodemon.json src/app.ts"  
}

Create this folder structure for the project:

ussd-project  
└───scr  
│   └───menu-builder  
│   │    └───configs  
│   │    └───core  
│   │    └───lang  
│   │    └───menus  
│   │    └───states  
│   │    │   └───controllers  
│   │    └───typings  
│   │    └───index.ts  
│   └───app.ts  
└───node\_modules  
└───nodemon.json  
└───package.json  
└───package-lock.json  
└───tsconfig.json

Menu builder contains the following folders:

  • configs folder — Sets the base configurations for the project
  • core folder — Manage project input and session handling.
  • lang folder — Manage different menu languages.
  • menus folder — Manage creation of menus.
  • states folder — Manage menu states.
  • typings folder — Manage menu types (TypeScript)

Create the http server

Lets create a http server with express JS. Add a route to accept USSD requests and call the menu builder function. The menu builder function accepts the request body and a redis client as parameters.

import express from 'express';
import redis from 'redis';
import ussdMenuBuilder from './menu-builder'

const app: express.Application = express();
app.disable('etag').disable('x-powered-by');
app.use(express.json());
app.use(express.urlencoded({ extended: true }));


// CONNECT TO REDIS SERVER
const redisClient = redis.createClient({
    host: "localhost",
    // password: "pass123",
    port: 6379
})

redisClient.on('connect', () => {
    console.log('Connected to redis server');
})

redisClient.on('error', (err) => {
    console.log('Redis connection error', err);
})

// USSD ROUTE
app.post('/ussd', async (req, res) => {
    let menu_res;
    try{
      // RUN THE MENU BUILDER
      // PASS REQ BODY AND REDIS CLIENT
        menu_res = await ussdMenuBuilder(req.body, redisClient);
    } catch(e){
        console.log("MENU ERROR");
        return res.send(e)
        
    }
    res.send(menu_res);
});


const port = 4000;
app.listen(port, () => console.log(`Server listening at port ${port}`));

Create the menu builder configuration file

Project has a set of base configurations:

  • session_prefix — This unique identifier that is used to create sessions
  • default_lang — Default language used in the project
  • session_time — Lifetime of the session menu in seconds
  • start_state —The 1st state that runs
  • sequential_requests — Set whether the project should allow user to run sequential queries eg. *144*1*3*6#. It’s important since some MNOs do not allow sequential queries.
    export default {
        session_prefix: "keapp:",
        default_lang: "en", // ENSURE NAME MATCHES LANGUAGE CONFIG NAME
        session_time: 180,
        start_state: 'start_state',
        sequential_requests: false,
    }
    
    src/menu-builder/configs/index.ts

Create the language config

Create an English language file and add the following generic properties:

export default {
  generic: {
    fatal_error: "An error occurred executing your request, please try again later.",
    deny_sequential_requests: "Sequential requests eg: *1*2*3 are not allowed",
    input_violation: "Input pattern is not supported.",
    bad_input: "Invalid input\n",
  }
}

src/menu-builder/lang/en.ts

Create a file to manage all language options:

import en from './en'

export default{
    en: en
}

src/menu-builder/lang/index.ts

Join our newsletter
Join over 111,000 others and get access to exclusive content, job opportunities and more!

Create the menu builder types

Add TypeScript interface for the incoming request body.

export interface RequestBody{
    phoneNumber: string,
    serviceCode: string,
    text: string,
    sessionId: string
}

src/menu-builder/typings/global.ts

Create the menu builder main file

With all base configurations set let us create the menu builder file. This is the entry point of our application.

import {RedisClient} from 'redis'
import {RequestBody} from './typings/global'
import languages from './lang'
import configs from './configs'

export default function(args: RequestBody, redis: RedisClient){
  return new Promise(async(resolve, reject) => {
     try{
       
       // BUILD INPUT VARIABLE
        let buildInput = {
            current_input: args.text,
            full_input: args.text,
            masked_input: args.text,
            active_state: configs.start_state,
            sid: configs.session_prefix+args.sessionId,
            language: configs.default_lang,
            phone: args.phoneNumber,
            hash: ""
        }
        
        resolve("CON Welcome to the USSD Redis App")
        return
       
     }catch(e) {
       // SOMETHING WENT REALLY WRONG
        reject("END " + languages[configs.default_lang].generic.fatal_error )
        return
     }
    
  });
}

src/menu-builder/index.ts

Run the Project

Run npm run start. Lets send a POST request to our server “http://localhost:4000/ussd”. You will get a response from the menu builder as shown below:

Wrapping Up

That wraps up the first session of building the USSD application. Stay tuned for the rest of the articles.

Have fun and boost the article if you liked it 👍

Originally published on moses-odhiambo-dev.medium.com

Author's avatar
Moses Odhiambo
A Software Engineer based in Nairobi, Kenya. I am on a mission to discover and build technology that can shape the future of society.

Related Issues

open-editions / corpus-joyce-ulysses-tei
open-editions / corpus-joyce-ulysses-tei
  • Started
  • 0
  • 1
  • Intermediate
  • HTML
open-editions / corpus-joyce-ulysses-tei
open-editions / corpus-joyce-ulysses-tei
  • Started
  • 0
  • 2
  • Intermediate
  • HTML
open-editions / corpus-joyce-ulysses-tei
open-editions / corpus-joyce-ulysses-tei
  • Open
  • 0
  • 0
  • Intermediate
  • HTML
open-editions / corpus-joyce-ulysses-tei
open-editions / corpus-joyce-ulysses-tei
  • Open
  • 0
  • 0
  • Intermediate
  • HTML

Get hired!

Sign up now and apply for roles at companies that interest you.

Engineers who find a new job through WorksHub average a 15% increase in salary.

Start with GitHubStart with Stack OverflowStart with Email