Building a Ghana Digital Address Route Finder

I recently set out to build a prototype of an idea/question that occurred to me: ‘What if we could search for locations using Ghana’s digital addresses just like we do for locations we know?’

Admittedly, this seemed like a pretty wild idea at first because, while the digital addressing system was an interesting innovation, there were a couple of issues to address and questions to answer like:

  • Does the regular individual actually know or use their digital addresses?
  • Even if people did know their addresses, what was the incentive to use it instead of a location name that was easier to remember?
  • How good are the addresses at actually pinpointing specific locations? This was the even more interesting question to me because the addressing system in Ghana (and Africa in general) still leaves a lot to be desired. As advanced as Google Maps is, it still cannot locate many addresses here in Ghana.

The major use case for this that I could think of was for shipping and logistics purposes, and not really for a regular user. Regardless of these issues, I decided to try my hands on the project, and the result was interesting. Read on to find out more.

As an aside, I will add that part of the inspiration for this project came from a project another person did, which was to recreate the addressing system itself. Pretty stellar work I’d say. Check it out: Recreating Ghana’s Digital Address System.


Step 1

The first step in building this project was to decide on the tools I wanted to use for it. I had been deepening my knowledge of Go, so I thought it would be cool to build this project with it. However, I decided to use Python and Flask since I was already very familiar with them, and it’d enable me to prototype very quickly.

After this, I thought of what to use for the frontend. I don’t consider myself much of a frontend person, but I knew that if I wanted people to test this out, they’d need an interface. I settled with Bootstrap for this because I was also pretty familiar with it. Here, I also needed to determine the page workflow.

These were the fundamental tools I needed, so I started working with them.

I first designed an iteration of the user interface in Bootstrap Studio. I wanted only one page: the user would just open the URL, type in the addresses and search, then view the map. I started with this. However, as I proceeded to work with flask, I found that this was probably not the best way to go about this, so I ended up creating multiple pages.

For the ‘home’ page where most of the interactions would be, I know I needed a simple form for input and a place on the page where the map would be displayed, so I added that:

Note that I used a lot of templating for the frontend to modify it and into one suitable for a flask application. This involved creating multiple files and using template inheritance.

Step 2

The next step was to get a Maps API key for the application. This was straight forward. I simply when to the Google Cloud site and generated an API. I also made sure to restrict the API key to only the APIs I would actually need in my applicaton, which were the GeoCoding API, Directions API, Maps Embed API, and Maps JavaScript API. After this, I stored the links to their respective documentations in a Notion page I created for the project.

Step 3

Before I actually started coding, I wrote down the workflow of what I wanted my application to do. This would make it easier to know what functions to build and how to structure their logic. As I wrote down the workflow, I realized that I needed a way to iteract with the digital addressing system. I then set out to find the API. Interestingly, the developers of this system did not make available a public facing API to iteract with the system. A strong blow, but I kept looking, and to my amazement and relief, a really smart person had reverse-engineered the mobile application to create a public facing API. Link below. Finding this API gave me more reason to continue. I tried it out with a couple of values, and it worked really well.

I then initialized a Flask project with the required folders (static for static files and templates for html templates). I also decided to use Pipenv to manage whatever dependencies I might have for the project, which where flask, python-dotenv, requests, and googlemaps (the official Python client for Google Maps).

Without going into too much details, I created two main Python files: helpers.py and main,py to manage helper functions and control the flask application logic respectively. Inside helpers.py, I had a couple of functions (which I created and iterated on as I went along). I discuss them briefly below:

is_valid_input()

This function validates the form inputs on the server-side and returns True if the input matches the pattern and False if it doesn’t.

Since the digital addresses have a fixed pattern as shown below:

I wrote a simple regular expression to validate and accept only inputs of that pattern. An alternative form for an address is also “XXYYYZZZZ”, which the regex covered as well. The regex was: ^[A-Z]{2}-[0-9]{3}-[0-9]{4}$||^[A-Z]{2}[0-9]{7}$. To check that the regex pattern was correct, I used regex101.com.

NB: There was also client-side validation.

query_ghpost_api()

This function queries the Ghana Post Digital Address API (the one that was reverse-engineered) to get the coordinates (latitude and longitude) of the given addresses. It returned the fetched values as a dictionary of lists or None if no values were fetched.

get_location_details()

This function used the Google Maps API to reverse geocode the longitude and latitude to return a more formatted (human-readable) address. It also returned a place_id of the decoded coordinated, which is a unique identifier of the location on Maps. Its return value was either a tuple of the place id and formatted address, or None if no details were found.

main.py simply contained function routes for a landing page (which I eventually added) and the home page. For details on how I did that, please see the GitHub project GitHub link below.

Sample Results

Below is a sample result gotten when searching using AK4849321 and GA-183-8164 as the source and destination addresses respectively.

Limitations and Challenges Faced

Challenges

  • The major challenge I faced when building the project was getting access to a public facing API for the digital address system. This was solved when I found the API made available by Jay from Sperix Labs.

  • Due to the coordinate mapping not being well-developed and specific, some addresses I tried did not return any values which led to errors. I handled these edge cases by broadening the type of location data the Maps API could return and by adding more error handling.

  • Reloading only the map section of the home page and not the entire page. This is certainly possible using Flask, but I wasn’t able to do it due to time limitations, and because I’m not very good at JavaScript. The StackOverflow answers did help, but not too much. I ended up having to reload the whole page.

Limitations

  • Perhaps due to the not-so-advanced urban development in Ghana, the Google Mapping system here is not very accurate. Thus, some correct digital search addresses did not return any results especially when I tried to modify the data returned by the Maps API to be more specific. One way I made up for this was to use the "GEOMETRIC_CENTER" location type filter for the reverse geocoding, which according to the documentation returns only geometric centers of locations such as a polyline (for example, a street) or polygon (region). I also had to settle for approximate locations using the "APPROXIMATE" location type.

  • The map is not as interactive as that used in transportation apps like Uber and Bolt.

Possible Project Extensions and Features

Some possible extensions for this application include:

  • rebuilding the form with Flask-WTForms. This beneficial in a couple of ways such as writing more Python as opposed to HTML and allowing Flask to translate the Python to HTML for you, and improving security by setting the CSRF (Cross Site Request Forgery) tokens flask-WTForms makes available for you.

  • Refreshing only the map on the homepage with the directions, as opposed to the entire page.

  • Add feature to allow for the user’s location permission and decode the source address from the location coordinates.

  • UI improvements.

Thank you for sticking to the end, and I hope you enjoyed the article!


Update: Based on feedback from my friend Ian Akotey, I updated the regex in the code (formerly ^[A-Z]{2}-[0-9]{3}-[0-9]{4}$||^[A-Z]{2}[0-9]{7}$) to ^[a-zA-Z0-9]{2}(?:-?\d{3}-?\d{4})$ to include atomic non-capturing groups and allow for a broader range of inputs such as GC-1234567 or GC123-4567.