Skip to content

Repository files navigation

Rwanda Location 🇷🇼

A simple, powerful TypeScript library for working with Rwanda's administrative divisions. Get information about provinces, districts, sectors, cells, and villages with ease!

npm versionLicenseSecurityDependencies

Why Use This Library?

Perfect for building:

  • 📝 Address forms with cascading dropdowns
  • 🗺️ Location-based applications
  • 📊 Geographic data analysis
  • 🏢 Administrative management systems
  • 📱 Mobile apps needing Rwanda location data

Features

  • Complete Data - All 5 provinces, 30 districts, 416 sectors, 2,148 cells, and 14,837 villages
  • Easy to Use - Simple, intuitive API
  • Zero Dependencies - Lightweight and fast
  • Type-Safe - Full TypeScript support
  • Well Tested - 98%+ test coverage (109 tests)
  • Secure - Zero vulnerabilities, security audited
  • Production Ready - Used in real-world applications

Installation

npm install @devrw/rwanda-location

or with yarn:

yarn add @devrw/rwanda-location

Quick Start

import{rwandaLocation}from'@devrw/rwanda-location';// Get all provincesconstprovinces=rwandaLocation.getProvinces();console.log(provinces);// [// { code: 1, name: 'KIGALI' },// { code: 2, name: 'SOUTH' },// { code: 3, name: 'WEST' },// { code: 4, name: 'NORTH' },// { code: 5, name: 'EAST' }// ]// Get districts in a provinceconstkigaliDistricts=rwandaLocation.getDistricts(1);console.log(kigaliDistricts);// [// { code: 101, name: 'Nyarugenge', provinceCode: 1, provinceName: 'KIGALI' },// { code: 102, name: 'Gasabo', provinceCode: 1, provinceName: 'KIGALI' },// { code: 103, name: 'Kicukiro', provinceCode: 1, provinceName: 'KIGALI' }// ]

Common Use Cases

1. Building a Cascading Address Form

This is the most common use case - building address forms where each dropdown depends on the previous selection:

import{RwandaLocation}from'@devrw/rwanda-location';constrw=newRwandaLocation();// Step 1: User selects a provinceconstprovinces=rw.getProvinces();// Show provinces in dropdown// Step 2: When province is selected, load its districtsconstselectedProvinceCode=1;// User selected KIGALIconstdistricts=rw.getDistricts(selectedProvinceCode);// Show districts in next dropdown// Step 3: When district is selected, load its sectorsconstselectedDistrictCode=101;// User selected Nyarugengeconstsectors=rw.getSectors(selectedDistrictCode);// Show sectors in next dropdown// Step 4: When sector is selected, load its cellsconstselectedSectorCode='010101';// User selected Gitegaconstcells=rw.getCells(selectedSectorCode);// Show cells in next dropdown// Step 5: When cell is selected, load its villagesconstselectedCellCode=1010101;// User selected Akabahiziconstvillages=rw.getVillages(selectedCellCode);// Show villages in final dropdown// Step 6: Get complete informationconstselectedVillageCode=101010102;constfullInfo=rw.getVillageByCode(selectedVillageCode);console.log(fullInfo);// {// code: 101010102,// name: 'Gihanga',// cellCode: 1010101,// cellName: 'Akabahizi',// sectorCode: '010101',// sectorName: 'Gitega',// districtCode: 101,// districtName: 'Nyarugenge',// provinceCode: 1,// provinceName: 'KIGALI'// }

2. Searching for Locations

Search across all administrative levels:

// Search for locations containing "Kigali"constresults=rw.search({query: 'Kigali',limit: 10});results.forEach((location)=>{console.log(`${location.village_name}, ${location.sector_name}, ${location.district_name}`);});

3. Finding Specific Locations

// Find a province by nameconstprovince=rw.getProvinceByName('KIGALI');// Find a district by codeconstdistrict=rw.getDistrictByCode(101);// Get all sectors in a districtconstsectors=rw.getSectors(101);// Get complete hierarchy for a villageconstvillage=rw.getVillageByCode(101010102);

4. Querying with Filters

// Find all locations in a specific areaconstlocations=rw.query({provinceCode: 1,districtCode: 101,sectorName: 'Gitega',});// Query by names (case-insensitive)constbyName=rw.query({provinceName: 'kigali'});

Complete API Reference

Province Methods

getProvinces()

Get all 5 provinces in Rwanda.

constprovinces=rw.getProvinces();// Returns: Province[]

getProvinceByCode(code: number)

Get a specific province by its code (1-5).

constkigali=rw.getProvinceByCode(1);// Returns: Province | null

getProvinceByName(name: string)

Get a province by name (case-insensitive).

constsouth=rw.getProvinceByName('south');// Returns: Province | null

District Methods

getDistricts(provinceCode?: number)

Get all districts, or filter by province.

// All districtsconstallDistricts=rw.getDistricts();// Districts in specific provinceconstkigaliDistricts=rw.getDistricts(1);// Returns: District[]

getDistrictByCode(code: number)

Get a specific district by its code.

constnyarugenge=rw.getDistrictByCode(101);// Returns: District | null

Sector Methods

getSectors(districtCode?: number, provinceCode?: number)

Get all sectors, or filter by district/province.

// All sectorsconstallSectors=rw.getSectors();// Sectors in a districtconstdistrictSectors=rw.getSectors(101);// Sectors in a provinceconstprovinceSectors=rw.getSectors(undefined,1);// Returns: Sector[]

getSectorByCode(code: string)

Get a specific sector by its code.

constsector=rw.getSectorByCode('010101');// Returns: Sector | null

Cell Methods

getCells(sectorCode?: string, districtCode?: number, provinceCode?: number)

Get all cells, or filter by sector/district/province.

// All cellsconstallCells=rw.getCells();// Cells in a sectorconstsectorCells=rw.getCells('010101');// Cells in a districtconstdistrictCells=rw.getCells(undefined,101);// Returns: Cell[]

getCellByCode(code: number)

Get a specific cell by its code.

constcell=rw.getCellByCode(1010101);// Returns: Cell | null

Village Methods

getVillages(cellCode?: number, sectorCode?: string, districtCode?: number, provinceCode?: number)

Get all villages, or filter by cell/sector/district/province.

// All villagesconstallVillages=rw.getVillages();// Villages in a cellconstcellVillages=rw.getVillages(1010101);// Villages in a sectorconstsectorVillages=rw.getVillages(undefined,'010101');// Returns: Village[]

getVillageByCode(code: number)

Get a specific village with its complete hierarchy.

constvillage=rw.getVillageByCode(101010102);// Returns: Village | null// Village includes: province, district, sector, cell, and village info

Search & Query Methods

search(options: SearchOptions)

Search for locations by name across all levels.

// Basic searchconstresults=rw.search({query: 'Kigali'});// Case-sensitive searchconstexactResults=rw.search({query: 'KIGALI',caseSensitive: true,});// Limited resultsconsttopResults=rw.search({query: 'gitega',limit: 10,});// Returns: LocationData[]

query(filter: QueryFilter)

Query locations with multiple filters.

constfiltered=rw.query({provinceCode: 1,districtCode: 101,sectorName: 'Gitega',});// Returns: LocationData[]

Utility Methods

getStatistics()

Get counts of all administrative divisions.

conststats=rw.getStatistics();// Returns:// {// totalProvinces: 5,// totalDistricts: 30,// totalSectors: 416,// totalCells: 2148,// totalVillages: 14837// }

getHierarchy(villageCode: number)

Get complete hierarchy for a village (alias for getVillageByCode).

consthierarchy=rw.getHierarchy(101010102);// Returns: Village | null

getFullPath(villageCode: number)

Get structured path for breadcrumb navigation.

constpath=rw.getFullPath(101010102);// Returns:// {// province: { code: 1, name: 'KIGALI' },// district: { code: 101, name: 'Nyarugenge', ... },// sector: { code: '010101', name: 'Gitega', ... },// cell: { code: 1010101, name: 'Akabahizi', ... },// village: { code: 101010102, name: 'Gihanga', ... }// }

TypeScript Types

interfaceProvince{code: number;// 1-5name: string;// 'KIGALI', 'SOUTH', 'WEST', 'NORTH', 'EAST'}interfaceDistrict{code: number;name: string;provinceCode: number;provinceName: string;}interfaceSector{code: string;name: string;districtCode: number;districtName: string;provinceCode: number;provinceName: string;}interfaceCell{code: number;name: string;sectorCode: string;sectorName: string;districtCode: number;districtName: string;provinceCode: number;provinceName: string;}interfaceVillage{code: number;name: string;cellCode: number;cellName: string;sectorCode: string;sectorName: string;districtCode: number;districtName: string;provinceCode: number;provinceName: string;}

Province Codes Reference

CodeProvince Name
1KIGALI
2SOUTH
3WEST
4NORTH
5EAST

Administrative Structure

Rwanda's administrative hierarchy:

Country (Rwanda)
└── Province (5)
└── District (30)
└── Sector (416)
└── Cell (2,148)
└── Village (14,837)

Real-World Examples

React Example - Address Form

importReact,{useState}from'react';import{rwandaLocation}from'@devrw/rwanda-location';functionAddressForm(){const[selectedProvince,setSelectedProvince]=useState('');const[selectedDistrict,setSelectedDistrict]=useState('');const[districts,setDistricts]=useState([]);constprovinces=rwandaLocation.getProvinces();consthandleProvinceChange=(provinceCode)=>{setSelectedProvince(provinceCode);setDistricts(rwandaLocation.getDistricts(parseInt(provinceCode)));setSelectedDistrict('');};return(<div><selectonChange={(e)=>handleProvinceChange(e.target.value)}><optionvalue="">SelectProvince</option>{provinces.map(p=>(<optionkey={p.code}value={p.code}>{p.name}</option>))}</select>{selectedProvince&&(<selectonChange={(e)=>setSelectedDistrict(e.target.value)}><optionvalue="">SelectDistrict</option>{districts.map(d=>(<optionkey={d.code}value={d.code}>{d.name}</option>))}</select>)}</div>);}

Node.js Example - API Endpoint

constexpress=require('express');const{ rwandaLocation }=require('@devrw/rwanda-location');constapp=express();app.get('/api/provinces',(req,res)=>{constprovinces=rwandaLocation.getProvinces();res.json(provinces);});app.get('/api/districts/:provinceCode',(req,res)=>{constdistricts=rwandaLocation.getDistricts(parseInt(req.params.provinceCode));res.json(districts);});app.listen(3000);

Validation Example

functionvalidateAddress(data: {provinceCode: number;districtCode: number;sectorCode: string}){// Check province existsconstprovince=rw.getProvinceByCode(data.provinceCode);if(!province){return{valid: false,error: 'Invalid province'};}// Check district exists and belongs to provinceconstdistrict=rw.getDistrictByCode(data.districtCode);if(!district||district.provinceCode!==data.provinceCode){return{valid: false,error: 'Invalid district for this province'};}// Check sector exists and belongs to districtconstsector=rw.getSectorByCode(data.sectorCode);if(!sector||sector.districtCode!==data.districtCode){return{valid: false,error: 'Invalid sector for this district'};}return{valid: true};}

Troubleshooting

Common Issues

Q: Getting null or empty results?

A: Make sure you're using valid codes. Province codes are 1-5, district codes start from 101, etc.

// ❌ Wrongconstdistricts=rw.getDistricts(999);// Returns []// ✅ Correctconstdistricts=rw.getDistricts(1);// Returns Kigali districts

Q: TypeScript errors?

A: Ensure you have TypeScript installed and configured:

npm install --save-dev typescript @types/node

Q: Import errors?

A: Use the correct import syntax:

// ES6import{rwandaLocation,RwandaLocation}from'@devrw/rwanda-location';// CommonJSconst{ rwandaLocation }=require('@devrw/rwanda-location');

Best Practices

  1. Reuse instances - Create one instance and reuse it:
// ✅ Goodimport{rwandaLocation}from'@devrw/rwanda-location';constprovinces=rwandaLocation.getProvinces();// ❌ Less efficientimport{RwandaLocation}from'@devrw/rwanda-location';constrw1=newRwandaLocation();constrw2=newRwandaLocation();
  1. Check for null - Always validate results:
constprovince=rw.getProvinceByCode(userInput);if(!province){console.error('Province not found');return;}// Use province safely
  1. Use TypeScript - Get full type safety:
import{RwandaLocation,Province}from'@devrw/rwanda-location';constrw=newRwandaLocation();constprovinces: Province[]=rw.getProvinces();

Performance

The library is optimized for speed:

OperationTimeRecords
Get all provinces< 1ms5
Get all districts< 5ms30
Get all sectors< 20ms416
Get all cells< 50ms2,148
Get all villages< 100ms14,837
Search (with limit)< 10msVariable
  • ⚡ Zero dependencies - Fast installation
  • 📦 Lightweight - ~7MB (mostly location data)
  • 🚀 Efficient - Uses Maps for O(1) lookups
  • 💾 Memory efficient - Data loaded once

Security

This package is secure and production-ready:

  • Zero vulnerabilities - Regularly audited with npm audit
  • Zero runtime dependencies - No third-party code
  • No code execution - Pure data access only
  • Type-safe - TypeScript strict mode
  • Well tested - 98%+ code coverage

Security Contact: info@jnkindilogs.xyz

Browser Support

Works in all modern browsers and Node.js:

  • ✅ Node.js >= 14.0.0
  • ✅ Chrome, Firefox, Safari, Edge (latest versions)
  • ✅ React, Vue, Angular applications
  • ✅ Next.js, Nuxt.js applications

Contributing

We welcome contributions! Here's how:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes
  4. Run tests (npm test)
  5. Commit (git commit -m 'Add amazing feature')
  6. Push (git push origin feature/amazing-feature)
  7. Open a Pull Request

Testing

# Run tests
npm test# Run tests in watch mode
npm run test:watch
# Build the project
npm run build
# Lint code
npm run lint

Changelog

1.1.2 (Latest)

  • 📄 License: Updated Read me to capture license change
  • 📦 Package: Updated package metadata

1.1.1

  • 📄 License: Changed from Apache-2.0 to MIT license for better compatibility
  • 📦 Package: Updated package metadata

1.1.0

  • 🔒 Security: Fixed all vulnerabilities (0 vulnerabilities)
  • ✅ Testing: Enhanced test coverage to 98%+
  • 📚 Documentation: Comprehensive documentation
  • 🔧 Improvements: Better TypeScript types
  • 🎯 Performance: Optimized query performance
  • 📦 Package: Improved package structure

1.0.0

  • 🎉 Initial release
  • ✨ Complete Rwanda location data
  • 📖 Basic documentation

Support

Need help? We're here for you:

License

MIT License - see the LICENSE file for details.

Authors

Acknowledgments

Thanks to everyone who contributed to this project and to the Rwanda government for the official administrative data.


Made with ❤️ for Rwanda 🇷🇼

Star us on GitHub if you find this useful!

About

A simple, powerful TypeScript library for working with Rwanda's administrative divisions. Get information about provinces, districts, sectors, cells, and villages with ease!

Resources

Stars

6 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages