Skip to content

voidst1/sg-bus-api

Repository files navigation

sg-bus-api

A geospatial REST API endpoint that efficiently finds the nearest bus stops in Singapore for any given coordinate. It leverages S2 geometry for fast, hierarchical spatial indexing and RocksDB as a high-performance embedded key–value store for low-latency lookups.

Learnings

Refer to LEARNINGS.MD for lessons, challenges, and reflections from building this project.

API

GET /ping

Health check.

Response

{ "message": "pong" }

GET /bus-stops/nearest

Returns the 5 nearest bus stops to the given coordinates.

Query Parameters

Parameter Type Required Description
lat float64 Yes Latitude
lng float64 Yes Longitude

Example

GET /bus-stops/nearest?lat=1.2968&lng=103.8525

Response

[
  {
    "BusStopCode": "01012",
    "Description": "Hotel Grand Pacific",
    "Latitude": 1.29684825487647,
    "Longitude": 103.85253591654006,
    "RoadName": "Victoria St",
    "distance_m": 6.7
  },
  {
    "BusStopCode": "01019",
    "Description": "Bras Basah Cplx",
    "Latitude": 1.29698951191332,
    "Longitude": 103.85302201172507,
    "RoadName": "Victoria St",
    "distance_m": 61.7
  },
  {
    "BusStopCode": "04179",
    "Description": "Aft Bras Basah Stn Exit A",
    "Latitude": 1.29647916306741,
    "Longitude": 103.85147164487202,
    "RoadName": "Bras Basah Rd",
    "distance_m": 119.8
  },
  {
    "BusStopCode": "01013",
    "Description": "St. Joseph's Ch",
    "Latitude": 1.29770970610083,
    "Longitude": 103.8532247463225,
    "RoadName": "Victoria St",
    "distance_m": 129.3
  },
  {
    "BusStopCode": "01029",
    "Description": "Opp Natl Lib",
    "Latitude": 1.2966729849642,
    "Longitude": 103.85441422464267,
    "RoadName": "Nth Bridge Rd",
    "distance_m": 213.3
  }
]

Error responses

  • 400 Bad Request — missing or invalid lat/lng
  • 404 Not Found — no bus stops found near the given location

Setup

Prerequisites

  • Go 1.25+
  • RocksDB system libraries (installed automatically in the dev container):
    librocksdb-dev libsnappy-dev liblz4-dev libzstd-dev
    

Install dependencies

go mod tidy

Seed the database

Populate RocksDB with bus stop data from data/bus_stops.json:

go run seed.go

Optional flag:

--input  Path to JSON input file (default: ./data/bus_stops.json)

Run the server

go run .

Optional flags:

-db  Path to RocksDB directory (default: ./data/rocksdb)

The server listens on port 8080.

Build

go build .

Project Structure

.
├── main.go                    # HTTP server and route handlers
├── nearest.go                 # Nearest bus stop search logic
├── seed.go                    # One-time DB seeding utility
├── config.go                  # Default path constants
├── data/
│   ├── bus_stops.json         # Full Singapore bus stop dataset
│   ├── bus_stops_small.json   # Small sample for testing
│   └── rocksdb/               # RocksDB data directory (generated)
└── internal/
    ├── config/                # Shared path constants
    ├── db/                    # RocksDB wrapper and key definitions
    ├── geo/                   # S2 cell utilities and distance calculation
    └── models/                # BusStop data model

How It Works

Bus stops are indexed in RocksDB under two key types:

  • stop:{BusStopCode} — full bus stop record (JSON)
  • geo:{s2CellToken}:{BusStopCode} — spatial index entry

At query time, the API computes the S2 cell (level 14, ~600m edge) for the requested coordinates, scans that cell and its 4 edge neighbors, fetches matching stops, calculates geodesic distances, and returns the 5 closest results.

Testing

go test ./...

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors