TL;DR Use the ussd-router utility to manage USSD routing headaches. Install on npm or view the source code.
Case Study: The headache in building USSD apps
Imagine you are building a USSD application as follows:
Perhaps, you would write code as follows:
import express from 'express';
import bodyParser from 'body-parser';
const app = express();
const port = 3000;
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.post('/webhook/ussd', (req, res) => {
const { body: { text } } = req;
const footer = '\n0: Back 00: Home';
let msg = '';
if (text === '') {
msg += '1: Buy data bundles';
msg += '\n2: Buy calls and sms bundles';
} else if (text === '1') {
msg += '1: Daily bundles';
msg += '\n2: Weekly bundles';
msg += footer;
} else if (text === '1*1') {
msg += '1. Buy for my number';
msg += '\n2. Buy for other number';
msg += footer;
} else if (text === 1*1*1) {
// more logic
}
res.send(msg);
});
app.listen(port, () => {
console.log('Server running...');
});
The important part is in the if-else flow, which allows you to add several screens to the USSD application:
This works flawlessly! But what happens when a user decides to navigate to the previous screen by pressing ‘0’ or to the home screen by pressing ‘00’?
You guessed it. This introduces an unsavory chain of if-else statements:
const footer = '\n0: Back 00: Home';
let msg = '';
if (rawText === '' || rawText === '1*00' || rawText === '1*0' || rawText === '1*1*00') {
msg += '1: Buy data bundles';
msg += '\n2: Buy calls and sms bundles';
} else if (rawText === '1' || rawText === '1*1*0') {
msg += '1: Daily bundles';
msg += '\n2: Weekly bundles';
msg += footer;
} else if (rawText === '1*1' || rawText === '1*1*1*0') {
msg += '1: Buy for my number';
msg += '\n2: Buy for other number';
msg += footer;
}
Ugh. That’s one huge spaghetti of code.
Mind you, I didn’t even explore all the paths a user could take while navigating. In fact, as the user navigates deeper and deeper and decides to navigate to the previous/home screen, it may get too complicated for you to even handle the logic.
The solution
As illustrated, you may decide to handle the routing on your own, but that will add unnecessary boilerplate to your code.
Or you could use the
ussd-router
library.
The ussd-router
library will help you remove the boilerplate needed to handle navigation in your application to the previous/home screen, and let you rest easy as you concentrate on your business logic.
import { ussdRouter } from 'ussd-router';
const text1 = ussdRouter('544*1*2'); // '544*1*2'
const text2 = ussdRouter('544*1*2*00*3'); // '544*1*3'
const text3 = ussdRouter('544*1*2*0*1*2'); // '1*2'
const text4 = ussdRouter('544*1*2*0*1*2*00*3'); // '1*3'
Thus, you can update your code as follows:
import { ussdRouter } from 'ussd-router';
app.post('/webhook/ussd', (req, res) => {
const { body: { text: rawText } } = req;
const text = ussdRouter(rawText);
let msg = '';
if (text === '') {
// do something
} else if (text === '1') {
// do something else
}
});
And you never again have to worry about handling navigation in your USSD application.
What if I want to use a different keyword to go to the home/previous screen?
By default 0
is the keyword used to go to the home screen, while 00
is used to go to the previous screen.
If you want to change this, simply update this as follows:
const text1 = ussdRouter(rawText, '98', '99');
Here, 98
is the keyword that will be used to go to the home screen, while 99
will be used to go to the previous screen.
Getting the library
If you use node.js, you can install the npm package as follows:
npm i ussd-router
If you don’t use node.js, you can view the source code, and transpile the algorithm into the programming language of your choice.
Cheers!
Top comments (8)
Hi ! How can use ussd-router with python ussd application ?
Is it possible ?
Hi! Not directly. You will need to rewrite the code from Typescript to Python. The good news is that it's just 35 lines of code.
Here's the source: github.com/tawn33y/ussd-router/blo...
Let me know if you face any issues.
Cheers!
Hi ! Thanks a lot. I have encoded the lines below and it's work perfectly :
coding: utf-8
def goBack(str, keyword='00'):
strArray = str.split('*')
newStrArray = []
for i in range(len(strArray)):
return "*".join(newStrArray)
def goToHome(str, keyword='0'):
strArray = str.split('*')
newStr = str
for i in reversed(range(len(strArray))):
if strArray[i] == keyword:
newStr = "*".join(strArray[i+1:])
break
return newStr
def ussdRouter(str, goToHomeKeyword='0', goBackKeyword='00'):
return goBack(goToHome(str, goToHomeKeyword), goBackKeyword)
This is great!! 🙌🏽
Thanks for sharing! When you get a minute, feel free to create a python package for the same, and I can add a hyperlink pointer to this in the js package for future people who would like a python version
github.com/ditsarl/ussdrouter.git
Awesome! 🙌🏽
Very helpful.
There is a very comprehensive course on USSD and SMS featuring the Africa's Talking #USSD gateway. skillsday.co/courses/building-and-...
This course also implements a simple PHP router function, which achieves a similar result.
How can this be achieved with a USSD gateway that does not append each new request with a '*' ?