We're planting a tree for every job application! Click here to learn more
WORKSHUB

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

Moses Odhiambo

14 Jun 2021

4 min read

Creating a USSD application with NodeJS and Redis [Part 1]
  • Redis
  • JavaScript
  • Node.js

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

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 👍

Did you like this article?

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.

See other articles by Moses

Related jobs

Title

The company

title

Remote

Title

The company

title

Remote

Title

The company

title

Remote

Title

The company

title

Remote

Related articles

title

title

title

title

CareersCompaniesSitemapFunctional WorksBlockchain WorksJavaScript WorksAI WorksGolang WorksJava WorksPython WorksRemote Works
email iconhello@works-hub.comUK flag

Ground Floor, Verse Building, 18 Brunswick Place, London, N1 6DZ

US flag

108 E 16th Street, New York, NY 10003

Subscribe to our newsletter

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

© 2021 WorksHub

Privacy PolicyDeveloped by WorksHub